mirror of
https://github.com/processwire/processwire.git
synced 2025-08-10 00:37:02 +02:00
Add support for custom configuration of what Fieldtype/Inputfield settings may be overridden for field/template context. Appears only in $config->advanced mode. You can see it when editing a field (ProcessField) on the "Overrides" tab. Related to processwire/processwire-requests#145
This commit is contained in:
@@ -31,6 +31,7 @@
|
||||
* @property array $viewRoles Role IDs with view access, applicable only if access control is enabled. #pw-group-access
|
||||
* @property array|null $orderByCols Columns that WireArray values are sorted by (default=null), Example: "sort" or "-created". #pw-internal
|
||||
* @property int|null $paginationLimit Used by paginated WireArray values to indicate limit to use during load. #pw-internal
|
||||
* @property array $allowContexts Names of settings that are custom configured to be allowed for context. #pw-group-properties
|
||||
*
|
||||
* Common Inputfield properties that Field objects store:
|
||||
* @property int|bool|null $required Whether or not this field is required during input #pw-group-properties
|
||||
@@ -341,16 +342,17 @@ class Field extends WireData implements Saveable, Exportable {
|
||||
*/
|
||||
public function get($key) {
|
||||
if($key == 'viewRoles') return $this->viewRoles;
|
||||
else if($key == 'editRoles') return $this->editRoles;
|
||||
else if($key == 'table') return $this->getTable();
|
||||
else if($key == 'prevTable') return $this->prevTable;
|
||||
else if($key == 'prevFieldtype') return $this->prevFieldtype;
|
||||
else if(isset($this->settings[$key])) return $this->settings[$key];
|
||||
else if($key == 'icon') return $this->getIcon(true);
|
||||
else if($key == 'useRoles') return ($this->settings['flags'] & self::flagAccess) ? true : false;
|
||||
else if($key == 'flags') return $this->settings['flags'];
|
||||
else if($key == 'editRoles') return $this->editRoles;
|
||||
else if($key == 'table') return $this->getTable();
|
||||
else if($key == 'prevTable') return $this->prevTable;
|
||||
else if($key == 'prevFieldtype') return $this->prevFieldtype;
|
||||
else if(isset($this->settings[$key])) return $this->settings[$key];
|
||||
else if($key == 'icon') return $this->getIcon(true);
|
||||
else if($key == 'useRoles') return ($this->settings['flags'] & self::flagAccess) ? true : false;
|
||||
else if($key == 'flags') return $this->settings['flags'];
|
||||
|
||||
$value = parent::get($key);
|
||||
if($key === 'allowContexts' && !is_array($value)) $value = array();
|
||||
if(is_array($this->trackGets)) $this->trackGets($key);
|
||||
return $value;
|
||||
}
|
||||
@@ -916,6 +918,7 @@ class Field extends WireData implements Saveable, Exportable {
|
||||
if($fieldgroupContext) {
|
||||
$allowContext = $this->type->getConfigAllowContext($this);
|
||||
if(!is_array($allowContext)) $allowContext = array();
|
||||
$allowContext = array_merge($allowContext, $this->allowContexts);
|
||||
} else {
|
||||
$allowContext = array();
|
||||
}
|
||||
@@ -926,6 +929,8 @@ class Field extends WireData implements Saveable, Exportable {
|
||||
if(!$fieldgroupContext) $inputfields->head = $this->_('Field type details');
|
||||
$inputfields->attr('title', $this->_('Details'));
|
||||
$inputfields->attr('id+name', 'fieldtypeConfig');
|
||||
$remainingNames = array();
|
||||
foreach($allowContext as $name) $remainingNames[$name] = $name;
|
||||
|
||||
try {
|
||||
$fieldtypeInputfields = $this->type->getConfigInputfields($this);
|
||||
@@ -940,7 +945,19 @@ class Field extends WireData implements Saveable, Exportable {
|
||||
foreach($fieldtypeInputfields as $inputfield) {
|
||||
if($fieldgroupContext && !in_array($inputfield->name, $allowContext)) continue;
|
||||
$inputfields->append($inputfield);
|
||||
unset($remainingNames[$inputfield->name]);
|
||||
}
|
||||
// now capture those that may have been stuck in a fieldset
|
||||
if($fieldgroupContext) {
|
||||
foreach($remainingNames as $name) {
|
||||
if($inputfields->getChildByName($name)) continue;
|
||||
$inputfield = $fieldtypeInputfields->getChildByName($name);
|
||||
if(!$inputfield) continue;
|
||||
$inputfields->append($inputfield);
|
||||
unset($remainingNames[$inputfield->name]);
|
||||
}
|
||||
}
|
||||
|
||||
} catch(\Exception $e) {
|
||||
$this->trackException($e, false, true);
|
||||
}
|
||||
@@ -955,11 +972,15 @@ class Field extends WireData implements Saveable, Exportable {
|
||||
if($inputfield) {
|
||||
if($fieldgroupContext) {
|
||||
$allowContext = array('visibility', 'collapsed', 'columnWidth', 'required', 'requiredIf', 'showIf');
|
||||
$allowContext = array_merge($allowContext, $inputfield->getConfigAllowContext($this));
|
||||
$allowContext = array_merge($allowContext, $this->allowContexts, $inputfield->getConfigAllowContext($this));
|
||||
} else {
|
||||
$allowContext = array();
|
||||
$inputfields->head = $this->_('Input field settings');
|
||||
}
|
||||
$remainingNames = array();
|
||||
foreach($allowContext as $name) {
|
||||
$remainingNames[$name] = $name;
|
||||
}
|
||||
$inputfields->attr('title', $this->_('Input'));
|
||||
$inputfields->attr('id+name', 'inputfieldConfig');
|
||||
$inputfieldInputfields = $inputfield->getConfigInputfields();
|
||||
@@ -974,6 +995,16 @@ class Field extends WireData implements Saveable, Exportable {
|
||||
foreach($inputfieldInputfields as $i) {
|
||||
if($fieldgroupContext && !in_array($i->name, $allowContext)) continue;
|
||||
$inputfields->append($i);
|
||||
unset($remainingNames[$i->name]);
|
||||
}
|
||||
if($fieldgroupContext) {
|
||||
foreach($remainingNames as $name) {
|
||||
if($inputfields->getChildByName($name)) continue;
|
||||
$inputfield = $inputfieldInputfields->getChildByName($name);
|
||||
if(!$inputfield) continue;
|
||||
$inputfields->append($inputfield);
|
||||
unset($remainingNames[$inputfield->name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -911,7 +911,8 @@ class ProcessField extends Process implements ConfigurableModule {
|
||||
if(!$fieldgroup->hasFieldContext($field->name, $this->contextNamespace)) continue;
|
||||
$allChanges[$fieldgroup->name] = $this->getContextChanges($form, $field, $fieldgroup);
|
||||
}
|
||||
if(!count($allChanges)) return;
|
||||
|
||||
if(!count($allChanges) && !$this->wire('config')->advanced) return;
|
||||
|
||||
$tab = $this->wire(new InputfieldWrapper());
|
||||
$tab->attr('title', $this->_('Overrides'));
|
||||
@@ -932,43 +933,117 @@ class ProcessField extends Process implements ConfigurableModule {
|
||||
$f->notes = $this->_('To edit an override setting or override other settings, edit any template and click the field name in the fields list.');
|
||||
}
|
||||
$tab->add($f);
|
||||
|
||||
if(count($allChanges)) {
|
||||
/** @var MarkupAdminDataTable $table */
|
||||
$table = $this->wire('modules')->get('MarkupAdminDataTable');
|
||||
$table->setEncodeEntities(false);
|
||||
$table->setSortable(false);
|
||||
$header = array();
|
||||
if(!$this->fieldgroup) $header[] = $this->_x('Template', 'context-thead');
|
||||
$header[] = $this->_x('Setting', 'context-thead');
|
||||
$header[] = $this->_x('Original', 'context-thead');
|
||||
$header[] = $this->_x('Override', 'context-thead');
|
||||
$header[] = "<i class='fa fa-fw fa-lg fa-trash override-select-all'></i>";
|
||||
$table->headerRow($header);
|
||||
|
||||
$sanitizer = $this->wire('sanitizer');
|
||||
$lastFieldgroupName = '';
|
||||
$this->wire('modules')->get('JqueryUI')->use('modal');
|
||||
|
||||
foreach($allChanges as $fieldgroupName => $changes) {
|
||||
$fieldgroup = $this->wire('fieldgroups')->get($fieldgroupName);
|
||||
foreach($changes as $key => $change) {
|
||||
$a = $fieldgroupName;
|
||||
// $a = "<a class='pw-modal' data-buttons='#Inputfield_submit_save_field' data-autoclose='1' " .
|
||||
// "href='./edit?id={$this->field->id}&fieldgroup_id=$fieldgroup->id'>$fieldgroupName</a>";
|
||||
$fieldgroupLabel = $fieldgroupName == $lastFieldgroupName ? '' : $a;
|
||||
$row = array();
|
||||
if(!$this->fieldgroup) $row[] = $fieldgroupLabel;
|
||||
$row[] = $sanitizer->entities($change['label']);
|
||||
$row[] = "<del>" . $sanitizer->entities($change['originalValue']) . "</del>";
|
||||
$row[] = $sanitizer->entities($change['value']);
|
||||
$row[] = "<input type='checkbox' name='_remove_context[]' value='$fieldgroup->id:$key' />";
|
||||
$options = $fieldgroupLabel ? array('separator' => true) : array();
|
||||
$table->row($row, $options);
|
||||
$lastFieldgroupName = $fieldgroupName;
|
||||
}
|
||||
}
|
||||
|
||||
$f->value = $table->render();
|
||||
} else {
|
||||
$f->value = '<p>' . $this->_('There are currently no settings being overridden by template.') . '</p>';
|
||||
$f->collapsed = Inputfield::collapsedYes;
|
||||
}
|
||||
|
||||
/** @var MarkupAdminDataTable $table */
|
||||
$table = $this->wire('modules')->get('MarkupAdminDataTable');
|
||||
$table->setEncodeEntities(false);
|
||||
$table->setSortable(false);
|
||||
$header = array();
|
||||
if(!$this->fieldgroup) $header[] = $this->_x('Template', 'context-thead');
|
||||
$header[] = $this->_x('Setting', 'context-thead');
|
||||
$header[] = $this->_x('Original', 'context-thead');
|
||||
$header[] = $this->_x('Override', 'context-thead');
|
||||
$header[] = "<i class='fa fa-trash-o override-select-all'></i>";
|
||||
$table->headerRow($header);
|
||||
// allow the following configuration only for advanced mode
|
||||
if(!$this->wire('config')->advanced) return;
|
||||
|
||||
$sanitizer = $this->wire('sanitizer');
|
||||
$lastFieldgroupName = '';
|
||||
$this->wire('modules')->get('JqueryUI')->use('modal');
|
||||
|
||||
foreach($allChanges as $fieldgroupName => $changes) {
|
||||
$fieldgroup = $this->wire('fieldgroups')->get($fieldgroupName);
|
||||
foreach($changes as $key => $change) {
|
||||
$a = $fieldgroupName;
|
||||
// $a = "<a class='pw-modal' data-buttons='#Inputfield_submit_save_field' data-autoclose='1' " .
|
||||
// "href='./edit?id={$this->field->id}&fieldgroup_id=$fieldgroup->id'>$fieldgroupName</a>";
|
||||
$fieldgroupLabel = $fieldgroupName == $lastFieldgroupName ? '' : $a;
|
||||
$row = array();
|
||||
if(!$this->fieldgroup) $row[] = $fieldgroupLabel;
|
||||
$row[] = $sanitizer->entities($change['label']);
|
||||
$row[] = "<del>" . $sanitizer->entities($change['originalValue']) . "</del>";
|
||||
$row[] = $sanitizer->entities($change['value']);
|
||||
$row[] = "<input type='checkbox' name='_remove_context[]' value='$fieldgroup->id:$key' />";
|
||||
$options = $fieldgroupLabel ? array('separator' => true) : array();
|
||||
$table->row($row, $options);
|
||||
$lastFieldgroupName = $fieldgroupName;
|
||||
/** @var InputfieldCheckboxes $field */
|
||||
$field = $this->modules->get('InputfieldCheckboxes');
|
||||
$field->attr('name', 'allowContexts');
|
||||
$field->label = $this->_('Allowed overrides');
|
||||
$field->icon = 'sliders';
|
||||
$field->description =
|
||||
$this->_('Checked settings will appear as configuration options when editing this field within the context of a particular template.') . ' ' .
|
||||
$this->_('**Warning:** doing this for settings beyond those specified by the module author may not always work, or may cause problems.');
|
||||
$field->table = true;
|
||||
$field->thead =
|
||||
$this->_('Label') . '|' .
|
||||
$this->_('Name') . '|' .
|
||||
$this->_('Type');
|
||||
|
||||
$tabNames = array(
|
||||
'fieldtypeConfig' => $this->_('Details:'),
|
||||
'inputfieldConfig' => $this->_('Input:')
|
||||
);
|
||||
$exclusions = array(
|
||||
'collapsed',
|
||||
'showIf',
|
||||
'required',
|
||||
'requiredIf',
|
||||
'columnWidth',
|
||||
'visibility',
|
||||
'themeOffset',
|
||||
'themeBorder',
|
||||
'themeColor',
|
||||
);
|
||||
|
||||
$fieldtypeNames = $this->field->type->getConfigAllowContext($this->field);
|
||||
if(!is_array($fieldtypeNames)) $fieldtypeNames = array();
|
||||
$dummyPage = $this->wire('pages')->get("/"); // only using this to satisfy param requirement
|
||||
$inputfieldNames = $this->field->getInputfield($dummyPage)->getConfigAllowContext($this->field);
|
||||
if(!is_array($inputfieldNames)) $inputfieldNames = array();
|
||||
$alwaysSelected = array_merge($fieldtypeNames, $inputfieldNames);
|
||||
$allowContexts = $this->field->get('allowContexts');
|
||||
$alwaysSelected = array_diff($alwaysSelected, $allowContexts);
|
||||
$qty = 0;
|
||||
|
||||
foreach($tabNames as $tabName => $tabLabel) {
|
||||
/** @var InputfieldWrapper $tabInputfield */
|
||||
$tabInputfield = $form->getChildByName($tabName);
|
||||
if(!$tabInputfield) continue;
|
||||
foreach($tabInputfield->getAll() as $f) {
|
||||
$name = $f->name;
|
||||
if(strpos($name, '_') === 0) continue;
|
||||
if(in_array($name, $exclusions)) continue;
|
||||
if($f instanceof InputfieldWrapper || $f instanceof InputfieldMarkup || $f instanceof InputfieldHidden) continue;
|
||||
$typeName = str_replace('Inputfield', '', $f->className());
|
||||
$label = str_replace('|', ' ', "$tabLabel $f->label") .
|
||||
"| [span.detail] $name [/span] " .
|
||||
"| [span.detail] $typeName [/span]";
|
||||
if(in_array($name, $alwaysSelected)) {
|
||||
$field->addOption($name, $label, array('checked' => 'checked', 'disabled' => 'disabled'));
|
||||
$allowContexts[] = $name;
|
||||
} else {
|
||||
$field->addOption($name, $label);
|
||||
$qty++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$f->value = $table->render();
|
||||
$field->attr('value', $allowContexts);
|
||||
if($qty) $tab->append($field);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user