1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-14 18:55:56 +02:00

Add support for group notifications in AdminThemeFramework (AdminThemeUikit), along with a config option in the AdminThemeUikit module. Also fix an issue in ProcessProfile that was interfering with ajax requests.

This commit is contained in:
Ryan Cramer
2017-11-20 09:45:16 -05:00
parent 32b3da7b0d
commit 337e59663b
11 changed files with 168 additions and 50 deletions

View File

@@ -579,10 +579,12 @@ abstract class AdminThemeFramework extends AdminTheme {
/**
* Test all notice types
*
* @return bool
*
*/
public function testNotices() {
if(!$this->wire('user')->isLoggedin()) return;
if(!$this->wire('user')->isLoggedin()) return false;
$this->message('Message test');
$this->message('Message test debug', Notice::debug);
$this->message('Message test markup <a href="#">example</a>', Notice::allowMarkup);
@@ -592,27 +594,19 @@ abstract class AdminThemeFramework extends AdminTheme {
$this->error('Error test');
$this->error('Error test debug', Notice::debug);
$this->error('Error test markup <a href="#">example</a>', Notice::allowMarkup);
return true;
}
/**
* Render runtime notices div#notices
*
* @param Notices $notices
* @param array $options See defaults in method
* @return string
* @param Notices|bool $notices Notices object or specify boolean true to return array of all available $options
* @param array $options See defaults in method
* @return string|array Returns string unless you specify true for $notices argument, then it returns an array.
*
*/
public function renderNotices($notices, array $options = array()) {
// if(!count($notices)) return '';
/*
if($this->isLoggedIn && $this->wire('modules')->isInstalled('SystemNotifications')) {
$systemNotifications = $this->wire('modules')->get('SystemNotifications');
if(!$systemNotifications->placement) return '';
}
*/
$defaults = array(
'messageClass' => 'NoticeMessage', // class for messages
'messageIcon' => 'check-square', // default icon to show with notices
@@ -622,20 +616,42 @@ abstract class AdminThemeFramework extends AdminTheme {
'errorIcon' => 'exclamation-triangle', // icon for errors
'debugClass' => 'NoticeDebug', // class for debug items (appended)
'debugIcon' => 'bug', // icon for debug notices
'closeClass' => 'notice-remove', // class for close notices link <a>
'closeClass' => 'pw-notice-remove notice-remove', // class for close notices link <a>
'closeIcon' => 'times', // icon for close notices link
'listMarkup' => "<ul class='pw-notices' id='notices'>{out}</ul><!--/notices-->",
'itemMarkup' => "<li class='{class}'>{remove}{icon}{text}</li>"
'itemMarkup' => "<li class='{class}'>{remove}{icon}{text}</li>",
// the following apply only when groupByType==true
'groupByType' => true, // Group notices by type
'groupParentClass' => 'pw-notice-group-parent', // class for parent notices
'groupChildClass' => 'pw-notice-group-child', // class for children (of parent notices)
'groupToggleMarkup' => "<a class='pw-notice-group-toggle' href='#'>{label}" .
"<i class='fa fa-fw fa-bell-o' data-toggle='fa-bell-o fa-bell'></i>" .
"<i class='fa fa-fw fa-angle-right' data-toggle='fa-angle-right fa-angle-down'></i></a>",
'groupToggleLabel' => $this->_("+{n-1}"),
);
$options = array_merge($defaults, $options);
if($notices === true) return $options;
$config = $this->wire('config');
$noticesArray = array();
$out = '';
$removeIcon = $this->renderIcon($options['closeIcon']);
$removeLabel = $this->_('Close all');
$removeLink = "<a class='$options[closeClass]' href='#' title='$removeLabel'>$removeIcon</a>";
if($this->isLoggedIn && $this->wire('modules')->isInstalled('SystemNotifications')) {
$defaults['groupByType'] = false;
//$systemNotifications = $this->wire('modules')->get('SystemNotifications');
//if(!$systemNotifications->placement) return '';
}
foreach($notices as $n => $notice) {
$text = $notice->text;
if($notice->flags & Notice::allowMarkup) {
$allowMarkup = $notice->flags & Notice::allowMarkup;
if($allowMarkup) {
// leave $text alone
} else {
// unencode + re-encode entities, just in case module already entity some or all of output
@@ -646,41 +662,70 @@ abstract class AdminThemeFramework extends AdminTheme {
if($notice instanceof NoticeError) {
$class = $options['errorClass'];
$icon = $options['errorIcon'];
$noticeType = 'errors';
} else if($notice instanceof NoticeWarning) {
$class = $options['warningClass'];
$icon = $options['warningIcon'];
$noticeType = 'warnings';
} else {
$class = $options['messageClass'];
$icon = $options['messageIcon'];
$noticeType = 'messages';
}
if($notice->flags & Notice::debug) {
$class .= " " . $options['debugClass'];
$icon = $options['debugIcon'];
// ensure non-debug version is set as well
if(!isset($noticesArray[$noticeType])) $noticesArray[$noticeType] = array();
$noticeType .= "-debug";
}
// indicate which class the notice originated from in debug mode
if($notice->class && $config->debug) $text = "{$notice->class}: $text";
// show remove link for first item only
if($n) {
$remove = '';
} else {
$removeIcon = $this->renderIcon($options['closeIcon']);
$removeLabel = $this->_('Close all');
$remove = "<a class='$options[closeClass]' href='#' title='$removeLabel'>$removeIcon</a>";
}
$replacements = array(
'{class}' => $class,
'{remove}' => $remove,
'{remove}' => '',
'{icon}' => $this->renderNavIcon($notice->icon ? $notice->icon : $icon),
'{text}' => $text,
);
$out .= str_replace(array_keys($replacements), array_values($replacements), $options['itemMarkup']);
if($options['groupByType']) {
if(!isset($noticesArray[$noticeType])) $noticesArray[$noticeType] = array();
$noticesArray[$noticeType][] = $replacements;
} else {
if($n === 0) $replacements['{remove}'] = $removeLink;
$out .= str_replace(array_keys($replacements), array_values($replacements), $options['itemMarkup']);
}
}
if($options['groupByType']) {
$cnt = 0;
foreach($noticesArray as $noticeType => $noticeReplacements) {
if(strpos($noticeType, '-debug')) continue;
if(isset($noticesArray["$noticeType-debug"])) {
$noticeReplacements = array_merge($noticeReplacements, $noticesArray["$noticeType-debug"]);
}
$n = count($noticeReplacements);
if($n > 1) {
$notice =& $noticeReplacements[0];
$label = str_replace(array('{n}', '{n-1}'), array($n, $n-1), $options['groupToggleLabel']);
$notice['{text}'] .= ' ' . str_replace(array('{label}'), array($label), $options['groupToggleMarkup']);
$notice['{class}'] .= ' ' . $options['groupParentClass'];
$childClass = $options['groupChildClass'];
} else {
$childClass = '';
}
foreach($noticeReplacements as $i => $replacements) {
if(!$cnt) $replacements['{remove}'] = $removeLink;
if($childClass && $i > 0) $replacements['{class}'] .= ' ' . $childClass;
$out .= str_replace(array_keys($replacements), array_values($replacements), $options['itemMarkup']);
$cnt++;
}
}
}
$out = str_replace('{out}', $out, $options['listMarkup']);

View File

@@ -15,7 +15,8 @@
* @property string $layout Layout type (blank=default, sidenav=multi-pane, sidenav-tree=left-tree, sidenav-tree-alt=right-tree)
* @property int $logoAction Logo click action (0=admin root page list, 1=offcanvas nav)
* @property string $userLabel Text containing user {vars} to use for user label in masthead (default="{Name}")
* @property int $maxWidth Maimum layout width in pixels, or 0 for no max (default=1600).
* @property int $maxWidth Maximum layout width in pixels, or 0 for no max (default=1600).
* @property bool|int $groupNotices Whether or not notices should be grouped by type
*
*/
class AdminThemeUikit extends AdminThemeFramework implements Module, ConfigurableModule {
@@ -23,7 +24,7 @@ class AdminThemeUikit extends AdminThemeFramework implements Module, Configurabl
public static function getModuleInfo() {
return array(
'title' => 'Uikit',
'version' => 20,
'version' => 21,
'summary' => 'Uikit v3 admin theme (beta)',
'autoload' => 'template=admin',
'requires' => 'ProcessWire>=3.0.61'
@@ -73,6 +74,7 @@ class AdminThemeUikit extends AdminThemeFramework implements Module, Configurabl
$this->set('userLabel', '{Name}');
$this->set('userAvatar', 'icon.user-circle');
$this->set('maxWidth', 1600);
$this->set('groupNotices', true);
$this->addHookAfter('InputfieldSelector::ajaxReady', $this, 'hookInputfieldSelectorAjax');
}
@@ -113,7 +115,9 @@ class AdminThemeUikit extends AdminThemeFramework implements Module, Configurabl
}
$session->removeFor('Page', 'appendEditUrl');
$modules->get('JqueryUI')->use('panel');
/** @var JqueryUI $jqueryUI */
$jqueryUI = $modules->get('JqueryUI');
$jqueryUI->use('panel');
// add rendering hooks
$this->addHookBefore('Inputfield::render', $this, 'hookBeforeRenderInputfield');
@@ -149,6 +153,22 @@ class AdminThemeUikit extends AdminThemeFramework implements Module, Configurabl
}
return $out;
}
/**
* Test all notice types
*
* @return bool
*
*/
public function testNotices() {
if(parent::testNotices()) {
$v = $this->wire('input')->get('test_notices');
if($v === 'group-off') $this->groupNotices = false;
if($v === 'group-on') $this->groupNotices = true;
return true;
}
return false;
}
/*******************************************************************************************
* HOOKS
@@ -541,14 +561,15 @@ class AdminThemeUikit extends AdminThemeFramework implements Module, Configurabl
/**
* Render runtime notices div#notices
*
* @param Notices|bool $notices
* @param array $options See defaults in method
* @param Notices $notices
* @return string
* @return string|array
*
*/
public function renderNotices($notices, array $options = array()) {
$defaults = array(
'groupByType' => $this->groupNotices ? true : false,
'messageClass' => 'NoticeMessage uk-alert uk-alert-primary', // class for messages
'messageIcon' => 'check-square', // default icon to show with notices
'warningClass' => 'NoticeWarning uk-alert uk-alert-warning', // class for warnings
@@ -557,7 +578,7 @@ class AdminThemeUikit extends AdminThemeFramework implements Module, Configurabl
'errorIcon' => 'exclamation-triangle', // icon for errors
'debugClass' => 'NoticeDebug uk-alert', // class for debug items (appended)
'debugIcon' => 'bug', // icon for debug notices
'closeClass' => 'notice-remove', // class for close notices link <a>
'closeClass' => 'pw-notice-remove notice-remove', // class for close notices link <a>
'closeIcon' => 'times', // icon for close notices link
'listMarkup' => "<ul class='pw-notices' id='notices'>{out}</ul><!--/notices-->",
'itemMarkup' =>

View File

@@ -11,10 +11,12 @@ if(!defined("PROCESSWIRE")) die();
*/
function AdminThemeUikitConfig(AdminTheme $adminTheme, InputfieldWrapper $inputfields) {
$defaultNote = __('When blank, the default file used.') . ' ';
$defaultDesc = __('Enter path relative to homepage URL.');
$defaultFileNote = __('When blank, the default file used.') . ' ';
$defaultFileDesc = __('Enter path relative to homepage URL.');
$recommendedLabel = __('(RECOMMENDED)');
$experimentalLabel = __('(EXPERIMENTAL)');
$defaultLabel = __('(default)');
$exampleLabel = __('example');
$modules = $adminTheme->wire('modules');
$session = $adminTheme->wire('session');
@@ -139,6 +141,18 @@ function AdminThemeUikitConfig(AdminTheme $adminTheme, InputfieldWrapper $inputf
$f->attr('value', $adminTheme->maxWidth);
$fieldset->add($f);
$testURL = $modules->wire('config')->urls->admin . 'profile/?test_notices';
$f = $modules->get('InputfieldRadios');
$f->attr('name', 'groupNotices');
$f->label = __('Notifications style');
$f->notes = __('Does not apply if the SystemNotifications module is installed.');
$f->addOption(1, __('Group by type with expand/collapse control') . " ([$exampleLabel]($testURL=group-on))");
$f->addOption(0, __('Always show all') . " ([$exampleLabel]($testURL=group-off))");
$f->attr('value', (int) $adminTheme->groupNotices);
$fieldset->appendMarkup .= "<script>$('#wrap_Inputfield_groupNotices .InputfieldContent').find('a').addClass('pw-modal');</script>";
$modules->get('JqueryUI')->use('modal');
$fieldset->add($f);
/** @var InputfieldFieldset $fieldset */
$fieldset = $modules->get('InputfieldFieldset');
$fieldset->label = __('Custom files');
@@ -151,9 +165,9 @@ function AdminThemeUikitConfig(AdminTheme $adminTheme, InputfieldWrapper $inputf
$f->attr('name', 'cssURL');
$f->attr('value', $adminTheme->get('cssURL'));
$f->label = __('Primary CSS file');
$f->description = $defaultDesc . ' ' .
$f->description = $defaultFileDesc . ' ' .
__('We do not recommend changing this unless you are an admin theme developer.');
$f->notes = $defaultNote . "\nsite/modules/AdminThemeUikit/uikit/dist/css/uikit.pw.css";
$f->notes = $defaultFileNote . "\nsite/modules/AdminThemeUikit/uikit/dist/css/uikit.pw.css";
$f->collapsed = Inputfield::collapsedBlank;
$f->icon = 'file-code-o';
$fieldset->add($f);
@@ -163,8 +177,8 @@ function AdminThemeUikitConfig(AdminTheme $adminTheme, InputfieldWrapper $inputf
$f->attr('name', 'logoURL');
$f->attr('value', $adminTheme->get('logoURL'));
$f->label = __('Logo image file');
$f->description = $defaultDesc;
$f->notes = $defaultNote .
$f->description = $defaultFileDesc;
$f->notes = $defaultFileNote .
__('File should be PNG, GIF, JPG or SVG, on transparent background, and at least 100px in both dimensions.');
$f->collapsed = Inputfield::collapsedBlank;
$f->icon = 'file-image-o';

View File

@@ -15454,9 +15454,11 @@ a.InputfieldButtonLink:hover {
padding-left: 0;
margin: 3px 0;
}
.pw-notices .pw-notice-remove,
.pw-notices .notice-remove {
float: right;
color: #354b60;
margin-left: 10px;
}
.pw-notices .uk-alert-primary .notice-remove {
color: #3eb998;
@@ -15467,6 +15469,17 @@ a.InputfieldButtonLink:hover {
.pw-notices .uk-alert-danger .notice-remove {
color: #bc283d;
}
.pw-notices .uk-alert-danger a {
color: rgba(255, 255, 255, 0.7);
}
.pw-notices .pw-notice-group-toggle {
font-size: 0.875rem;
text-transform: uppercase;
font-weight: bold;
}
.pw-notices .pw-notice-group-toggle:hover {
text-decoration: none;
}
.pw-layout-sidenav-tree .pw-notices,
.pw-layout-sidenav-tree-alt .pw-notices {
margin-top: 0;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -8,6 +8,7 @@
*
*
* @property array $profileFields Names of fields user is allowed to edit in their profile
* @method bool|string isDisallowedUserName($value)
*
*/
@@ -208,10 +209,6 @@ class ProcessProfile extends Process implements ConfigurableModule, WirePageEdit
$user = $this->user;
$languages = $this->wire('languages');
$id = (int) $this->input->post('id');
if($id !== $user->id) throw new WireException('Invalid POST data');
$form->processInput($this->input->post);
if(count($form->getErrors())) {
@@ -321,6 +318,8 @@ class ProcessProfile extends Process implements ConfigurableModule, WirePageEdit
if(!$language->isDefault()) $user->set("name$language->id", $userName);
}
}
return true;
}
/**

View File

@@ -15,7 +15,26 @@ var ProcessWireAdmin = {
this.setupButtonStates();
this.setupTooltips();
this.setupDropdowns();
this.setupNotices();
},
setupNotices: function() {
$(".pw-notice-group-toggle").click(function() {
var $parent = $(this).closest('.pw-notice-group-parent');
var $children = $parent.nextUntil('.pw-notice-group-parent');
if($parent.hasClass('pw-notice-group-open')) {
$parent.removeClass('pw-notice-group-open');
$children.slideUp('fast');
} else {
$parent.addClass('pw-notice-group-open');
$children.slideDown('fast');
}
$parent.find('i[data-toggle]').each(function() {
$(this).toggleClass($(this).attr('data-toggle'));
});
return false;
});
},
/**
* Enable jQuery UI tooltips

File diff suppressed because one or more lines are too long

View File

@@ -29,4 +29,5 @@
user-select: none;
/* prevent selection of this element */ }
/*# sourceMappingURL=AdminTheme.css.map */
.pw-notices .pw-notice-group-child {
display: none; }

View File

@@ -67,4 +67,9 @@
.pw-description {}
// Small muted text
.pw-detail {}
.pw-detail {}
.pw-notices .pw-notice-group-child {
display: none;
}