Skip to content

Commit

Permalink
Added support for mode: switch to the PermissionEditor formwidget
Browse files Browse the repository at this point in the history
  • Loading branch information
LukeTowers committed Oct 15, 2019
1 parent d52c592 commit a69c761
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 141 deletions.
1 change: 1 addition & 0 deletions modules/backend/ServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ protected function registerAssetBundles()
$combiner->registerBundle('~/modules/backend/formwidgets/nestedform/assets/less/nestedform.less');
$combiner->registerBundle('~/modules/backend/formwidgets/richeditor/assets/js/build-plugins.js');
$combiner->registerBundle('~/modules/backend/formwidgets/colorpicker/assets/less/colorpicker.less');
$combiner->registerBundle('~/modules/backend/formwidgets/permissioneditor/assets/less/permissioneditor.less');

/*
* Rich Editor is protected by DRM
Expand Down
30 changes: 22 additions & 8 deletions modules/backend/formwidgets/PermissionEditor.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,33 @@
* User/group permission editor
* This widget is used by the system internally on the System / Administrators pages.
*
* Available Modes:
* - radio: Default mode, used by user-level permissions.
* Provides three-state control over each available permission. States are
* -1: Explicitly deny the permission
* 0: Inherit the permission's value from a parent source (User inherits from Role)
* 1: Explicitly grant the permission
* - checkbox: Used to define permissions for roles. Intended to define a base of what permissions are available
* Provides two state control over each available permission. States are
* 1: Explicitly allow the permission
* null: If the checkbox is not ticked, the permission will not be sent to the server and will not be stored.
* This is interpreted as the permission not being present and thus not allowed
* - switch: Used to define overriding permissions in a simpler UX than the radio.
* Provides two state control over each available permission. States are
* 1: Explicitly allow the permission
* -1: Explicitly deny the permission
*
* @package october\backend
* @author Alexey Bobkov, Samuel Georges
*/
class PermissionEditor extends FormWidgetBase
{
protected $user;

public $mode;
/**
* @var string Mode to display the permission editor with. Available options: radio, checkbox, switch
*/
public $mode = 'radio';

/**
* @inheritDoc
Expand Down Expand Up @@ -51,7 +70,7 @@ public function prepareVars()
$permissionsData = [];
}

$this->vars['checkboxMode'] = $this->getControlMode() === 'checkbox';
$this->vars['mode'] = $this->mode;
$this->vars['permissions'] = $this->getFilteredPermissions();
$this->vars['baseFieldName'] = $this->getFieldName();
$this->vars['permissionsData'] = $permissionsData;
Expand Down Expand Up @@ -79,11 +98,6 @@ protected function loadAssets()
$this->addJs('js/permissioneditor.js', 'core');
}

protected function getControlMode()
{
return strlen($this->mode) ? $this->mode : 'radio';
}

/**
* Returns a safely parsed set of permissions, ensuring the user cannot elevate
* their own permissions or permissions of another user above their own.
Expand Down Expand Up @@ -117,7 +131,7 @@ protected function getSaveValueSecure($value)
/**
* 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
* @return array The permissions that the logged-in user does have access to ['permission-tab' => $arrayOfAllowedPermissionObjects]
*/
protected function getFilteredPermissions()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,110 +1,40 @@
.permissioneditor {
position: relative;
margin: 0 -20px;
}
.permissioneditor.control-disabled .permissions-overlay {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.01);
cursor: not-allowed;
}
.permissioneditor.control-disabled table {
opacity: 0.5;
filter: alpha(opacity=50);
}
.permissioneditor table {
width: 100%;
}
.permissioneditor table th {
padding: 30px 4px 8px 4px;
color: #2a3e51;
font-weight: normal;
border-bottom: 1px solid #dbe1e3;
}
.permissioneditor table th.tab {
font-size: 13px;
}
.permissioneditor table th.permission-type {
text-transform: uppercase;
font-size: 11px;
text-align: center;
}
.permissioneditor table td {
padding: 10px 4px;
vertical-align: top;
border-bottom: 1px solid #ecf0f1;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.permissioneditor table td.permission-value {
text-align: center;
}
.permissioneditor table td.permission-name {
font-size: 13px;
cursor: pointer;
color: #777777;
}
.permissioneditor table td p.comment {
margin-top: 5px;
margin-bottom: 0;
}
.permissioneditor table td p.comment:empty {
display: none;
}
.permissioneditor table tr:hover td {
background: #4da7e8;
}
.permissioneditor table tr:hover td.permission-name {
color: #ffffff !important;
}
.permissioneditor {position:relative;margin:0 -20px}
.permissioneditor.control-disabled .permissions-overlay {position:absolute;left:0;top:0;width:100%;height:100%;background:rgba(255,255,255,0.01);cursor:not-allowed}
.permissioneditor.control-disabled table {opacity:0.5;filter:alpha(opacity=50)}
.permissioneditor table {width:100%}
.permissioneditor table th {padding:30px 4px 8px 4px;color:#2a3e51;font-weight:normal;border-bottom:1px solid #dbe1e3}
.permissioneditor table th.tab {font-size:13px}
.permissioneditor table th.permission-type {text-transform:uppercase;font-size:11px;text-align:center}
.permissioneditor table td {padding:10px 4px;vertical-align:top;border-bottom:1px solid #ecf0f1;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
.permissioneditor table td.permission-value {text-align:center}
.permissioneditor table td.permission-name {font-size:13px;cursor:pointer;color:#777}
.permissioneditor table td p.comment {margin-top:5px;margin-bottom:0}
.permissioneditor table td p.comment:empty {display:none}
.permissioneditor table tr:hover td {background:#4ea5e0}
.permissioneditor table tr:hover td.permission-name {color:#fff !important}
.permissioneditor table th:first-child,
.permissioneditor table td:first-child {
padding-left: 20px;
}
.permissioneditor table td:first-child {padding-left:20px}
.permissioneditor table th:last-child,
.permissioneditor table td:last-child {
padding-right: 5px;
}
.permissioneditor table td:last-child {padding-right:5px}
.permissioneditor table .custom-radio,
.permissioneditor table .custom-checkbox {
display: inline-block;
padding-left: 0;
}
.permissioneditor table .custom-checkbox,
.permissioneditor table .custom-switch {display:inline-block;padding-left:0}
.permissioneditor table .custom-radio,
.permissioneditor table .custom-checkbox,
.permissioneditor table .custom-switch,
.permissioneditor table .custom-radio label,
.permissioneditor table .custom-checkbox label {
margin-bottom: 0;
}
.permissioneditor table .custom-checkbox label,
.permissioneditor table .custom-switch label {margin-bottom:0}
.permissioneditor table .custom-radio label,
.permissioneditor table .custom-checkbox label {
padding: 0 0 0 14px;
margin: 0;
top: 0;
}
.permissioneditor table .custom-checkbox label,
.permissioneditor table .custom-switch label {padding:0 0 0 14px;margin:0;top:0}
.permissioneditor table .custom-radio label span,
.permissioneditor table .custom-checkbox label span {
text-indent: -10000em;
display: block;
}
.permissioneditor table .custom-checkbox label span,
.permissioneditor table .custom-switch label span {text-indent:-10000em;display:block}
.permissioneditor table .custom-radio label:before,
.permissioneditor table .custom-checkbox label:before {
margin-right: 0;
}
.permissioneditor table tr:last-child td {
border-bottom: none;
}
.permissioneditor table tr:first-child th {
padding-top: 0;
}
.permissioneditor table tr.disabled td.permission-name {
color: #AAA;
}
.permissioneditor table tr.last-section-row td {
border-bottom: none;
}
.permissioneditor table .custom-checkbox label:before,
.permissioneditor table .custom-switch label:before {margin-right:0}
.permissioneditor table tr:last-child td {border-bottom:none}
.permissioneditor table tr:first-child th {padding-top:0}
.permissioneditor table tr.disabled td.permission-name {color:#AAA}
.permissioneditor table tr.last-section-row td {border-bottom:none}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
padding: 30px 4px 8px 4px;
color: @color-label;
font-weight: normal;
border-bottom: 1px solid @color-permissioneditor-section-border;
border-bottom: 1px solid @color-permissioneditor-section-border;

&.tab {
font-size: @font-size-base - 1;
Expand All @@ -47,7 +47,7 @@
td {
padding: 10px 4px;
vertical-align: top;
border-bottom: 1px solid @color-permissioneditor-permission-border;
border-bottom: 1px solid @color-permissioneditor-permission-border;
.user-select(none);

&.permission-value{
Expand Down Expand Up @@ -91,7 +91,8 @@
}

.custom-radio,
.custom-checkbox {
.custom-checkbox,
.custom-switch {
display: inline-block;;
padding-left: 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@
<?php
$firstTab = true;
$globalIndex = 0;
$checkboxMode = !($this->mode === 'radio');
?>
<?php foreach ($permissions as $tab => $tabPermissions): ?>
<tr class="section">
<th class="tab"><?= e(trans($tab)) ?></th>

<th class="permission-type"><?= $firstTab ? e(trans('backend::lang.user.allow')) : '' ?></th>

<?php if (!$checkboxMode): ?>
<?php if ($this->mode === 'radio') : ?>
<th class="permission-type"><?= $firstTab ? e(trans('backend::lang.user.inherit')) : '' ?></th>
<th class="permission-type"><?= $firstTab ? e(trans('backend::lang.user.deny')) : '' ?></th>
<?php endif ?>
<?php endif; ?>

<th></th>
</tr>
Expand All @@ -24,13 +26,19 @@
<?php
$globalIndex++;

if (!$checkboxMode) {
$permissionValue = array_key_exists($permission->code, $permissionsData)
? $permissionsData[$permission->code]
: 0;
}
else {
$isChecked = array_key_exists($permission->code, $permissionsData);
switch ($this->mode) {
case 'radio':
$permissionValue = array_key_exists($permission->code, $permissionsData)
? $permissionsData[$permission->code]
: 0;
break;
case 'switch':
$isChecked = !((int) @$permissionsData[$permission->code] === -1);
break;
case 'checkbox':
default:
$isChecked = array_key_exists($permission->code, $permissionsData);
break;
}

$allowId = $this->getId('permission-' . $globalIndex . '-allow');
Expand All @@ -42,13 +50,14 @@
<?= $checkboxMode && !$isChecked ? 'disabled' : '' ?>
<?= !$checkboxMode && $permissionValue == -1 ? 'disabled' : '' ?>
">

<td class="permission-name">
<?= e(trans($permission->label)) ?>

<p class="comment"><?= e(trans($permission->comment)) ?></p>
</td>
<td class="permission-value">
<?php if (!$checkboxMode): ?>

<?php if ($this->mode === 'radio'): ?>
<td class="permission-value">
<div class="radio custom-radio">
<input
id="<?= $allowId ?>"
Expand All @@ -61,22 +70,7 @@

<label for="<?= $allowId ?>"><span>Allow</span></label>
</div>
<?php else: ?>
<div class="checkbox custom-checkbox">
<input
id="<?= $allowId ?>"
name="<?= e($baseFieldName) ?>[<?= e($permission->code) ?>]"
value="1"
type="checkbox"
<?= $isChecked ? 'checked="checked"' : '' ?>
>

<label for="<?= $allowId ?>"><span>Allow</span></label>
</div>
<?php endif?>
</td>

<?php if (!$checkboxMode): ?>
</td>
<td class="permission-value">
<div class="radio custom-radio">
<input
Expand Down Expand Up @@ -104,7 +98,41 @@
<label for="<?= $denyId ?>"><span>Deny</span></label>
</div>
</td>
<?php endif ?>
<?php elseif ($this->mode === 'switch'): ?>
<td class="permission-value">
<input
type="hidden"
name="<?= e($baseFieldName) ?>[<?= e($permission->code) ?>]"
value="-1"
>

<label class="custom-switch">
<input
id="<?= $allowId ?>"
name="<?= e($baseFieldName) ?>[<?= e($permission->code) ?>]"
value="1"
type="checkbox"
<?= $isChecked ? 'checked="checked"' : '' ?>
>
<span><span><?= e(trans('backend::lang.list.column_switch_true')) ?></span><span><?= e(trans('backend::lang.list.column_switch_false')) ?></span></span>
<a class="slide-button"></a>
</label>
</td>
<?php else: ?>
<td class="permission-value">
<div class="checkbox custom-checkbox">
<input
id="<?= $allowId ?>"
name="<?= e($baseFieldName) ?>[<?= e($permission->code) ?>]"
value="1"
type="checkbox"
<?= $isChecked ? 'checked="checked"' : '' ?>
>

<label for="<?= $allowId ?>"><span>Allow</span></label>
</div>
</td>
<?php endif; ?>

<td></td>
</tr>
Expand Down

0 comments on commit a69c761

Please sign in to comment.