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

Lots of upgrades to ProcessField overrides tab

This commit is contained in:
Ryan Cramer
2019-10-31 15:39:18 -04:00
parent da36905422
commit 69e2c0e729
6 changed files with 339 additions and 118 deletions

View File

@@ -104,3 +104,16 @@ body.modal #fieldgroupContext {
.pw-init #ProcessFieldEdit { .pw-init #ProcessFieldEdit {
display: none; display: none;
} }
span.pw-diff {
color: #999;
}
ins {
color: green;
background: transparent;
font-weight: bold;
}
del {
color: red
}

View File

@@ -135,5 +135,11 @@ $(document).ready(function() {
return false; return false;
}); });
// update overrides table if anything was changed in a modal
$(document).on('pw-modal-closed', 'a', function(e, ui) {
if(!$('#tab-overrides').is(':visible')) return;
Inputfields.reload('#Inputfield_overrides_table');
});
}); });

View File

@@ -1 +1 @@
$(document).ready(function(){var e=function(){$("#field_filter_form").submit()};$("#templates_id").change(e);$("#fieldtype").change(e);$("#wrap_show_system input").click(e);var b=$("#asmListItemStatus");var d=$("#columnWidth");function a(){var i=b.attr("data-tpl");if(!i){return}var k=$("#Inputfield_showIf").val();var j=$("#Inputfield_required").is(":checked")?true:false;if(k&&k.length>0){i="<i class='fa fa-question-circle'></i>"+i}if(j){i="<i class='fa fa-asterisk'></i>"+i}var h=parseInt(d.val());if(h==100){h=0}if(h>0){h=h+"%"}else{h=""}i=i.replace("%",h);b.val(i)}$("#Inputfield_showIf").change(a);$("#Inputfield_required").change(a);a();if(d.length>0){var f=$("<div class='InputfieldColumnWidthSlider'></div>");var c=parseInt($("#columnWidth").val());d.val(c+"%");d.after(f);f.slider({range:"min",min:10,max:100,value:parseInt(d.val()),slide:function(i,h){var j=h.value+"%";d.val(j).trigger("change");a()}});d.change(function(){var h=parseInt($(this).val());if(h>100){h=100}if(h<10){h=10}$(this).val(h+"%");f.slider("option","value",h)})}var g=$("#ProcessFieldEdit");if(g.length>0&&$("li.WireTab").length>1){g.find("script").remove();g.WireTabs({items:$(".Inputfields li.WireTab"),id:"FieldEditTabs",skipRememberTabIDs:["delete"]})}$("#fieldgroupContextSelect").change(function(){var i=$("#Inputfield_id").val();var j=$(this).val();var h="./edit?id="+i;if(j>0){h+="&fieldgroup_id="+j}window.location=h});$("a.fieldFlag").click(function(){return false});$("#export_data").click(function(){$(this).select()});$(".import_toggle input[type=radio]").change(function(){var h=$(this).parents("p.import_toggle").next("table");var i=$(this).closest(".InputfieldFieldset");if($(this).is(":checked")&&$(this).val()==0){h.hide();i.addClass("ui-priority-secondary")}else{h.show();i.removeClass("ui-priority-secondary")}}).change();$("#wrap_Inputfield_send_templates").find(":input").change(function(){$("#_send_templates_changed").val("changed")});$("#viewRoles_37").click(function(){if($(this).is(":checked")){$("input.viewRoles").attr("checked","checked")}});$("input.viewRoles:not(#viewRoles_37)").click(function(){if($("#viewRoles_37").is(":checked")){return false}return true});$("input.editRoles:not(:disabled)").click(function(){if($(this).is(":checked")){$(this).closest("tr").find("input.viewRoles").attr("checked","checked")}});$(".override-select-all").click(function(){var h=$(this).closest("table").find("input[type=checkbox]");if($(this).hasClass("override-checked")){h.removeAttr("checked");$(this).removeClass("override-checked")}else{h.attr("checked","checked");$(this).addClass("override-checked")}return false})}); $(document).ready(function(){var fieldFilterFormChange=function(){$("#field_filter_form").submit()};$("#templates_id").change(fieldFilterFormChange);$("#fieldtype").change(fieldFilterFormChange);$("#wrap_show_system input").click(fieldFilterFormChange);var $asmListItemStatus=$("#asmListItemStatus");var $columnWidth=$("#columnWidth");function setAsmListItemStatus(){var tpl=$asmListItemStatus.attr("data-tpl");if(!tpl)return;var showIf=$("#Inputfield_showIf").val();var required=$("#Inputfield_required").is(":checked")?true:false;if(showIf&&showIf.length>0)tpl="<i class='fa fa-question-circle'></i>"+tpl;if(required)tpl="<i class='fa fa-asterisk'></i>"+tpl;var w=parseInt($columnWidth.val());if(w==100)w=0;if(w>0)w=w+"%";else w="";tpl=tpl.replace("%",w);$asmListItemStatus.val(tpl)}$("#Inputfield_showIf").change(setAsmListItemStatus);$("#Inputfield_required").change(setAsmListItemStatus);setAsmListItemStatus();if($columnWidth.length>0){var $slider=$("<div class='InputfieldColumnWidthSlider'></div>");var columnWidthVal=parseInt($("#columnWidth").val());$columnWidth.val(columnWidthVal+"%");$columnWidth.after($slider);$slider.slider({range:"min",min:10,max:100,value:parseInt($columnWidth.val()),slide:function(e,ui){var val=ui.value+"%";$columnWidth.val(val).trigger("change");setAsmListItemStatus()}});$columnWidth.change(function(){var val=parseInt($(this).val());if(val>100)val=100;if(val<10)val=10;$(this).val(val+"%");$slider.slider("option","value",val)})}var $fieldEdit=$("#ProcessFieldEdit");if($fieldEdit.length>0&&$("li.WireTab").length>1){$fieldEdit.find("script").remove();$fieldEdit.WireTabs({items:$(".Inputfields li.WireTab"),id:"FieldEditTabs",skipRememberTabIDs:["delete"]})}$("#fieldgroupContextSelect").change(function(){var field_id=$("#Inputfield_id").val();var fieldgroup_id=$(this).val();var href="./edit?id="+field_id;if(fieldgroup_id>0)href+="&fieldgroup_id="+fieldgroup_id;window.location=href});$("a.fieldFlag").click(function(){return false});$("#export_data").click(function(){$(this).select()});$(".import_toggle input[type=radio]").change(function(){var $table=$(this).parents("p.import_toggle").next("table");var $fieldset=$(this).closest(".InputfieldFieldset");if($(this).is(":checked")&&$(this).val()==0){$table.hide();$fieldset.addClass("ui-priority-secondary")}else{$table.show();$fieldset.removeClass("ui-priority-secondary")}}).change();$("#wrap_Inputfield_send_templates").find(":input").change(function(){$("#_send_templates_changed").val("changed")});$("#viewRoles_37").click(function(){if($(this).is(":checked"))$("input.viewRoles").attr("checked","checked")});$("input.viewRoles:not(#viewRoles_37)").click(function(){if($("#viewRoles_37").is(":checked"))return false;return true});$("input.editRoles:not(:disabled)").click(function(){if($(this).is(":checked")){$(this).closest("tr").find("input.viewRoles").attr("checked","checked")}});$(".override-select-all").click(function(){var $checkboxes=$(this).closest("table").find("input[type=checkbox]");if($(this).hasClass("override-checked")){$checkboxes.removeAttr("checked");$(this).removeClass("override-checked")}else{$checkboxes.attr("checked","checked");$(this).addClass("override-checked")}return false});$(document).on("pw-modal-closed","a",function(e,ui){if(!$("#tab-overrides").is(":visible"))return;Inputfields.reload("#Inputfield_overrides_table")})});

