mirror of
https://github.com/processwire/processwire.git
synced 2025-08-09 16:26:59 +02:00
Add support for Inputfield header dropdown menu actions. These expand upon the existing Inputfield header actions added in 3.0.240 and enable you to have dropdown menus contain more actions within them.
This commit is contained in:
@@ -62,6 +62,7 @@
|
||||
* @property string $tabLabel Label for tab if Inputfield rendered in its own tab via Inputfield::collapsedTab* setting. @since 3.0.201 #pw-group-labels
|
||||
* @property string|null $prependMarkup Optional markup to prepend to the Inputfield content container. #pw-group-other
|
||||
* @property string|null $appendMarkup Optional markup to append to the Inputfield content container. #pw-group-other
|
||||
* @property string|null $footerMarkup Optional markup to add to the '.Inputfield' container, after '.InputfieldContent'. @since 3.0.241 #pw-advanced
|
||||
*
|
||||
* @method string|Inputfield label($label = null) Get or set the 'label' property via method. @since 3.0.110 #pw-group-labels
|
||||
* @method string|Inputfield description($description = null) Get or set the 'description' property via method. @since 3.0.110 #pw-group-labels
|
||||
@@ -433,8 +434,9 @@ abstract class Inputfield extends WireData implements Module {
|
||||
$this->set('textFormat', self::textFormatBasic); // format applied to description and notes
|
||||
$this->set('renderFlags', 0); // See render* constants
|
||||
$this->set('renderValueFlags', 0); // see renderValue* constants, applicable to renderValue mode only
|
||||
$this->set('prependMarkup', ''); // markup to prepend to Inputfield output
|
||||
$this->set('appendMarkup', ''); // markup to append to Inputfield output
|
||||
$this->set('prependMarkup', ''); // markup to prepend to InputfieldContent output
|
||||
$this->set('appendMarkup', ''); // markup to append to InputfieldContent output
|
||||
$this->set('footerMarkup', ''); // markup to add to end of Inputfield output
|
||||
|
||||
// default ID attribute if no 'id' attribute set
|
||||
$this->defaultID = $this->className() . self::$numInstances;
|
||||
@@ -2104,16 +2106,16 @@ abstract class Inputfield extends WireData implements Module {
|
||||
* `toggle` or 'link' action based on what you provide in the $settings argument.
|
||||
* Below is a summary of these settings:
|
||||
*
|
||||
* Settings for 'click' or 'link' type actions:
|
||||
*
|
||||
* Settings for 'click' or 'link' type actions
|
||||
* -------------------------------------------
|
||||
* - `icon` (string): Name of font-awesome icon to use.
|
||||
* - `tooltip` (string): Optional tooltip text to display when icon hovered.
|
||||
* - `event` (string): Event name to trigger in JS when clicked ('click' actions only).
|
||||
* - `href` (string): URL to open ('link' actions only).
|
||||
* - `modal` (bool): Specify true to open link in modal ('link' actions only).
|
||||
*
|
||||
* Settings for 'toggle' (on/off) type actions:
|
||||
*
|
||||
* Settings for 'toggle' (on/off) type actions
|
||||
* -------------------------------------------
|
||||
* - `on` (bool): Start with the 'on' state? (default=false)
|
||||
* - `onIcon` (string): Name of font-awesome icon to show for on state.
|
||||
* - `onEvent` (string): JS event name to trigger when toggled on.
|
||||
@@ -2122,15 +2124,41 @@ abstract class Inputfield extends WireData implements Module {
|
||||
* - `offEvent` (string): JS event name to trigger when toggled off.
|
||||
* - `offTooltip` (string): Tooltip text to show when off icon is hovered.
|
||||
*
|
||||
* Other/optional settings (applies to all types):
|
||||
*
|
||||
* Other/optional settings (applies to all types)
|
||||
* ----------------------------------------------
|
||||
* - `name` (string): Name of this action (-_a-zA-Z0-9).
|
||||
* - `parent` (string): Name of parent action, if this action is part of a menu.
|
||||
* - `overIcon` (string): Name of font-awesome icon to show when hovered.
|
||||
* - `overEvent` (string): JS event name to trigger when mouse is over the icon.
|
||||
* - `downIcon` (string): Icon to display when mouse is down on the action icon (3.0.241+).
|
||||
* - `downEvent` (string): JS event name to trigger when mouse is down on the icon (3.0.241+).
|
||||
* - `cursor` (string): CSS cursor name to show when mouse is over the icon.
|
||||
* - `setAll` (array): Set all of the header actions in one call, replaces any existing.
|
||||
* Note: to get all actions, call the method and omit the $settings argument.
|
||||
*
|
||||
* Settings for dropdown menu actions (3.0.241+)
|
||||
* ---------------------------------------------
|
||||
* Note that menu type actions also require jQuery UI and /wire/templates-admin/scripts/main.js,
|
||||
* both of which are already present in PW’s admin themes (AdminThemeUikit recommended).
|
||||
* Requires ProcessWire 3.0.241 or newer.
|
||||
* - `icon` (string): Icon name to use for dropdown toggle, i.e. 'fa-wrench'.
|
||||
* - `tooltip` (string): Optional tooltip to describe what the dropdown is for.
|
||||
* - `menuAction` (string): Action that toggles the menu to show, one of 'click' or 'hover' (default).
|
||||
* - `menuItems` (array): Definition of menu items, each with one or more of the following properties.
|
||||
* - `label` (string): Label text for the menu item (required).
|
||||
* - `icon` (string): Icon name for the menu item, if desired.
|
||||
* - `callback` (function|null): JS callback to execute item is clicked (not applicable in PHP).*
|
||||
* - `event` (string): JS event name to trigger when item is clicked.
|
||||
* - `tooltip` (string): Tooltip text to show when hovering menu item (title attribute).
|
||||
* - `href` (string): URL to go to when menu item clicked.
|
||||
* - `target` (string): Target attribute when href is used (i.e. "_blank").
|
||||
* - `modal` (bool): Open href in modal window instead?
|
||||
* - `active` (function|bool): Callback function that returns true if menu item active, or false.*
|
||||
* if disabled. You can also directly specify true or false for this option.
|
||||
* - NOTE 1: All `menuItems` properties above are optional, except for 'label'.
|
||||
* - NOTE 2: To use `callback` or `active` as functions, you must define your menu in JS instead.
|
||||
* - NOTE 3: For examples see the addHeaderAction() method in /wire/templates-admin/scripts/inputfields.js
|
||||
*
|
||||
* @param array $settings Specify array containing the appropriate settings above.
|
||||
* @return array Returns all currently added actions.
|
||||
* @since 3.0.240
|
||||
|
@@ -974,6 +974,7 @@ class InputfieldWrapper extends Inputfield implements \Countable, \IteratorAggre
|
||||
$markupItemContent = str_replace('{class}', '', $markupItemContent);
|
||||
}
|
||||
if($inputfield->className() != 'InputfieldWrapper') $ffOut = str_replace('{out}', $ffOut, $markupItemContent);
|
||||
$ffOut .= $inputfield->getSetting('footerMarkup');
|
||||
$out .= str_replace(array('{attrs}', '{out}'), array(trim($attrs), $label . $ffOut), $markup['item']);
|
||||
$lastInputfield = $inputfield;
|
||||
} // foreach($children as $inputfield)
|
||||
|
@@ -901,6 +901,21 @@ var Inputfields = {
|
||||
return $inputfield;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get an Inputfield by name, id or element
|
||||
*
|
||||
* This is an alias of the inputfield() function and works the same way,
|
||||
* but this syntax may be preferred in some cases.
|
||||
*
|
||||
* @param value
|
||||
* @returns object
|
||||
* @since 3.0.241
|
||||
*
|
||||
*/
|
||||
get: function(value) {
|
||||
return this.inputfield(value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the .InputfieldHeader element for given Inputfield (or id, name, element within)
|
||||
*
|
||||
@@ -1074,7 +1089,8 @@ var Inputfields = {
|
||||
* `toggle` or 'link' action based on what you provide in the settings argument.
|
||||
* Below is a summary of these settings:
|
||||
*
|
||||
* Settings for 'click' and 'link' type actions:
|
||||
* Settings for 'click' and 'link' type actions
|
||||
* ============================================
|
||||
* - `icon` (string): Class to use for icon, i.e. 'fa-cog'.
|
||||
* - `callback` (function): Callback function when action icon is clicked.
|
||||
* - `event` (string): Event name to trigger in JS when clicked ('click' actions only).
|
||||
@@ -1083,7 +1099,8 @@ var Inputfields = {
|
||||
* - `modal` (bool): Specify true to make a link open in a modal window ('link' actions only).
|
||||
* (requires that /wire/modules/JqueryUI/JqueryUI/modal.js is loaded)
|
||||
*
|
||||
* Settings for 'toggle' (on/off) type actions:
|
||||
* Settings for 'toggle' (on/off) type actions
|
||||
* ===========================================
|
||||
* - `on` (bool): True if action is currently ON, false if not (default=false).
|
||||
* - `onIcon` (string): Icon class when action is ON and clicking would toggle OFF, i.e. 'fa-toggle-off'.
|
||||
* - `onCallback` (function): Callback function when action is clicked to turn ON.
|
||||
@@ -1095,10 +1112,37 @@ var Inputfields = {
|
||||
* - `offTooltip` (string): Optional tooltip text for when action is OFF.
|
||||
* - Note that if 'offIcon' or 'offTooltip' are omitted, they will use their 'on' equivalent.
|
||||
*
|
||||
* Other/optional settings (applies to all types):
|
||||
* Settings for dropdown 'menu' type actions
|
||||
* =========================================
|
||||
* Note that menu type actions also require jQuery UI and /wire/templates-admin/scripts/main.js,
|
||||
* both of which are already present in PW’s admin themes (AdminThemeUikit recommended).
|
||||
* Dropdown menu actions require ProcessWire 3.0.241 or newer.
|
||||
* - `icon` (string): Icon name to use for dropdown toggle, i.e. 'fa-wrench'.
|
||||
* - `tooltip` (string): Optional tooltip to describe what the dropdown is for.
|
||||
* - `menuItems` (array): Definition of menu items, each with one or more of the following properties.
|
||||
* - `label` (string): Label text for the menu item (required).
|
||||
* - `icon` (string): Icon name for the menu item, if desired.
|
||||
* - `callback` (function|null): JS callback function to execute item is clicked.
|
||||
* - `event` (string): JS event name to trigger when item is clicked.
|
||||
* - `tooltip` (string): Tooltip text to show when hovering menu item (title attribute).
|
||||
* - `href` (string): URL to go to when menu item clicked.
|
||||
* - `target` (string): Target attribute when href is used (i.e. "_blank").
|
||||
* - `modal` (bool): Open href in modal window instead?
|
||||
* - `active` (function|bool): Callback function that returns true if menu item active, or false
|
||||
* if disabled. You can also directly specify true or false for this option.
|
||||
* - Note that all menuItems properties above are optional, except for 'label'.
|
||||
* - `menuAction` (string): Action that toggles the menu to show, one of 'click' or 'hover' (default).
|
||||
* - `menuMy` (string): The 'my' jQuery position (default='right top') https://api.jqueryui.com/menu/#option-position
|
||||
* - `menuAt` (string): The 'at' jQuery position (default='right+15 bottom') https://api.jqueryui.com/menu/#option-position
|
||||
*
|
||||
* Other/optional settings (applies to all types)
|
||||
* ==============================================
|
||||
* - `name` (string): Name of action using only characters [_-a-zA-Z0-9].
|
||||
* - `overIcon` (string): Optional icon class when mouse cursor is hovering OVER the action.
|
||||
* - `overCallback` (function): Optional callback function when mouse cursor is hovering OVER the action.
|
||||
* - `downIcon` (string): Optional icon class when mouse is down (3.0.241+).
|
||||
* - `downCallback` (function): Optional callback function when mouse is down on the icon (3.0.241+).
|
||||
* - `downEvent` (string): Optional JS event to trigger when mouse is down on the icon (3.0.241+).
|
||||
* - `cursor` (function): Optional/alternate mouse cursor to show when hovering over the action.
|
||||
* - `iconTag` (string): Optionally override the default <i> tag used for the icon. You can specify this
|
||||
* if you want to use a non-FontAwesome icon.
|
||||
@@ -1128,6 +1172,40 @@ var Inputfields = {
|
||||
* ProcessWire.alert('You toggled off');
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* // Add a dropdown menu with select-all/unselect-all for a checkboxes field
|
||||
* $f = Inputfields.get('checkboxes_field_name');
|
||||
* Inputfields.addHeaderAction($f, {
|
||||
* name: 'tools',
|
||||
* icon: 'fa-wrench',
|
||||
* tooltip: 'Select or unselect all',
|
||||
* menuItems: [
|
||||
* {
|
||||
* name: 'select-all',
|
||||
* label: 'Select all',
|
||||
* icon: 'fa-check-square-o',
|
||||
* callback: function() {
|
||||
* $f.find('input[type=checkbox]').prop('checked', true);
|
||||
* $f.trigger('change');
|
||||
* },
|
||||
* active: function() {
|
||||
* return $f.find('input[type=checkbox]').not(':checked').length > 0;
|
||||
* }
|
||||
* },
|
||||
* {
|
||||
* name: 'unselect-all',
|
||||
* label: 'Unselect all',
|
||||
* icon: 'fa-square-o',
|
||||
* callback: function() {
|
||||
* $f.find('input[type=checkbox]').prop('checked', false);
|
||||
* $f.trigger('change');
|
||||
* },
|
||||
* active: function() {
|
||||
* return $f.find('input[type=checkbox]:checked').length > 0;
|
||||
* }
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
* ~~~~~
|
||||
*
|
||||
* Note: all callback functions receive the $icon element returned by this function,
|
||||
@@ -1166,14 +1244,27 @@ var Inputfields = {
|
||||
overCallback: null,
|
||||
overEvent: '',
|
||||
cursor: '',
|
||||
// other
|
||||
// for optional mousedown state:
|
||||
downIcon: '',
|
||||
downCallback: null,
|
||||
downEvent: '',
|
||||
// name of this action (to make getable by getHeaderAction)
|
||||
name: '',
|
||||
// tag to use for icon
|
||||
iconTag: '<i class="fa fa-fw"></i>',
|
||||
// icon element if already present
|
||||
$iconElement: null,
|
||||
// items for menu, see menuItemDefaults in _addHeaderActionMenu()
|
||||
menuItems: [],
|
||||
// type of dropdown menu: 'click' or 'hover' (requires menuItems)
|
||||
menuAction: 'hover',
|
||||
// jQuery UI 'my' and 'at' position values for menu (https://api.jqueryui.com/menu/#option-position)
|
||||
menuMy: 'right top',
|
||||
menuAt: 'right+15 bottom'
|
||||
};
|
||||
|
||||
settings = $.extend(defaults, settings);
|
||||
$inputfield = this.inputfield($inputfield);
|
||||
|
||||
var $header = this.header($inputfield);
|
||||
var $icon = settings.$iconElement ? settings.$iconElement : $(settings.iconTag);
|
||||
@@ -1261,12 +1352,134 @@ var Inputfields = {
|
||||
}
|
||||
}
|
||||
|
||||
if(settings.downIcon.length || settings.downCallback || settings.downEvent) {
|
||||
$icon.on('mousedown', function() {
|
||||
if(settings.downIcon.length) {
|
||||
$icon.addClass(fa(settings.downIcon));
|
||||
}
|
||||
if(settings.downCallback) settings.downCallback($icon);
|
||||
if(settings.downEvent) $icon.trigger(settings.downEvent, [ $icon ]);
|
||||
});
|
||||
if(settings.downIcon.length) {
|
||||
$icon.on('mouseup', function() {
|
||||
$icon.removeClass(fa(settings.downIcon));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// setup dropdown menu if specified
|
||||
if(settings.menuItems.length) {
|
||||
for(var n = 0; n < settings.menuItems.length; n++) {
|
||||
if(typeof settings.menuItems[n].icon === 'undefined') continue;
|
||||
settings.menuItems[n].icon = fa(settings.menuItems[n].icon);
|
||||
}
|
||||
this._addHeaderActionMenu($inputfield, $header, $icon, settings);
|
||||
}
|
||||
|
||||
$header.append($icon);
|
||||
if($icon.prop('hidden')) $icon.prop('hidden', false);
|
||||
|
||||
return $icon;
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup dropdown 'menu' type header actions for addHeaderAction() function
|
||||
*
|
||||
* @param $inputfield
|
||||
* @param settings
|
||||
* @private
|
||||
*
|
||||
*/
|
||||
_addHeaderActionMenu: function($inputfield, $header, $icon, settings) {
|
||||
|
||||
var menuItemDefaults = {
|
||||
icon: '', // optional icon
|
||||
label: '', // menu item label (required)
|
||||
callback: null, // function to call on click
|
||||
event: '', // event to trigger on click
|
||||
tooltip: '', // tooltip text (title attribute)
|
||||
href: '', // URL to link to
|
||||
target: '', // if href populated, i.e. '_blank'
|
||||
modal: false, // if href populated, open in modal?
|
||||
active: true, // is item active? Specify callback that returns true or false
|
||||
};
|
||||
|
||||
if(!settings.name.length) {
|
||||
settings.name = 'act' + ($header.find('.InputfieldHeaderAction').length + 1);
|
||||
}
|
||||
|
||||
var menuId = $inputfield.attr('id') + '-menu-' + settings.name;
|
||||
var $menu = $('<ul></ul>').attr('id', menuId)
|
||||
.addClass('pw-dropdown-menu').css('display', 'none')
|
||||
.attr('data-my', settings.menuMy)
|
||||
.attr('data-at', settings.menuAt);
|
||||
|
||||
for(var n = 0; n < settings.menuItems.length; n++) {
|
||||
|
||||
var item = $.extend(menuItemDefaults, settings.menuItems[n]);
|
||||
var $li = $('<li></li>');
|
||||
var $a = $('<a></a>').text(item.label);
|
||||
|
||||
if(item.href) $a.attr('href', item.href);
|
||||
if(item.target) $a.attr('target', item.target);
|
||||
if(item.tooltip) $a.attr('title', item.tooltip);
|
||||
|
||||
if(item.icon) {
|
||||
var $itemIcon = $(settings.iconTag).addClass(item.icon);
|
||||
$a.prepend($itemIcon);
|
||||
}
|
||||
|
||||
$a.attr('data-n', n);
|
||||
$li.append($a);
|
||||
$menu.append($li);
|
||||
|
||||
$a.on('click', function() {
|
||||
var $a = $(this);
|
||||
var $li = $a.parent();
|
||||
if($li.hasClass('ui-state-disabled')) return false;
|
||||
var n = parseInt($a.attr('data-n'));
|
||||
// note: cannot use 'item' defined outside this function since
|
||||
// the 'n' value can be different
|
||||
var item = $.extend(menuItemDefaults, settings.menuItems[n]);
|
||||
if(item.callback) item.callback($a);
|
||||
if(typeof item.event !== 'undefined' && item.event.length) {
|
||||
$icon.trigger(item.event, [$a]);
|
||||
}
|
||||
if(item.href) {
|
||||
if(item.modal) {
|
||||
pwModalWindow(item.href);
|
||||
} else if(item.target.length) {
|
||||
return true;
|
||||
} else {
|
||||
window.location.href = item.href;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
$icon.addClass('pw-dropdown-toggle').attr('data-pw-dropdown', '#' + menuId);
|
||||
|
||||
if(settings.menuAction === 'click') $icon.addClass('pw-dropdown-toggle-click');
|
||||
|
||||
$inputfield.append($menu);
|
||||
|
||||
$menu.on('pw-show-dropdown', function() {
|
||||
$(this).children('li').each(function() {
|
||||
var $li = $(this);
|
||||
var $a = $li.children('a');
|
||||
var n = parseInt($a.attr('data-n'));
|
||||
var active = settings.menuItems[n].active;
|
||||
if(typeof active === 'function') active = active($a);
|
||||
if(active) {
|
||||
$li.removeClass('ui-state-disabled');
|
||||
} else {
|
||||
$li.addClass('ui-state-disabled');
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a previously added header action by name
|
||||
*
|
||||
@@ -2402,6 +2615,7 @@ function InputfieldStates($target) {
|
||||
$inputfields.trigger('reloaded', [ 'InputfieldAjaxLoad' ]);
|
||||
InputfieldStates($li);
|
||||
InputfieldRequirements($li);
|
||||
InputfieldHeaderActions($li);
|
||||
InputfieldColumnWidths();
|
||||
} else {
|
||||
$li.trigger('reloaded', [ 'InputfieldAjaxLoad' ]);
|
||||
|
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user