diff --git a/config/cms.php b/config/cms.php
index 0b12b46f2..e6f7c32b9 100644
--- a/config/cms.php
+++ b/config/cms.php
@@ -51,6 +51,24 @@ return [
'backendForceSecure' => null,
+ /*
+ |--------------------------------------------------------------------------
+ | Back-end login remember
+ |--------------------------------------------------------------------------
+ |
+ | Define live duration of backend sessions :
+ |
+ | true - session never expire (cookie expiration in 5 years)
+ |
+ | false - session have a limited time (see session.lifetime)
+ |
+ | null - The form login display a checkbox that allow user to choose
+ | wanted behavior
+ |
+ */
+
+ 'backendForceRemember' => true,
+
/*
|--------------------------------------------------------------------------
| Back-end timezone
diff --git a/modules/backend/assets/css/october.css b/modules/backend/assets/css/october.css
index a6034f8b3..e8dea756a 100644
--- a/modules/backend/assets/css/october.css
+++ b/modules/backend/assets/css/october.css
@@ -846,6 +846,7 @@ body.outer .layout > .layout-row > .layout-cell .outer-form-container h2{font-si
body.outer .layout > .layout-row > .layout-cell .outer-form-container .horizontal-form{font-size:0;display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:-ms-flex;display:flex}
body.outer .layout > .layout-row > .layout-cell .outer-form-container .horizontal-form input{vertical-align:top;margin-right:9px;display:inline-block;border:none;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}
body.outer .layout > .layout-row > .layout-cell .outer-form-container .horizontal-form button{background:#0181b9;text-align:center;font-size:13px;font-weight:600;height:40px;vertical-align:top;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
+body.outer .layout > .layout-row > .layout-cell .outer-form-container .remember label {color:rgba(255,255,255,0.44)}
body.outer .layout > .layout-row > .layout-cell .outer-form-container .forgot-password{margin-top:30px;font-size:13px;top:8px}
body.outer .layout > .layout-row > .layout-cell .outer-form-container .forgot-password a{color:rgba(255,255,255,0.44)}
body.outer .layout > .layout-row > .layout-cell .outer-form-container .forgot-password:before{color:rgba(255,255,255,0.44);font-size:14px;position:relative;margin-right:5px}
diff --git a/modules/backend/assets/less/layout/outerlayout.less b/modules/backend/assets/less/layout/outerlayout.less
index 9c549bdc0..2de805597 100644
--- a/modules/backend/assets/less/layout/outerlayout.less
+++ b/modules/backend/assets/less/layout/outerlayout.less
@@ -74,6 +74,12 @@ body.outer {
}
}
+ .remember {
+ label {
+ color: @color-outer-muted-text;
+ }
+ }
+
.forgot-password {
margin-top: 30px;
font-size: 13px;
diff --git a/modules/backend/behaviors/relationcontroller/partials/_toolbar.htm b/modules/backend/behaviors/relationcontroller/partials/_toolbar.htm
index 7e0c03224..3b23bd498 100644
--- a/modules/backend/behaviors/relationcontroller/partials/_toolbar.htm
+++ b/modules/backend/behaviors/relationcontroller/partials/_toolbar.htm
@@ -4,7 +4,7 @@
= $this->relationMakePartial('button_update', [
- 'relationManageId' => $relationViewModel->id
+ 'relationManageId' => $relationViewModel->getKey()
]) ?>
= $this->relationMakePartial('button_'.$button) ?>
diff --git a/modules/backend/classes/WidgetManager.php b/modules/backend/classes/WidgetManager.php
index 5027b2009..67c4fe102 100644
--- a/modules/backend/classes/WidgetManager.php
+++ b/modules/backend/classes/WidgetManager.php
@@ -2,6 +2,7 @@
use Str;
use System\Classes\PluginManager;
+use Event;
/**
* Widget manager
@@ -188,6 +189,23 @@ class WidgetManager
}
}
+ /**
+ * @event system.reportwidgets.extendItems
+ * Allows to append or remove a report widget.
+ *
+ * You will have access to the WidgetManager instance and be able to call the appropiated methods
+ * $manager->registerReportWidget();
+ * $manager->removeReportWidget();
+ *
+ * Example usage:
+ *
+ * Event::listen('system.reportwidgets.extendItems', function($manager) {
+ * $manager->removeReportWidget('Acme\ReportWidgets\YourWidget');
+ * });
+ *
+ */
+ Event::fire('system.reportwidgets.extendItems', [$this]);
+
return $this->reportWidgets;
}
@@ -215,4 +233,19 @@ class WidgetManager
{
$this->reportWidgetCallbacks[] = $definitions;
}
+
+ /**
+ * Remove a registered ReportWidget.
+ * @param string $className Widget class name.
+ * @return void
+ */
+ public function removeReportWidget($className)
+ {
+ if (!$this->reportWidgets) {
+ throw new SystemException('Unable to remove a widget before widgets are loaded.');
+ }
+
+ unset($this->reportWidgets[$className]);
+ }
+
}
diff --git a/modules/backend/controllers/Auth.php b/modules/backend/controllers/Auth.php
index c1545d6ae..6a6c72cb4 100644
--- a/modules/backend/controllers/Auth.php
+++ b/modules/backend/controllers/Auth.php
@@ -69,11 +69,15 @@ class Auth extends Controller
throw new ValidationException($validation);
}
+ if (is_null($remember = config('cms.backendForceRemember', true))) {
+ $remember = (bool) post('remember');
+ }
+
// Authenticate user
$user = BackendAuth::authenticate([
'login' => post('login'),
'password' => post('password')
- ], true);
+ ], $remember);
// Load version updates
UpdateManager::instance()->update();
diff --git a/modules/backend/controllers/auth/signin.htm b/modules/backend/controllers/auth/signin.htm
index b508a74fd..7e186d337 100644
--- a/modules/backend/controllers/auth/signin.htm
+++ b/modules/backend/controllers/auth/signin.htm
@@ -32,6 +32,21 @@
+
+
+
+
+
diff --git a/modules/backend/formwidgets/DatePicker.php b/modules/backend/formwidgets/DatePicker.php
index 4718bf946..b10789b22 100644
--- a/modules/backend/formwidgets/DatePicker.php
+++ b/modules/backend/formwidgets/DatePicker.php
@@ -46,6 +46,12 @@ class DatePicker extends FormWidgetBase
*/
public $yearRange = null;
+ /**
+ * @var int first day of the week
+ * eg: 0 (Sunday), 1 (Monday), 2 (Tuesday), etc.
+ */
+ public $firstDay = 0;
+
//
// Object properties
//
@@ -66,6 +72,7 @@ class DatePicker extends FormWidgetBase
'minDate',
'maxDate',
'yearRange',
+ 'firstDay',
]);
$this->mode = strtolower($this->mode);
@@ -112,6 +119,7 @@ class DatePicker extends FormWidgetBase
$this->vars['minDate'] = $this->minDate;
$this->vars['maxDate'] = $this->maxDate;
$this->vars['yearRange'] = $this->yearRange;
+ $this->vars['firstDay'] = $this->firstDay;
$this->vars['format'] = $this->format;
$this->vars['formatMoment'] = $this->getDateFormatMoment();
$this->vars['formatAlias'] = $this->getDateFormatAlias();
diff --git a/modules/backend/formwidgets/PermissionEditor.php b/modules/backend/formwidgets/PermissionEditor.php
index ebaa1692c..565ea3e68 100644
--- a/modules/backend/formwidgets/PermissionEditor.php
+++ b/modules/backend/formwidgets/PermissionEditor.php
@@ -44,7 +44,7 @@ class PermissionEditor extends FormWidgetBase
}
$this->vars['checkboxMode'] = $this->getControlMode() === 'checkbox';
- $this->vars['permissions'] = BackendAuth::listTabbedPermissions();
+ $this->vars['permissions'] = $this->getFilteredPermissions();
$this->vars['baseFieldName'] = $this->getFieldName();
$this->vars['permissionsData'] = $permissionsData;
$this->vars['field'] = $this->formField;
@@ -55,11 +55,29 @@ class PermissionEditor extends FormWidgetBase
*/
public function getSaveValue($value)
{
- if (is_array($value)) {
- return $value;
+ $newPermissions = is_array($value) ? array_map('intval', $value) : [];
+
+ if (!empty($newPermissions)) {
+ $existingPermissions = $this->model->permissions;
+
+ $allowedPermissions = array_map(function ($permissionObject) {
+ return $permissionObject->code;
+ }, array_flatten($this->getFilteredPermissions()));
+
+ foreach ($newPermissions as $permission => $code) {
+ if ($code === 0) {
+ continue;
+ }
+
+ if (in_array($permission, $allowedPermissions)) {
+ $existingPermissions[$permission] = $code;
+ }
+ }
+
+ $newPermissions = $existingPermissions;
}
- return [];
+ return $newPermissions;
}
/**
@@ -75,4 +93,30 @@ class PermissionEditor extends FormWidgetBase
{
return strlen($this->mode) ? $this->mode : 'radio';
}
+
+ /**
+ * Returns the available permissions; removing those that the logged-in user does not have access to
+ *
+ * @return array The permissions that the logged-in user does have access to
+ */
+ protected function getFilteredPermissions()
+ {
+ $permissions = BackendAuth::listTabbedPermissions();
+ $user = BackendAuth::getUser();
+ foreach ($permissions as $tab => $permissionsArray) {
+ foreach ($permissionsArray as $index => $permission) {
+ if (!$user->hasAccess($permission->code)) {
+ unset($permissionsArray[$index]);
+ }
+ }
+
+ if (empty($permissionsArray)) {
+ unset($permissions[$tab]);
+ } else {
+ $permissions[$tab] = $permissionsArray;
+ }
+ }
+
+ return $permissions;
+ }
}
diff --git a/modules/backend/formwidgets/RecordFinder.php b/modules/backend/formwidgets/RecordFinder.php
index 49d1a58bc..32361efd6 100644
--- a/modules/backend/formwidgets/RecordFinder.php
+++ b/modules/backend/formwidgets/RecordFinder.php
@@ -179,6 +179,10 @@ class RecordFinder extends FormWidgetBase
public function prepareVars()
{
$this->relationModel = $this->getLoadValue();
+
+ if ($this->formField->disabled) {
+ $this->previewMode = true;
+ }
$this->vars['value'] = $this->getKeyValue();
$this->vars['field'] = $this->formField;
diff --git a/modules/backend/formwidgets/Relation.php b/modules/backend/formwidgets/Relation.php
index c5f4699e5..0812379a6 100644
--- a/modules/backend/formwidgets/Relation.php
+++ b/modules/backend/formwidgets/Relation.php
@@ -28,11 +28,6 @@ class Relation extends FormWidgetBase
*/
public $nameFrom = 'name';
- /**
- * @var string Model column to use for the description reference
- */
- public $descriptionFrom = 'description';
-
/**
* @var string Custom SQL column selection to use for the name reference
*/
@@ -69,7 +64,6 @@ class Relation extends FormWidgetBase
{
$this->fillFromConfig([
'nameFrom',
- 'descriptionFrom',
'emptyOption',
'scope',
]);
diff --git a/modules/backend/formwidgets/Repeater.php b/modules/backend/formwidgets/Repeater.php
index dd9bf7b82..efec0c143 100644
--- a/modules/backend/formwidgets/Repeater.php
+++ b/modules/backend/formwidgets/Repeater.php
@@ -91,6 +91,10 @@ class Repeater extends FormWidgetBase
'maxItems',
]);
+ if ($this->formField->disabled) {
+ $this->previewMode = true;
+ }
+
$fieldName = $this->formField->getName(false);
$this->indexInputName = self::INDEX_PREFIX.$fieldName;
$this->groupInputName = self::GROUP_PREFIX.$fieldName;
@@ -116,6 +120,12 @@ class Repeater extends FormWidgetBase
*/
public function prepareVars()
{
+ if ($this->previewMode) {
+ foreach ($this->formWidgets as $widget) {
+ $widget->previewMode = true;
+ }
+ }
+
$this->vars['indexInputName'] = $this->indexInputName;
$this->vars['groupInputName'] = $this->groupInputName;
diff --git a/modules/backend/formwidgets/RichEditor.php b/modules/backend/formwidgets/RichEditor.php
index c8af07eab..75a291ba5 100644
--- a/modules/backend/formwidgets/RichEditor.php
+++ b/modules/backend/formwidgets/RichEditor.php
@@ -85,6 +85,7 @@ class RichEditor extends FormWidgetBase
$this->vars['value'] = $this->getLoadValue();
$this->vars['toolbarButtons'] = $this->evalToolbarButtons();
+ $this->vars['globalToolbarButtons'] = EditorSetting::getConfigured('html_toolbar_buttons');
$this->vars['allowEmptyTags'] = EditorSetting::getConfigured('html_allow_empty_tags');
$this->vars['allowTags'] = EditorSetting::getConfigured('html_allow_tags');
$this->vars['noWrapTags'] = EditorSetting::getConfigured('html_no_wrap_tags');
diff --git a/modules/backend/formwidgets/TagList.php b/modules/backend/formwidgets/TagList.php
index 8064bd2ba..b0f594f99 100644
--- a/modules/backend/formwidgets/TagList.php
+++ b/modules/backend/formwidgets/TagList.php
@@ -122,7 +122,7 @@ class TagList extends FormWidgetBase
foreach ($newTags as $newTag) {
$newModel = $relationModel::create([$this->nameFrom => $newTag]);
- $existingTags[$newModel->id] = $newTag;
+ $existingTags[$newModel->getKey()] = $newTag;
}
return array_keys($existingTags);
diff --git a/modules/backend/formwidgets/datepicker/partials/_datepicker.htm b/modules/backend/formwidgets/datepicker/partials/_datepicker.htm
index 53221db78..090c9a0b5 100644
--- a/modules/backend/formwidgets/datepicker/partials/_datepicker.htm
+++ b/modules/backend/formwidgets/datepicker/partials/_datepicker.htm
@@ -14,6 +14,7 @@
data-min-date="= $minDate ?>"
data-max-date="= $maxDate ?>"
data-year-range="= $yearRange ?>"
+ data-first-day="= $firstDay ?>"
>
diff --git a/modules/backend/formwidgets/repeater/assets/js/repeater.js b/modules/backend/formwidgets/repeater/assets/js/repeater.js
index d1fda348e..649abd0d6 100644
--- a/modules/backend/formwidgets/repeater/assets/js/repeater.js
+++ b/modules/backend/formwidgets/repeater/assets/js/repeater.js
@@ -1,6 +1,6 @@
/*
* Field Repeater plugin
- *
+ *
* Data attributes:
* - data-control="fieldrepeater" - enables the plugin on an element
* - data-option="value" - an option with a value
@@ -193,6 +193,11 @@
var $textInput = $('input[type=text]:first', $target)
if ($textInput.length) {
return $textInput.val()
+ } else {
+ var $disabledTextInput = $('.text-field:first > .form-control', $target)
+ if ($disabledTextInput.length) {
+ return $disabledTextInput.text()
+ }
}
return defaultText
diff --git a/modules/backend/formwidgets/repeater/partials/_repeater.htm b/modules/backend/formwidgets/repeater/partials/_repeater.htm
index 79cea1e78..aec9388e6 100644
--- a/modules/backend/formwidgets/repeater/partials/_repeater.htm
+++ b/modules/backend/formwidgets/repeater/partials/_repeater.htm
@@ -13,24 +13,26 @@
-
+ previewMode): ?>
+
+