View File

@@ -753,6 +753,8 @@ class ProcessField extends Process implements ConfigurableModule {
$this->breadcrumb("./edit?id=" . $this->field->id, $this->field->name); $this->breadcrumb("./edit?id=" . $this->field->id, $this->field->name);
if($this->contextLabel) { if($this->contextLabel) {
$headline .= ' (' . sprintf($this->_('when used with: %s'), $this->contextLabel) . ')'; $headline .= ' (' . sprintf($this->_('when used with: %s'), $this->contextLabel) . ')';
} else if($this->contextNamespace) {
$headline .= ' (' . sprintf($this->_('when used with template “%1$s” in context “%2$s”'), $this->fieldgroup->name, $this->contextNamespace) . ')';
} else { } else {
$headline .= ' (' . sprintf($this->_('when used with template: %s'), $this->fieldgroup->name) . ')'; $headline .= ' (' . sprintf($this->_('when used with template: %s'), $this->fieldgroup->name) . ')';
} }
@@ -974,26 +976,48 @@ class ProcessField extends Process implements ConfigurableModule {
*/ */
protected function ___buildEditForm() { protected function ___buildEditForm() {
/** @var Sanitizer $sanitizer */
$sanitizer = $this->wire('sanitizer');
/** @var WireInput $input */
$input = $this->wire('input');
/** @var Modules $modules */
$modules = $this->wire('modules');
$isPost = $input->requestMethod('POST');
// optional context fieldgroup // optional context fieldgroup
$fieldgroup_id = (int) $input->post('fieldgroup_id');
if(!$fieldgroup_id && !$isPost) $fieldgroup_id = (int) $input->get('fieldgroup_id');
/*
if($this->input->post->fieldgroup_id) $fieldgroup_id = (int) $this->input->post->fieldgroup_id; if($this->input->post->fieldgroup_id) $fieldgroup_id = (int) $this->input->post->fieldgroup_id;
else if($this->input->get->fieldgroup_id && !count($_POST)) $fieldgroup_id = (int) $this->input->get->fieldgroup_id; else if($this->input->get->fieldgroup_id && !count($_POST)) $fieldgroup_id = (int) $this->input->get->fieldgroup_id;
else $fieldgroup_id = 0; else $fieldgroup_id = 0;
*/
if($fieldgroup_id) { if($fieldgroup_id) {
// optional namespace for context fieldgroup // optional namespace for context fieldgroup
if($this->input->post('_context_namespace')) $contextNamespace = $this->input->post('_context_namespace'); $contextNamespace = '';
else if($this->input->get('context_namespace') && !count($_POST)) $contextNamespace = $this->input->get('context_namespace'); if($input->post('_context_namespace')) {
else $contextNamespace = ''; $contextNamespace = $input->post('_context_namespace');
} else if($input->get('context_namespace') && !$isPost) {
$contextNamespace = $input->get('context_namespace');
}
if($contextNamespace) { if($contextNamespace) {
$contextNamespace = $this->wire('sanitizer')->fieldName($contextNamespace); $contextNamespace = $sanitizer->fieldName($contextNamespace);
$this->contextNamespace = $contextNamespace; $this->contextNamespace = $contextNamespace;
} }
} }
if($this->input->post('_context_label')) $contextLabel = $this->input->post('_context_label');
else if($this->input->get('context_label')) $contextLabel = $this->input->get('context_label'); $contextLabel = '';
else $contextLabel = ''; if($input->post('_context_label')) {
$contextLabel = $input->post('_context_label');
} else if($input->get('context_label')) {
$contextLabel = $this->input->get('context_label');
}
if(strlen($contextLabel)) { if(strlen($contextLabel)) {
$contextLabel = $this->wire('sanitizer')->entities($contextLabel); $contextLabel = $sanitizer->entities($sanitizer->text($contextLabel));
$this->contextLabel = $contextLabel; $this->contextLabel = $contextLabel;
} }
@@ -1003,9 +1027,9 @@ class ProcessField extends Process implements ConfigurableModule {
} }
/** @var InputfieldForm $form */ /** @var InputfieldForm $form */
$form = $this->modules->get('InputfieldForm'); $form = $modules->get('InputfieldForm');
$form->attr('id+name', 'ProcessFieldEdit'); $form->attr('id+name', 'ProcessFieldEdit');
$form->attr('action', 'save'); $form->attr('action', 'save?id=' . $this->field->id);
$form->attr('method', 'post'); $form->attr('method', 'post');
$form->addClass('InputfieldFormFocusFirst'); $form->addClass('InputfieldFormFocusFirst');
$this->form = $form; $this->form = $form;
@@ -1041,24 +1065,24 @@ class ProcessField extends Process implements ConfigurableModule {
} }
/** @var InputfieldHidden $field */ /** @var InputfieldHidden $field */
$field = $this->modules->get('InputfieldHidden'); $field = $modules->get('InputfieldHidden');
$field->attr('name', 'id'); $field->attr('name', 'id');
$field->attr('value', $this->field->id); $field->attr('value', $this->field->id);
$form->add($field); $form->add($field);
if($this->fieldgroup) { if($this->fieldgroup) {
$field = $this->modules->get('InputfieldHidden'); $field = $modules->get('InputfieldHidden');
$field->attr('name', 'fieldgroup_id'); $field->attr('name', 'fieldgroup_id');
$field->attr('value', $this->fieldgroup->id); $field->attr('value', $this->fieldgroup->id);
$form->add($field); $form->add($field);
if($this->contextNamespace) { if($this->contextNamespace) {
$field = $this->modules->get('InputfieldHidden'); $field = $modules->get('InputfieldHidden');
$field->attr('name', '_context_namespace'); $field->attr('name', '_context_namespace');
$field->attr('value', $this->contextNamespace); $field->attr('value', $this->contextNamespace);
$form->add($field); $form->add($field);
} }
if($this->contextLabel) { if($this->contextLabel) {
$field = $this->modules->get('InputfieldHidden'); $field = $modules->get('InputfieldHidden');
$field->attr('name', '_context_label'); $field->attr('name', '_context_label');
$field->attr('value', $this->contextLabel); $field->attr('value', $this->contextLabel);
$form->add($field); $form->add($field);
@@ -1066,17 +1090,17 @@ class ProcessField extends Process implements ConfigurableModule {
} }
/** @var InputfieldSubmit $field */ /** @var InputfieldSubmit $field */
$field = $this->modules->get('InputfieldSubmit'); $field = $modules->get('InputfieldSubmit');
$field->attr('value', $this->labels['save']); $field->attr('value', $this->labels['save']);
$field->attr('name', 'submit_save_field'); $field->attr('name', 'submit_save_field');
$field->showInHeader(); $field->showInHeader();
$form->add($field); $form->add($field);
if($this->wire('input')->get('process_template')) { if($input->get('process_template')) {
// ProcessTemplate has loaded the field editor in a modal window // ProcessTemplate has loaded the field editor in a modal window
// so we add a cancel button that asmSelect will recognize for it's modal // so we add a cancel button that asmSelect will recognize for it's modal
/** @var InputfieldButton $field */ /** @var InputfieldButton $field */
$field = $this->modules->get('InputfieldButton'); $field = $modules->get('InputfieldButton');
$field->attr('id+name', 'modal_cancel_button'); $field->attr('id+name', 'modal_cancel_button');
$field->attr('value', $this->_x('Cancel', 'button')); $field->attr('value', $this->_x('Cancel', 'button'));
$field->setSecondary(); $field->setSecondary();
@@ -1084,14 +1108,33 @@ class ProcessField extends Process implements ConfigurableModule {
// contains the asm list item status, populated by JS // contains the asm list item status, populated by JS
/** @var InputfieldHidden $field */ /** @var InputfieldHidden $field */
$field = $this->modules->get('InputfieldHidden'); $field = $modules->get('InputfieldHidden');
$field->attr('id+name', 'asmListItemStatus'); $field->attr('id+name', 'asmListItemStatus');
$field->attr('class', 'asmListItemStatus'); $field->attr('class', 'asmListItemStatus');
$field->attr('data-tpl', "<span class='ui-priority-secondary'>" . str_replace('Fieldtype', '', $this->field->type) . "</span> %"); // % gets replaced with live percent $field->attr('data-tpl',
"<span class='ui-priority-secondary'>" .
str_replace('Fieldtype', '', $this->field->type) .
"</span> %"); // % gets replaced with live percent
$field->attr('value', ''); $field->attr('value', '');
$form->append($field); $form->append($field);
} }
$focus = $input->get('focus');
if($focus) {
$focus = $sanitizer->fieldName($focus);
if($focus === 'label') $focus = 'field_label';
$field = $focus ? $form->getChildByName($focus) : null;
if($field) {
$id = $field->id; //$field->name == $field->id ? "Inputfield_$field->name" : $field->id;
$form->appendMarkup .=
"<script>" .
"jQuery(document).ready(function() { " .
//"Inputfields.show($('#$id')); " .
"Inputfields.find('#$id'); " .
"});" .
"</script>";
}
}
return $form; return $form;
} }
@@ -1104,8 +1147,11 @@ class ProcessField extends Process implements ConfigurableModule {
*/ */
protected function ___buildEditFormContext($form) { protected function ___buildEditFormContext($form) {
/** @var Modules $modules */
$modules = $this->wire('modules');
$allChanges = array(); $allChanges = array();
$fieldgroups = $this->fieldgroup ? array($this->fieldgroup) : $this->wire('fieldgroups'); $fieldgroups = $this->fieldgroup ? array($this->fieldgroup) : $this->wire('fieldgroups');
$allowAddSettings = !$this->fieldgroup && !$this->contextNamespace; // whether settings can be added here
foreach($fieldgroups as $fieldgroup) { foreach($fieldgroups as $fieldgroup) {
/** @var Fieldgroup $fieldgroup */ /** @var Fieldgroup $fieldgroup */
@@ -1116,14 +1162,19 @@ class ProcessField extends Process implements ConfigurableModule {
$allChanges[$fieldgroup->name] = $this->getContextChanges($form, $field, $fieldgroup); $allChanges[$fieldgroup->name] = $this->getContextChanges($form, $field, $fieldgroup);
} }
if(!count($allChanges) && !$this->wire('config')->advanced) return; // exit now if there are no context change and none are allowed to be added
if(!count($allChanges) && !$allowAddSettings) return;
/** @var InputfieldWrapper $tab */
$tab = $this->wire(new InputfieldWrapper()); $tab = $this->wire(new InputfieldWrapper());
$tab->attr('title', $this->_('Overrides')); $tab->attr('title', $this->_('Overrides'));
$tab->attr('id', 'tab-overrides');
$tab->attr('class', 'WireTab'); $tab->attr('class', 'WireTab');
$form->add($tab); $form->add($tab);
$f = $this->wire('modules')->get('InputfieldMarkup'); /** @var InputfieldMarkup $f */
$f = $modules->get('InputfieldMarkup');
$f->attr('name', 'overrides_table');
$f->description = $this->_('The following settings are overridden for this field by the indicated template(s). Check the box to the right of any row to remove the setting override (restoring the original value).'); $f->description = $this->_('The following settings are overridden for this field by the indicated template(s). Check the box to the right of any row to remove the setting override (restoring the original value).');
$f->icon = 'exchange'; $f->icon = 'exchange';
if($this->fieldgroup) { if($this->fieldgroup) {
@@ -1134,65 +1185,126 @@ class ProcessField extends Process implements ConfigurableModule {
} }
} else { } else {
$f->label = $this->_('Setting overrides by template'); $f->label = $this->_('Setting overrides by template');
$f->notes = $this->_('To edit an override setting or override other settings, edit any template and click the field name in the fields list.'); $f->notes = $this->_('To edit an override setting or override other settings, edit any template and click the field name in the fields list.') . ' ';
if(count($allChanges)) $f->notes .= $this->_('You may also click links above to edit in context, but note that any changes you make here will NOT be reflected in the table above until you save or reload this page.') . ' ';
$f->notes .= $this->_('To adjust what settings are allowed for overrides, see the field below.');
} }
$tab->add($f); $tab->add($f);
if(count($allChanges)) { if(count($allChanges)) {
/** @var MarkupAdminDataTable $table */ $table = $this->buildEditFormContextTable($allChanges);
$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(); $f->value = $table->render();
} else { } else {
$f->value = '<p>' . $this->_('There are currently no settings being overridden by template.') . '</p>'; $f->value = '<p>' . $this->_('There are currently no settings being overridden by template.') . '</p>';
$f->collapsed = Inputfield::collapsedYes; $f->collapsed = Inputfield::collapsedYes;
} }
// allow the following configuration only for advanced mode if($allowAddSettings) $this->buildEditFormAllowedContexts($form, $tab);
if(!$this->wire('config')->advanced) return; }
/**
* Build the overrides list table
*
* @param array $allChanges
* @return MarkupAdminDataTable
*
*/
protected function buildEditFormContextTable(array $allChanges) {
/** @var Sanitizer $sanitizer */
$sanitizer = $this->wire('sanitizer');
/** @var Modules $modules */
$modules = $this->wire('modules');
/** @var InputfieldCheckbox $checkbox */
$checkbox = $modules->get('InputfieldCheckbox');
$checkbox->attr('name', '_remove_context[]');
$checkbox->attr('id', '_remove_context');
$checkbox->checkboxOnly = true;
/** @var MarkupAdminDataTable $table */
$table = $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('Changes', 'context-thead');
$header[] = "<i class='fa fa-lg fa-trash override-select-all'></i>";
$table->headerRow($header);
/** @var JqueryUI $jQueryUI */
$jQueryUI = $modules->get('JqueryUI');
$jQueryUI->use('modal');
$textTools = $sanitizer->getTextTools();
$allowModalEdit = !$this->fieldgroup && !$this->contextNamespace && !$this->input->get('modal');
foreach($allChanges as $fieldgroupName => $changes) {
$fieldgroup = $this->wire('fieldgroups')->get($fieldgroupName);
foreach($changes as $key => $change) {
$ns = empty($change['ns']) ? '' : substr($change['ns'], 3);
if($allowModalEdit) {
$url = "./edit?id={$this->field->id}&fieldgroup_id=$fieldgroup->id&focus=$change[name]";
if($ns) $url .= "&context_namespace=$ns";
$fieldgroupLabel = "<a class='pw-modal' data-buttons='#Inputfield_submit_save_field' data-autoclose='1' href='$url'>$fieldgroupName</a>";
} else {
$fieldgroupLabel = $fieldgroupName;
}
$row = array();
$settingLabel = $change['label'];
$newValue = $change['value'];
$originalValue = $change['originalValue'];
if($ns) {
// use of $change[ns] rather than $ns is intentional so that $key is NS_foo.bar
if(strpos($key, $change['ns']) !== 0) $key = $change['ns'] . '.' . $key;
$fieldgroupLabel .= " <span class='detail'>($ns)</span>";
}
$checkbox->attr('value', "$fieldgroup->id:$key");
if(!$this->fieldgroup) $row[] = $fieldgroupLabel;
$row[] = $sanitizer->entities($settingLabel);
$row[] = "<span class='pw-diff'>" . $textTools->diffMarkup($originalValue, $newValue, array('split' => '[^\d\w]+')) . "</span>";
$row[] = $checkbox->render();
$options = $fieldgroupLabel ? array('separator' => true) : array();
$table->row($row, $options);
}
}
return $table;
}
/**
* Build the "allow contexts" Inputfield
*
* @param InputfieldForm $form
* @param InputfieldWrapper $tab
*
*/
protected function buildEditFormAllowedContexts(InputfieldForm $form, InputfieldWrapper $tab) {
$labels = $this->labels; $labels = $this->labels;
/** @var InputfieldCheckboxes $field */ /** @var InputfieldCheckboxes $field */
$field = $this->modules->get('InputfieldCheckboxes'); $field = $this->modules->get('InputfieldCheckboxes');
$field->attr('name', 'allowContexts'); $field->attr('name', 'allowContexts');
$field->label = $this->_('Allowed overrides'); $field->label = $this->_('Settings allowed to override by template');
$field->icon = 'sliders'; $field->icon = 'sliders';
$field->description = $field->description =
$this->_('Checked settings will appear as configuration options when editing this field within the context of a particular template.') . ' ' . $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.'); $this->_('**WARNING:** enabling settings beyond those specified by the Fieldtype/Inputfield module may not always work, or may cause problems.') . ' ' .
$this->_('As a result, we recommend testing any modifications to these settings in a non-production (development) environment first.');
$field->notes =
$this->_('Please Note:') . ' ' .
$this->_('Settings in **bold** are those that the Fieldtype/Inputfield module has designated as always allowed for override.') . ' ' .
$this->_('Other settings may or may not work for context overrides.') . ' ' .
$this->_('You should un-check any settings you find do not work, or otherwise cause problems.');
$field->table = true; $field->table = true;
$field->thead = "$labels[label]|$labels[name]|$labels[type]"; $field->thead = "$labels[label]|$labels[name]|$labels[type]";
@@ -1200,6 +1312,7 @@ class ProcessField extends Process implements ConfigurableModule {
'fieldtypeConfig' => $this->_('Details:'), 'fieldtypeConfig' => $this->_('Details:'),
'inputfieldConfig' => $this->_('Input:') 'inputfieldConfig' => $this->_('Input:')
); );
$exclusions = array( $exclusions = array(
'collapsed', 'collapsed',
'showIf', 'showIf',
@@ -1230,10 +1343,12 @@ class ProcessField extends Process implements ConfigurableModule {
if(in_array($name, $exclusions) || strpos($name, 'theme') === 0) continue; if(in_array($name, $exclusions) || strpos($name, 'theme') === 0) continue;
if($f instanceof InputfieldWrapper || $f instanceof InputfieldMarkup || $f instanceof InputfieldHidden) continue; if($f instanceof InputfieldWrapper || $f instanceof InputfieldMarkup || $f instanceof InputfieldHidden) continue;
$typeName = str_replace('Inputfield', '', $f->className()); $typeName = str_replace('Inputfield', '', $f->className());
$label = str_replace('|', ' ', "$tabLabel $f->label") . $settingLabel = str_replace('|', ' ', "$tabLabel $f->label");
$label = $settingLabel .
"| [span.detail] $name [/span] " . "| [span.detail] $name [/span] " .
"| [span.detail] $typeName [/span]"; "| [span.detail] $typeName [/span]";
if(in_array($name, $alwaysSelected)) { if(in_array($name, $alwaysSelected)) {
$label = str_replace($settingLabel, "[strong]" . $settingLabel . "[/strong]", $label);
$field->addOption($name, $label, array('checked' => 'checked', 'disabled' => 'disabled')); $field->addOption($name, $label, array('checked' => 'checked', 'disabled' => 'disabled'));
$allowContexts[] = $name; $allowContexts[] = $name;
} else { } else {
@@ -1247,33 +1362,6 @@ class ProcessField extends Process implements ConfigurableModule {
if($qty) $tab->append($field); if($qty) $tab->append($field);
} }
/*
protected function ___buildEditFormContextFieldgroup($form) {
if(!$this->fieldgroup) return;
$changes = $this->getContextChanges($form, $this->field, $this->fieldgroup);
$tab = new InputfieldWrapper();
$tab->attr('title', $this->_('Overrides'));
$tab->attr('class', 'WireTab');
$form->add($tab);
$f = $this->wire('modules')->get('InputfieldCheckboxes');
$f->label = $this->_('Remove context overrides');
$f->table = true;
$f->thead =
$this->_x('Remove setting', 'context-thead') . '|' .
$this->_x('Original', 'context-thead') . '|' .
$this->_x('Override', 'context-thead');
$f->description = sprintf($this->_('The following settings are overriding the original field settings when this field is used in the context of the "%s" template.'), $this->fieldgroup->name); // Context description
$f->description .= ' ' . $this->_('To remove any of the overridden values (and restore the original field value) check the box next to each setting you want to remove/restore.'); // Context description 2
$tab->add($f);
foreach($changes as $key => $change) {
$f->addOption($key, "$change[label]|$change[originalValue]|$change[value]");
}
}
*/
/** /**
* Add Fieldtype and Inputfield custom fields to the form * Add Fieldtype and Inputfield custom fields to the form
* *
@@ -1737,9 +1825,13 @@ class ProcessField extends Process implements ConfigurableModule {
*/ */
public function ___executeSave() { public function ___executeSave() {
$this->buildEditForm(); $form = $this->buildEditForm();
if(!$this->input->post->submit_save_field) { if($this->input->get('reloadInputfieldAjax') === 'Inputfield_overrides_table') {
return $form->render();
}
if(!$this->input->post('submit_save_field')) {
$this->session->redirect("./"); $this->session->redirect("./");
} }
@@ -1750,7 +1842,7 @@ class ProcessField extends Process implements ConfigurableModule {
$isNew = !$this->field->id; $isNew = !$this->field->id;
if($this->input->post->delete && $this->input->post->delete == $this->field->id && $this->field->numFieldgroups() == 0) { if($this->input->post('delete') && $this->input->post('delete') == $this->field->id && $this->field->numFieldgroups() == 0) {
$this->session->CSRF->validate(); $this->session->CSRF->validate();
$this->session->message($this->_('Deleted field') . " - {$this->field->name}"); // Message after deleting a field, followed by field name $this->session->message($this->_('Deleted field') . " - {$this->field->name}"); // Message after deleting a field, followed by field name
$this->fields->delete($this->field); $this->fields->delete($this->field);
@@ -2007,6 +2099,7 @@ class ProcessField extends Process implements ConfigurableModule {
*/ */
protected function saveInputfields(InputfieldWrapper $wrapper) { protected function saveInputfields(InputfieldWrapper $wrapper) {
/** @var Languages $languages */
$languages = $this->wire('languages'); $languages = $this->wire('languages');
foreach($wrapper->children() as $inputfield) { foreach($wrapper->children() as $inputfield) {
@@ -2023,16 +2116,16 @@ class ProcessField extends Process implements ConfigurableModule {
// see /core/Fieldtype.php for the inputfields that initiate the autojoin and global flags // see /core/Fieldtype.php for the inputfields that initiate the autojoin and global flags
if($name == 'autojoin') { if($name == 'autojoin') {
if(!$this->input->post->autojoin) $this->field->flags = $this->field->flags & ~Field::flagAutojoin; if(!$this->input->post('autojoin')) $this->field->flags = $this->field->flags & ~Field::flagAutojoin;
else $this->field->flags = $this->field->flags | Field::flagAutojoin; else $this->field->flags = $this->field->flags | Field::flagAutojoin;
continue; continue;
} else if($name == 'global') { } else if($name == 'global') {
if(!$this->input->post->global) $this->field->flags = $this->field->flags & ~Field::flagGlobal; if(!$this->input->post('global')) $this->field->flags = $this->field->flags & ~Field::flagGlobal;
else $this->field->flags = $this->field->flags | Field::flagGlobal; else $this->field->flags = $this->field->flags | Field::flagGlobal;
continue; continue;
} else if($name == 'system' && $this->config->advanced) { } else if($name == 'system' && $this->config->advanced) {
if(!$this->input->post->system) { if(!$this->input->post('system')) {
$this->field->flags = $this->field->flags | Field::flagSystemOverride; $this->field->flags = $this->field->flags | Field::flagSystemOverride;
$this->field->flags = $this->field->flags & ~Field::flagSystem; $this->field->flags = $this->field->flags & ~Field::flagSystem;
} else { } else {
@@ -2040,7 +2133,7 @@ class ProcessField extends Process implements ConfigurableModule {
} }
continue; continue;
} else if($name == 'permanent' && $this->config->advanced) { } else if($name == 'permanent' && $this->config->advanced) {
if(!$this->input->post->permanent) $this->field->flags = $this->field->flags & ~Field::flagPermanent; if(!$this->input->post('permanent')) $this->field->flags = $this->field->flags & ~Field::flagPermanent;
else $this->field->flags = $this->field->flags | Field::flagPermanent; else $this->field->flags = $this->field->flags | Field::flagPermanent;
continue; continue;
} }
@@ -2052,7 +2145,7 @@ class ProcessField extends Process implements ConfigurableModule {
if($name == 'field_label') $name = 'label'; if($name == 'field_label') $name = 'label';
if($name == 'id' && $this->field->id) continue; if($name == 'id' && $this->field->id) continue;
if($name == 'send_templates') continue; if($name == 'send_templates') continue;
if($this->field->send_templates) unset($this->field->send_templates); // value was previously getting stored if($this->field->get('send_templates')) $this->field->__unset('send_templates'); // value was previously getting stored
if($name == 'useRoles') $value = (bool) ((int) $value); if($name == 'useRoles') $value = (bool) ((int) $value);
// if adding new field or existing name has changed, check that its an allowed name // if adding new field or existing name has changed, check that its an allowed name
@@ -2131,10 +2224,84 @@ class ProcessField extends Process implements ConfigurableModule {
* *
*/ */
protected function saveRemoveOverrides() { protected function saveRemoveOverrides() {
$removeContext = $this->wire('input')->post('_remove_context'); $removeContext = $this->wire('input')->post('_remove_context');
if(empty($removeContext)) return; if(empty($removeContext)) return;
$contextArrays = array(); $contextArrays = array();
$fieldgroups = array(); $fieldgroups = array();
foreach($removeContext as $value) {
// FYI: "<input type='checkbox' name='_remove_context[]' value='$fieldgroup->id:$key' />"
$ns = '';
list($fieldgroupID, $property) = explode(':', $value);
$fieldgroupID = (int) $fieldgroupID;
// check for namespace (when there is no $this->contextNamespace)
if(strpos($property, 'NS_') === 0 && strpos($property, '.')) {
list($ns, $property) = explode('.', $property, 2);
if(strpos($property, '.') !== false) list($property,) = explode('.', $property, 2);
}
if(isset($fieldgroups[$fieldgroupID])) {
$fieldgroup = $fieldgroups[$fieldgroupID];
} else {
$fieldgroup = $this->wire('fieldgroups')->get((int) $fieldgroupID);
if(!$fieldgroup) continue;
$fieldgroups[$fieldgroup->id] = $fieldgroup;
}
if(isset($contextArrays[$fieldgroup->id])) {
// use previously loaded version
$contextArray = $contextArrays[$fieldgroup->id];
} else {
$contextArray = $fieldgroup->getFieldContextArray($this->field->id);
}
if($ns && isset($contextArray[$ns])) {
// narrrow in on namespace portion
$context = &$contextArray[$ns];
} else {
$context = &$contextArray;
}
if(strpos($property, 'flagsAdd-') === 0 || strpos($property, 'flagsDel-') === 0) {
// special handling of flags bitmask removals
list($flagType, $flag) = explode('-', $property);
$flag = (int) $flag;
if(isset($context[$flagType])) $context[$flagType] = $context[$flagType] & ~$flag;
} else {
// remove property
unset($context[$property]);
}
$this->message($this->_('Removed context override') . " (template=$fieldgroup->name, property=$property)");
// cache for if this comes up in another iteration
$contextArrays[$fieldgroup->id] = $contextArray;
}
foreach($contextArrays as $fieldgroupID => $contextArray) {
$fieldgroup = $fieldgroups[$fieldgroupID];
//$fieldgroup->setFieldContextArray($this->field->id, $contextArray, $this->contextNamespace);
$fieldgroup->setFieldContextArray($this->field->id, $contextArray);
$fieldgroup->saveContext();
}
}
/**
* Saves the submitted checkboxes from the "Overrides" tab
*
*/
protected function xsaveRemoveOverrides() {
$removeContext = $this->wire('input')->post('_remove_context');
if(empty($removeContext)) return;
$contextArrays = array();
$fieldgroups = array();
foreach($removeContext as $value) { foreach($removeContext as $value) {
// FYI: "<input type='checkbox' name='_remove_context[]' value='$fieldgroup->id:$key' />" // FYI: "<input type='checkbox' name='_remove_context[]' value='$fieldgroup->id:$key' />"
list($fieldgroupID, $property) = explode(':', $value); list($fieldgroupID, $property) = explode(':', $value);
@@ -2145,24 +2312,33 @@ class ProcessField extends Process implements ConfigurableModule {
if(!$fieldgroup) continue; if(!$fieldgroup) continue;
$fieldgroups[$fieldgroup->id] = $fieldgroup; $fieldgroups[$fieldgroup->id] = $fieldgroup;
} }
if(isset($contextArrays[$fieldgroup->id])) { if(isset($contextArrays[$fieldgroup->id])) {
// use previously loaded version
$contextArray = $contextArrays[$fieldgroup->id]; $contextArray = $contextArrays[$fieldgroup->id];
} else { } else {
$contextArray = $fieldgroup->getFieldContextArray($this->field->id); $contextArray = $fieldgroup->getFieldContextArray($this->field->id);
} }
if(strpos($property, 'flagsAdd-') === 0 || strpos($property, 'flagsDel-') === 0) { if(strpos($property, 'flagsAdd-') === 0 || strpos($property, 'flagsDel-') === 0) {
// special handling of flags bitmask removals
list($flagType, $flag) = explode('-', $property); list($flagType, $flag) = explode('-', $property);
$flag = (int) $flag; $flag = (int) $flag;
if(isset($contextArray[$flagType])) $contextArray[$flagType] = $contextArray[$flagType] & ~$flag; if(isset($contextArray[$flagType])) $contextArray[$flagType] = $contextArray[$flagType] & ~$flag;
} else { } else {
unset($contextArray[$property]); unset($contextArray[$property]);
} }
$this->message($this->_('Removed context override') . " (template=$fieldgroup->name, property=$property)"); $this->message($this->_('Removed context override') . " (template=$fieldgroup->name, property=$property)");
// cache for if this comes up in another iteration
$contextArrays[$fieldgroup->id] = $contextArray; $contextArrays[$fieldgroup->id] = $contextArray;
} }
foreach($contextArrays as $fieldgroupID => $contextArray) { foreach($contextArrays as $fieldgroupID => $contextArray) {
$fieldgroup = $fieldgroups[$fieldgroupID]; $fieldgroup = $fieldgroups[$fieldgroupID];
//$fieldgroup->setFieldContextArray($this->field->id, $contextArray, $this->contextNamespace);
$fieldgroup->setFieldContextArray($this->field->id, $contextArray); $fieldgroup->setFieldContextArray($this->field->id, $contextArray);
$fieldgroup->saveContext(); $fieldgroup->saveContext();
} }
} }
@@ -2183,8 +2359,8 @@ class ProcessField extends Process implements ConfigurableModule {
->add(new Breadcrumb('./', $this->labels['fields'])) ->add(new Breadcrumb('./', $this->labels['fields']))
->add(new Breadcrumb("./edit?id={$this->field->id}", $this->field->name)); ->add(new Breadcrumb("./edit?id={$this->field->id}", $this->field->name));
if(!$this->input->get->type) $this->session->redirect('./'); if(!$this->input->get('type')) $this->session->redirect('./');
$newType = $this->wire('sanitizer')->name($this->input->get->type); $newType = $this->wire('sanitizer')->name($this->input->get('type'));
$newType = $this->wire('fieldtypes')->get($newType); $newType = $this->wire('fieldtypes')->get($newType);
if(!$newType) $this->session->redirect('./'); if(!$newType) $this->session->redirect('./');
@@ -2232,12 +2408,12 @@ class ProcessField extends Process implements ConfigurableModule {
public function ___executeSaveChangeType() { public function ___executeSaveChangeType() {
$this->buildEditForm(); $this->buildEditForm();
if(!$this->field || !$this->input->post->confirm_type) { if(!$this->field || !$this->input->post('confirm_type')) {
$this->message($this->_("Field type change aborted")); $this->message($this->_("Field type change aborted"));
$this->session->redirect('./'); $this->session->redirect('./');
} }
$type = $this->wire('sanitizer')->name($this->input->post->confirm_type); $type = $this->wire('sanitizer')->name($this->input->post('confirm_type'));
if($type = $this->fieldtypes->get($type)) { if($type = $this->fieldtypes->get($type)) {
$this->session->CSRF->validate(); $this->session->CSRF->validate();
$this->message($this->_("Field type changed")); $this->message($this->_("Field type changed"));
@@ -2511,6 +2687,7 @@ class ProcessField extends Process implements ConfigurableModule {
$fieldOriginal = $this->wire('fields')->get($field->id); $fieldOriginal = $this->wire('fields')->get($field->id);
$changes = array(); $changes = array();
$isInContext = $this->fieldgroup || $this->contextNamespace;
$labels = array( $labels = array(
'on' => $this->_('On'), 'on' => $this->_('On'),
@@ -2539,13 +2716,27 @@ class ProcessField extends Process implements ConfigurableModule {
Field::flagAccessEditor =>'flagsDelAccessEditor', Field::flagAccessEditor =>'flagsDelAccessEditor',
); );
// flatten namespaced to follow same formats others, but with key/name as NS_foo.bar
foreach($contextArray as $key => $value) { foreach($contextArray as $key => $value) {
if(strpos($key, 'NS_') === 0 && is_array($value)) {
foreach($value as $k => $v) {
$contextArray["$key.$k"] = $v;
unset($contextArray[$key]);
}
}
}
foreach($contextArray as $key => $value) {
$ns = '';
$name = $key; $name = $key;
$formFieldName = $key; if(strpos($key, '.')) list($ns, $name) = explode('.', $key, 2);
$formFieldName = $name;
if($formFieldName == 'label') $formFieldName = 'field_label'; if($formFieldName == 'label') $formFieldName = 'field_label';
$formField = $form->getChildByName($formFieldName); $formField = $form->getChildByName($formFieldName);
$originalValue = $fieldOriginal->$key; $originalValue = $fieldOriginal->$name;
if($formField) { if($formField) {
// if($isInContext) $formField->set('themeColor', 'primary');
if($formField instanceof InputfieldSelect) { if($formField instanceof InputfieldSelect) {
$options = $formField->getOptions(); $options = $formField->getOptions();
if(is_array($value)) foreach($value as $k => $v) { if(is_array($value)) foreach($value as $k => $v) {
@@ -2563,6 +2754,7 @@ class ProcessField extends Process implements ConfigurableModule {
$originalValue = $originalValue ? $labels['on'] : $labels['off']; $originalValue = $originalValue ? $labels['on'] : $labels['off'];
} }
} }
if(is_array($value) && ($key == 'viewRoles' || $key == 'editRoles')) { if(is_array($value) && ($key == 'viewRoles' || $key == 'editRoles')) {
foreach($value as $k => $v) { foreach($value as $k => $v) {
$v = $this->wire('roles')->get((int) $v); $v = $this->wire('roles')->get((int) $v);
@@ -2570,6 +2762,7 @@ class ProcessField extends Process implements ConfigurableModule {
if($v) $value[$k] = $roleName; if($v) $value[$k] = $roleName;
} }
} }
if(is_array($originalValue) && ($key == 'viewRoles' || $key == 'editRoles')) { if(is_array($originalValue) && ($key == 'viewRoles' || $key == 'editRoles')) {
foreach($originalValue as $k => $v) { foreach($originalValue as $k => $v) {
$v = $this->wire('roles')->get((int) $v); $v = $this->wire('roles')->get((int) $v);
@@ -2577,6 +2770,7 @@ class ProcessField extends Process implements ConfigurableModule {
if($v) $originalValue[$k] = $roleName; if($v) $originalValue[$k] = $roleName;
} }
} }
$valueStr = $value; $valueStr = $value;
$originalValueStr = $originalValue; $originalValueStr = $originalValue;
if(is_array($originalValueStr)) $originalValueStr = implode(', ', $originalValueStr); if(is_array($originalValueStr)) $originalValueStr = implode(', ', $originalValueStr);
@@ -2585,6 +2779,7 @@ class ProcessField extends Process implements ConfigurableModule {
$originalValueStr = ((int) $originalValue) ? $labels['on'] : $labels['off']; $originalValueStr = ((int) $originalValue) ? $labels['on'] : $labels['off'];
$valueStr = ((int) $value) ? $labels['on'] : $labels['off']; $valueStr = ((int) $value) ? $labels['on'] : $labels['off'];
} }
$originalValueStr = str_replace('|', ' ', $originalValueStr); $originalValueStr = str_replace('|', ' ', $originalValueStr);
$valueStr = str_replace('|', ' ', $valueStr); $valueStr = str_replace('|', ' ', $valueStr);
$change = array( $change = array(
@@ -2592,6 +2787,11 @@ class ProcessField extends Process implements ConfigurableModule {
"value" => $valueStr, "value" => $valueStr,
"originalValue" => $originalValueStr "originalValue" => $originalValueStr
); );
if($ns) {
$change['ns'] = $ns;
} else if($this->contextNamespace) {
$change['ns'] = 'NS_' . $this->contextNamespace;
}
if(isset($labels[$key])) { if(isset($labels[$key])) {
$label = $labels[$key]; $label = $labels[$key];
@@ -2621,6 +2821,7 @@ class ProcessField extends Process implements ConfigurableModule {
$change["label"] = $label; $change["label"] = $label;
$changes[$key] = $change; $changes[$key] = $change;
} }
return $changes; return $changes;
} }

View File

@@ -440,6 +440,7 @@ var Inputfields = {
$inputfield = this.inputfield($inputfield); $inputfield = this.inputfield($inputfield);
if(!$inputfield.length) return $inputfield; if(!$inputfield.length) return $inputfield;
if(typeof highlight == "undefined") highlight = true; if(typeof highlight == "undefined") highlight = true;
var Inputfields = this;
// locate th Inputfield // locate th Inputfield
if($inputfield.hasClass('InputfieldStateCollapsed') || !$inputfield.is(':visible')) { if($inputfield.hasClass('InputfieldStateCollapsed') || !$inputfield.is(':visible')) {
@@ -447,7 +448,7 @@ var Inputfields = {
// Inputfields.toggle() can call Inputfields.focus(), so prevent the focus by adding this class // Inputfields.toggle() can call Inputfields.focus(), so prevent the focus by adding this class
if(!hasNoFocus) $inputfield.addClass('InputfieldNoFocus'); if(!hasNoFocus) $inputfield.addClass('InputfieldNoFocus');
this.toggle($inputfield, true, 0, function($in, open, duration) { this.toggle($inputfield, true, 0, function($in, open, duration) {
this.find($inputfield, callback); Inputfields.find($inputfield, callback);
}); });
// remove the class we added // remove the class we added
if(!hasNoFocus) $inputfield.removeClass('InputfieldNoFocus'); if(!hasNoFocus) $inputfield.removeClass('InputfieldNoFocus');
@@ -455,12 +456,12 @@ var Inputfields = {
} }
var completed = function() { var completed = function() {
if(highlight) this.highlight($inputfield); if(highlight) Inputfields.highlight($inputfield);
if(typeof callback != "undefined") callback($inputfield); if(typeof callback != "undefined") callback($inputfield);
} }
setTimeout(function() { setTimeout(function() {
if(Inputfields.inView($inputfield)) { if(false && Inputfields.inView($inputfield)) {
completed(); completed();
} else { } else {
var properties = { var properties = {

File diff suppressed because one or more lines are too long