1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-12 09:44:38 +02:00

Version 3.0.78 has updates primarily specific to enabling more customization from admin themes. In this case, AdminThemeUikit, but applies to any admin theme.

This commit is contained in:
Ryan Cramer
2017-10-06 09:33:39 -04:00
parent 5a39c9efc9
commit df17b337fd
13 changed files with 177 additions and 51 deletions

View File

@@ -99,6 +99,8 @@ abstract class AdminTheme extends WireData implements Module {
*
* All admin themes must call this init() method to register themselves.
*
* Note: this should be called after API ready.
*
*/
public function init() {
self::$numAdminThemes++;
@@ -116,6 +118,11 @@ abstract class AdminTheme extends WireData implements Module {
// if admin theme has already been set, then no need to continue
if($this->wire('adminTheme')) return;
/** @var Config $config */
$config = $this->wire('config');
/** @var Session $session */
$session = $this->wire('session');
/** @var string $adminTheme */
$adminTheme = $this->wire('user')->admin_theme;
if($adminTheme) {
@@ -129,16 +136,17 @@ abstract class AdminTheme extends WireData implements Module {
}
// adjust $config adminThumbOptions[scale] for auto detect when requested
$o = $this->wire('config')->adminThumbOptions;
$o = $config->adminThumbOptions;
if($o && isset($o['scale']) && $o['scale'] === 1) {
$o['scale'] = $this->wire('session')->hidpi ? 0.5 : 1.0;
$this->wire('config')->adminThumbOptions = $o;
$o['scale'] = $session->hidpi ? 0.5 : 1.0;
$config->adminThumbOptions = $o;
}
$this->config->js('modals', $this->config->modals);
$config->js('modals', $config->modals);
if($session->hidpi) $this->addBodyClass('hidpi-device');
if($session->touch) $this->addBodyClass('touch-device');
if($this->wire('session')->hidpi) $this->addBodyClass('hidpi-device');
if($this->wire('session')->touch) $this->addBodyClass('touch-device');
$this->addBodyClass($this->className());
}

View File

@@ -85,6 +85,8 @@ abstract class AdminThemeFramework extends AdminTheme {
/**
* Initialize and attach hooks
*
* Note: descending classes should call this after API ready
*
*/
public function init() {
@@ -98,14 +100,33 @@ abstract class AdminThemeFramework extends AdminTheme {
$this->isLoggedIn = $user->isLoggedin();
$this->isSuperuser = $this->isLoggedIn && $user->isSuperuser();
$this->isEditor = $this->isLoggedIn && ($this->isSuperuser || $user->hasPermission('page-edit'));
$this->includeInitFile();
$modal = $this->wire('input')->get('modal');
if($modal) $this->isModal = $modal == 'inline' ? 'inline' : true;
// test notices when requested
if($this->wire('input')->get('test_notices')) $this->testNotices();
if($this->wire('input')->get('test_notices') && $this->isLoggedIn) $this->testNotices();
}
/**
* Include the admin theme init file
*
*/
public function includeInitFile() {
$config = $this->wire('config');
$initFile = $config->paths->adminTemplates . 'init.php';
if(file_exists($initFile)) {
if(strpos($initFile, $config->paths->site) === 0) {
// admin themes in /site/modules/ may be compiled
$initFile = $this->wire('files')->compile($initFile);
}
/** @noinspection PhpIncludeInspection */
include_once($initFile);
}
}
/**
* Perform a translation, based on text from shared admin file: /wire/templates-admin/default.php
*
@@ -584,10 +605,12 @@ abstract class AdminThemeFramework extends AdminTheme {
// 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

View File

@@ -742,8 +742,6 @@ class Modules extends WireArray {
/**
* Retrieve the installed module info as stored in the database
*
* @return array Indexed by module class name => array of module info
*
*/
protected function loadModulesTable() {
$database = $this->wire('database');
@@ -2648,8 +2646,11 @@ class Modules extends WireArray {
// if $info[requires] or $info[installs] isn't already an array, make it one
if(!is_array($info['requires'])) {
$info['requires'] = str_replace(' ', '', $info['requires']); // remove whitespace
if(strpos($info['requires'], ',') !== false) $info['requires'] = explode(',', $info['requires']);
else $info['requires'] = array($info['requires']);
if(strpos($info['requires'], ',') !== false) {
$info['requires'] = explode(',', $info['requires']);
} else {
$info['requires'] = array($info['requires']);
}
}
// populate requiresVersions
@@ -2669,8 +2670,11 @@ class Modules extends WireArray {
// what does it install?
if(!is_array($info['installs'])) {
$info['installs'] = str_replace(' ', '', $info['installs']); // remove whitespace
if(strpos($info['installs'], ',') !== false) $info['installs'] = explode(',', $info['installs']);
else $info['installs'] = array($info['installs']);
if(strpos($info['installs'], ',') !== false) {
$info['installs'] = explode(',', $info['installs']);
} else {
$info['installs'] = array($info['installs']);
}
}
// misc

View File

@@ -45,7 +45,7 @@ class ProcessWire extends Wire {
* Reversion revision number
*
*/
const versionRevision = 77;
const versionRevision = 78;
/**
* Version suffix string (when applicable)

View File

@@ -107,7 +107,7 @@ if($page->process && $page->process != 'ProcessPageView') {
$initFile = $wire->files->compile($initFile);
}
/** @noinspection PhpIncludeInspection */
include($initFile);
include_once($initFile);
}
if($input->get('modal')) $session->addHookBefore('redirect', null, '_hookSessionRedirectModal');
$content = $controller->execute();

View File

@@ -49,6 +49,9 @@
* @property string $subfieldIdentifier ...
* @property string $groupIdentifier (1)
* @property int $maxUsers [20] Maximum number of users selectable. If more than regular text input used rather than select.
* @property string $selectClass
* @property string $inputClass
* @property string $checkboxClass
*
*
*/
@@ -131,6 +134,13 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {
*/
protected $initTemplate = null;
/**
* Has the ready method been called?
* @var bool
*
*/
protected $isReady = false;
/**
* Variable names that should be picked up through the session each time
*
@@ -248,6 +258,21 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {
*/
public function ready() {
if($this->isReady) return;
$this->isReady = true;
// settings specified in $config->InputfieldSelector
$configDefaults = array(
'selectClass' => '',
'inputClass' => '',
'checkboxClass' => '',
);
$configSettings = $this->wire('config')->InputfieldSelector;
$configSettings = is_array($configSettings) ? array_merge($configDefaults, $configSettings) : $configDefaults;
foreach($configSettings as $key => $value) {
$this->setting($key, $value);
}
$input = $this->wire('input');
$name = $input->get('name');
$action = $input->get($this->className());
@@ -902,7 +927,8 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {
$outSections['adjust'] = "<option data-labels='$dataLabels' data-names='$dataNames' value='toggle-names-labels'>$dataDefault</option>";
$inputName = $this->attr('name') . "__" . $settings['name'] . "[]";
$out = "<select class='select-$settings[name]' name='$inputName' data-type='$settings[type]' data-selected='$selectedValue'><option></option>";
$selectClass = trim("$this->selectClass select-$settings[name]");
$out = "<select class='$selectClass' name='$inputName' data-type='$settings[type]' data-selected='$selectedValue'><option></option>";
if(!$this->showOptgroups) {
ksort($outAll);
@@ -1051,7 +1077,8 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {
}
$disabled = count($operators) ? "" : " disabled='disabled'";
$out = "<select$disabled class='select-operator' name='$inputName'>";
$selectClass = trim("$this->selectClass select-operator");
$out = "<select$disabled class='$selectClass' name='$inputName'>";
foreach($operators as $key => $label) {
if(isset($this->operators[$label])) {
@@ -1270,7 +1297,8 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {
if(in_array($type, array('select', 'page', 'checkbox'))) {
// render a <select> box for the value
$out .= "<select class='select-value input-value' name='$inputName'>";
$selectClass = trim("$this->selectClass select-value input-value");
$out .= "<select class='$selectClass' name='$inputName'>";
$out .= "<option value=''></option>";
if($type != 'checkbox' && !isset($this->systemFields[$fieldName]) && !isset($this->modifierFields[$fieldName])) {
@@ -1313,7 +1341,8 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {
}
}
$out .= "<input value='$selectedValueEntities' class='input-value' name='$inputName' type='hidden' />";
$out .= "<input value='$selectedValueTitle' class='input-value-autocomplete' name='autocomplete_$inputName' placeholder='$placeholder' type='text' />";
$inputClass = trim("$this->inputClass input-value-autocomplete");
$out .= "<input value='$selectedValueTitle' class='$inputClass' name='autocomplete_$inputName' placeholder='$placeholder' type='text' />";
} else if($type == 'datetime' || $type == 'date') {
// render date/datetime input
@@ -1324,7 +1353,7 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {
} else {
// render other input that uses an <input type='text'> whether text, number or selector
$inputType = $type;
$inputClass = "input-value input-value-$type";
$inputClass = trim("$this->inputClass input-value input-value-$type");
if($type == 'number' || $type == 'selector' || $fieldName == 'id' || $subfield == 'id') {
// adding this class tells InputfieldSelector.js that selector strings are allowed for this input
@@ -1338,7 +1367,8 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {
// end the opval row by rendering a checkbox for the OR option
$orLabel = $this->_('Check box to make this row OR rather than AND');
$orChecked = $orChecked ? ' checked' : '';
$out .= "<input$orChecked class='input-or' type='checkbox' name='or_$inputName' value='1' title='$orLabel' />";
$checkboxClass = trim("$this->checkboxClass input-or");
$out .= "<input$orChecked class='$checkboxClass' type='checkbox' name='or_$inputName' value='1' title='$orLabel' />";
return $out;
}
@@ -1409,7 +1439,8 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {
$inputName = $this->attr('name') . "__" . $field->name . "[]";
$outSub = ''; // subselector optgroup output
$out = "<select class='select-subfield' name='$inputName' data-type='$selectorInfo[input]'>";
$selectClass = trim("$this->selectClass select-subfield");
$out = "<select class='$selectClass' name='$inputName' data-type='$selectorInfo[input]'>";
$out .= "<option></option>";
// determine if there is a current value string and if it contains a selector string
@@ -1705,6 +1736,7 @@ class InputfieldSelector extends Inputfield implements ConfigurableModule {
*
*/
public function ___render() {
$this->ready();
// tell jQuery UI we want it to load the modal component which makes a.modal open modal windows
$this->wire('modules')->get('JqueryUI')->use('modal');

View File

@@ -123,6 +123,9 @@ $(document).ready(function() {
// milliseconds in fade time to reveal or hide hover actions
hoverActionFade: 150,
// show only edit and view actions, and make everything else extra actions
useNarrowActions: $('body').hasClass('pw-narrow-width'),
// markup for the spinner used when ajax calls are made
spinnerMarkup: "<span class='PageListLoading'><i class='ui-priority-secondary fa fa-fw fa-spin fa-spinner'></i></span>",
@@ -622,7 +625,8 @@ $(document).ready(function() {
function addClickEvents($ul) {
$("a.PageListPage", $ul).click(clickChild);
$(".PageListActionMove a", $ul).click(clickMove);
$ul.on('click', '.PageListActionMove a', clickMove);
// $(".PageListActionMove a", $ul).click(clickMove);
$(".PageListActionSelect a", $ul).click(clickSelect);
$(".PageListTriggerOpen:not(.PageListID1) > a.PageListPage", $ul).click();
$(".PageListActionExtras > a:not(.clickExtras)", $ul).addClass('clickExtras').on('click', clickExtras);
@@ -645,7 +649,7 @@ $(document).ready(function() {
.html(child.label)
.addClass('PageListPage label');
$li.addClass('PageListID' + child.id);
$li.addClass(child.numChildren > 0 ? 'PageListHasChildren' : 'PageListNoChildren').addClass('PageListID' + child.id);
if(child.status == 0) $li.addClass('PageListStatusOff disabled');
if(child.status & 2048) $li.addClass('PageListStatusUnpublished secondary');
if(child.status & 1024) $li.addClass('PageListStatusHidden secondary');
@@ -676,13 +680,26 @@ $(document).ready(function() {
}
var $lastAction = null;
var $extrasLink = null; // link that toggles extra actions
var extras = {}; // extra actions
$(links).each(function(n, action) {
var actionName;
if(action.name == options.selectSelectLabel) actionName = 'Select';
else if(action.name == options.selectUnselectLabel) actionName = 'Select';
else actionName = action.cn; // cn = className
if(action.name == options.selectSelectLabel) {
actionName = 'Select';
} else if(action.name == options.selectUnselectLabel) {
actionName = 'Select';
} else {
actionName = action.cn; // cn = className
if(options.useNarrowActions && (actionName != 'Edit' && actionName != 'View' && actionName != 'Extras')) {
// move non-edit/view actions to extras when in narrow mode
extras[actionName] = action;
return;
}
}
var $a = $("<a></a>").html(action.name).attr('href', action.url);
if(!isModal) {
if(action.cn == 'Edit') {
$a.addClass('pw-modal pw-modal-large pw-modal-longclick');
@@ -691,13 +708,20 @@ $(document).ready(function() {
$a.addClass('pw-modal pw-modal-large pw-modal-longclick');
}
}
if(typeof action.extras != "undefined") {
$a.data('extras', action.extras);
for(var key in action.extras) {
extras[key] = action.extras[key];
}
$extrasLink = $a;
}
var $action = $("<li></li>").addClass('PageListAction' + actionName).append($a);
if(actionName == 'Extras') $lastAction = $action;
else $actions.append($action);
});
if($extrasLink) $extrasLink.data('extras', extras);
if($lastAction) {
$actions.append($lastAction);
$lastAction.addClass('ui-priority-secondary');

File diff suppressed because one or more lines are too long

View File

@@ -18,10 +18,15 @@ class ProcessPageListActions extends Wire {
'unlock' => 'Unlock',
'trash' => 'Trash',
'restore' => 'Restore',
'extras' => "<i class='fa fa-angle-right'></i>",
);
public function __construct() {
$this->superuser = $this->wire('user')->isSuperuser();
$settings = $this->wire('config')->ProcessPageList;
if(is_array($settings) && isset($settings['extrasLabel'])) {
$this->actionLabels['extras'] = $settings['extrasLabel'];
}
}
public function setActionLabels(array $actionLabels) {
@@ -81,7 +86,7 @@ class ProcessPageListActions extends Wire {
if(count($extras)) {
$actions['extras'] = array(
'cn' => 'Extras',
'name' => "<i class='fa fa-angle-right'></i>",
'name' => $this->actionLabels['extras'],
'url' => '#',
'extras' => $extras,
);

View File

@@ -5,6 +5,12 @@
background-color: #fff;
}
.NotificationList {
margin: 0;
padding: 0;
list-style: none;
}
.NotificationList li {
opacity: 0.95;
}
@@ -18,10 +24,11 @@
display: block;
border-right: none !important;
border-left: none !important;
border-bottom: 1px dotted rgba(255,255,255,0.5);
border-bottom: 1px solid rgba(255,255,255,0.5);
border-top: none;
padding-top: 0.25em;
padding-bottom: 0.25em;
margin: 0;
}
.NotificationTitle {

View File

@@ -17,6 +17,13 @@ var Notifications = {
iconMessage: 'smile-o',
iconWarning: 'meh-o',
iconError: 'frown-o',
iconRemove: 'times-circle',
classCommon: 'NoticeItem',
classMessage: 'NoticeMessage',
classWarning: 'NoticeWarning',
classError: 'NoticeError',
classDebug: 'NoticeDebug',
classContainer: 'container',
ghostDelay: 2000,
ghostDelayError: 4000,
ghostFadeSpeed: 'fast',
@@ -273,11 +280,11 @@ var Notifications = {
}
if(qtyError > 0) {
$bug.addClass('NoticeError', 'slow').removeClass('NoticeWarning', 'slow');
$bug.addClass(Notifications.options.classError, 'slow').removeClass(Notifications.options.classWarning, 'slow');
} else if(qtyWarning > 0) {
$bug.addClass('NoticeWarning', 'slow').removeClass('NoticeError', 'slow');
$bug.addClass(Notifications.options.classWarning, 'slow').removeClass(Notifications.options.classError, 'slow');
} else {
$bug.removeClass('NoticeWarning NoticeError', 'slow');
$bug.removeClass(Notifications.options.classWarning + ' ' + Notifications.options.classError, 'slow');
}
},
@@ -389,7 +396,7 @@ var Notifications = {
$li = $("<li></li>");
}
$li.attr('id', notification.id);
$li.attr('id', notification.id).addClass(Notifications.options.classCommon);
if(notification.expires > 0) {
$li.attr('data-expires', notification.expires);
}
@@ -397,9 +404,9 @@ var Notifications = {
var $icon = $("<i></i>").addClass('fa fa-fw fa-' + notification.icon);
var $title = $("<span></span>").addClass('NotificationTitle').html(notification.title);
var $p = $("<p></p>").append($title).prepend('&nbsp;').prepend($icon);
var $div = $("<div></div>").addClass('container').append($p);
var $div = $("<div></div>").addClass(Notifications.options.classContainer).append($p);
var $text = $("<div></div>").addClass('NotificationText');
var $rm = $("<i class='NotificationRemove fa fa-times-circle'></i>");
var $rm = $("<i class='NotificationRemove fa fa-" + Notifications.options.iconRemove + "'></i>");
var addClass = '';
if(progressNext > 0) {
@@ -422,10 +429,10 @@ var Notifications = {
$title.append(" <small data-created='" + notification.created + "' class='created'>" + notification.when + "</small>");
}
if(notification.flagNames.indexOf('debug') != -1) $li.addClass('NoticeDebug');
if(notification.flagNames.indexOf('error') != -1) $li.addClass('NoticeError');
else if(notification.flagNames.indexOf('warning') != -1) $li.addClass('NoticeWarning');
else if(notification.flagNames.indexOf('message') != -1) $li.addClass('NoticeMessage');
if(notification.flagNames.indexOf('debug') != -1) $li.addClass(Notifications.options.classDebug);
if(notification.flagNames.indexOf('error') != -1) $li.addClass(Notifications.options.classError);
else if(notification.flagNames.indexOf('warning') != -1) $li.addClass(Notifications.options.classWarning);
else if(notification.flagNames.indexOf('message') != -1) $li.addClass(Notifications.options.classMessage);
if(notification.html.length > 0) {
@@ -586,15 +593,15 @@ var Notifications = {
var delay = Notifications.options.ghostDelay;
if(notification.flagNames.indexOf('error') > -1) {
$ghost.addClass('NoticeError');
$ghost.addClass(Notifications.options.classError);
delay = Notifications.options.ghostDelayError;
} else if(notification.flagNames.indexOf('warning') > -1) {
$ghost.addClass('NoticeWarning');
$ghost.addClass(Notifications.options.classWarning);
delay = Notifications.options.ghostDelayError;
} else {
$ghost.addClass('NoticeMessage');
$ghost.addClass(Notifications.options.classMessage);
}
Notifications.$ghosts.append($li.hide());
@@ -767,6 +774,8 @@ var Notifications = {
Notifications.$list = $("#NotificationList");
Notifications.$ghosts = $("#NotificationGhosts");
if(!Notifications.$bug.length) return;
Notifications.$menu.hide();
Notifications.$bug.click(Notifications.clickBug);
Notifications.useSession = typeof sessionStorage != "undefined";

File diff suppressed because one or more lines are too long

View File

@@ -67,6 +67,7 @@ class SystemNotifications extends WireData implements Module {
// hook method to access notifications, in case field name ever needs to change for some reason
$this->addHook('User::notifications', $this, 'hookUserNotifications');
$this->set('disabled', false);
}
/**
@@ -292,6 +293,8 @@ class SystemNotifications extends WireData implements Module {
*/
public function hookAdminThemeGetExtraMarkup($event) {
if($this->disabled) return;
$config = $this->wire('config');
$url = $config->urls->SystemNotifications . 'Notifications';
$info = self::getModuleInfo();
@@ -326,6 +329,17 @@ class SystemNotifications extends WireData implements Module {
}
$options['reverse'] = (bool) ((int) $options['reverse']);
// options specified in $config->SystemNotifications
$configDefaults = array(
'classMessage' => 'NoticeMessage',
'classWarning' => 'NoticeWarning',
'classError' => 'NoticeError',
'classContainer' => 'container',
);
$configOptions = $this->wire('config')->SystemNotifications;
if(!is_array($configOptions)) $configOptions = array();
$options = array_merge($options, $configDefaults, $configOptions);
$textdomain = '/wire/core/Functions.php';
$options['i18n'] = array(
'sec' => __('sec', $textdomain),