From a32c574106b8602e63ec0dc2f02d6918d8139581 Mon Sep 17 00:00:00 2001 From: Ryan Cramer Date: Tue, 3 May 2022 10:19:19 -0400 Subject: [PATCH] Updates to InputfieldPage behavior of selectors containing keyword 'page' like 'field=page.id', like when using dependent selects or referring to page being edited, by adding the alternative 'field=item.id' (using 'item' rather than 'page') to refer to the repeater item. In cases where the field appears outside of a repeater item then the keyword 'item' behaves the same as 'page'. --- .../InputfieldPage/InputfieldPage.js | 17 +++-- .../InputfieldPage/InputfieldPage.min.js | 2 +- .../InputfieldPage/InputfieldPage.module | 76 +++++++++++-------- 3 files changed, 59 insertions(+), 36 deletions(-) diff --git a/wire/modules/Inputfield/InputfieldPage/InputfieldPage.js b/wire/modules/Inputfield/InputfieldPage/InputfieldPage.js index 0ae3ac7d..23a11492 100644 --- a/wire/modules/Inputfield/InputfieldPage/InputfieldPage.js +++ b/wire/modules/Inputfield/InputfieldPage/InputfieldPage.js @@ -118,8 +118,13 @@ function initInputfieldPageDependentSelects($inputfieldPage) { function initSelector($t) { var selector = $t.val(); + var selectorHasPage = selector.indexOf('=page.') > -1; // 'page' refers to page being edited + var selectorHasItem = selector.indexOf('=item.') > -1; // 'item' refers to repeater item + // if there is no "=page." present in the selector, then this can't be a dependent select - if(selector.indexOf('=page.') == -1) return; + if(!selectorHasPage && !selectorHasItem) return; + + if(selectorHasItem) selector = selector.replaceAll('=item.', '=page.'); var labelFieldName = $t.attr('data-label'); var formatName = $t.attr('data-formatname'); @@ -140,13 +145,15 @@ function initInputfieldPageDependentSelects($inputfieldPage) { var name = part.replace('=page.', ''); var $select1 = $('#Inputfield_' + name); // see if available in page editor - if(!$select1.length && $repeaterItems.length) { - // if not available in page editor, and we are in a repeater, + if((!$select1.length || selectorHasItem) && $repeaterItems.length) { + // if not available in page editor, or we are in a repeater, // see if available in any of the repeaters we are nested within + var $selectInRepeater = ''; $repeaterItems.each(function() { - if($select1.length) return; - $select1 = $('#Inputfield_' + name + '_repeater' + $(this).attr('data-page')); + if($selectInRepeater.length) return; + $selectInRepeater = $('#Inputfield_' + name + '_repeater' + $(this).attr('data-page')); }); + if($selectInRepeater.length) $select1 = $selectInRepeater; } if($select1.length < 1) continue; diff --git a/wire/modules/Inputfield/InputfieldPage/InputfieldPage.min.js b/wire/modules/Inputfield/InputfieldPage/InputfieldPage.min.js index 27de5efe..47732735 100644 --- a/wire/modules/Inputfield/InputfieldPage/InputfieldPage.min.js +++ b/wire/modules/Inputfield/InputfieldPage/InputfieldPage.min.js @@ -1 +1 @@ -function initInputfieldPage($this){$this.find("p.InputfieldPageAddButton a").click(function(){var $input=$(this).parent("p").next(".InputfieldPageAddItems");if($input.is(":visible"))$input.slideUp("fast").find(":input").val("");else $input.slideDown("fast").parents(".ui-widget-content").slice(0,1).effect("highlight",{},500);return false});initInputfieldPageDependentSelects($this)}function initInputfieldPageDependentSelects($inputfieldPage){function selectChanged($select1,$select2,selector,formatName,labelFieldName,part,changed){var v=$select1.val();if(v==null){if($select2.children().length){$select2.children().remove();$select2.change()}return}v=v.toString();v=v.replace(/,/g,"|");selector=selector.replace(part,"="+v);selector=selector.replace(/,\s*/g,"&");if(selector.indexOf("_LPID"))selector=selector.replace(/_LPID[0-9]+/g,"");var url=ProcessWire.config.urls.admin+"page/search/for?"+selector+"&limit=9999&get="+labelFieldName;if(formatName.length)url+="&format_name="+formatName;$.getJSON(url,{},function(data){var numSelected=0;$select2.children().addClass("option-tbd");for(var n=0;n0)selected=$option.is(":selected")||$option.is(":checked");if(selected)numSelected++;$option.remove();if(formatName.length)label=page[formatName];if(!label.length)label=page[labelFieldName];if(!label.length)label=page.name;$option=$("");if(selected)$option.attr("selected","selected");$select2.append($option)}if(!$select2.attr("multiple")){$blankOption=$("");if(!numSelected)$blankOption.attr("selected","selected");$select2.prepend($blankOption)}$select2.children(".option-tbd").remove();if(changed||$select2.closest(".InputfieldAsmSelect").length){$select2.change()}})}function initSelector($t){var selector=$t.val();if(selector.indexOf("=page.")==-1)return;var labelFieldName=$t.attr("data-label");var formatName=$t.attr("data-formatname");var $repeaterItems=$t.parents(".InputfieldRepeaterItem");if(!labelFieldName.length)$labelFieldName="name";var $wrap=$t.parents(".InputfieldPage");var $select2=$("select#"+$wrap.attr("id").replace(/^wrap_/,""));if($select2.length<1)return;var parts=selector.match(/(=page.[_a-zA-Z0-9]+)/g);for(var n=0;n0)selected=$option.is(":selected")||$option.is(":checked");if(selected)numSelected++;$option.remove();if(formatName.length)label=page[formatName];if(!label.length)label=page[labelFieldName];if(!label.length)label=page.name;$option=$("");if(selected)$option.attr("selected","selected");$select2.append($option)}if(!$select2.attr("multiple")){$blankOption=$("");if(!numSelected)$blankOption.attr("selected","selected");$select2.prepend($blankOption)}$select2.children(".option-tbd").remove();if(changed||$select2.closest(".InputfieldAsmSelect").length){$select2.change()}})}function initSelector($t){var selector=$t.val();var selectorHasPage=selector.indexOf("=page.")>-1;var selectorHasItem=selector.indexOf("=item.")>-1;if(!selectorHasPage&&!selectorHasItem)return;if(selectorHasItem)selector=selector.replaceAll("=item.","=page.");var labelFieldName=$t.attr("data-label");var formatName=$t.attr("data-formatname");var $repeaterItems=$t.parents(".InputfieldRepeaterItem");if(!labelFieldName.length)$labelFieldName="name";var $wrap=$t.parents(".InputfieldPage");var $select2=$("select#"+$wrap.attr("id").replace(/^wrap_/,""));if($select2.length<1)return;var parts=selector.match(/(=page.[_a-zA-Z0-9]+)/g);for(var n=0;n 'Page', - 'version' => 107, + 'version' => 108, 'summary' => 'Select one or more pages', 'permanent' => true, ); @@ -365,7 +365,13 @@ class InputfieldPage extends Inputfield implements ConfigurableModule { } else if($findPagesSelector) { // a find() selector - $instance = $this->processInputMode || strpos($findPagesSelector, '=page.') ? $this : null; + if($this->processInputMode) { + $instance = $this; + } else if(strpos($findPagesSelector, '=page.') || strpos($findPagesSelector, '=item.')) { + $instance = $this; + } else { + $instance = null; + } $selector = self::populateFindPagesSelector($page, $findPagesSelector, $instance); $children = $pages->find($selector); @@ -422,40 +428,42 @@ class InputfieldPage extends Inputfield implements ConfigurableModule { */ protected static function populateFindPagesSelector(Page $page, $selector, $inputfield = null) { - // if an $inputfield is passed in, then we want to retrieve dependent values directly - // from the form, rather than from the $page - $repeaterWrappers = array(); // 0, 1, or 2+ if nested repeaters - /** @var InputfieldWrapper $form */ - if($inputfield) { - // locate the $form - $n = 0; - $form = $inputfield; - do { - if($form instanceof InputfieldWrapper && $form->hasClass('InputfieldRepeaterItem')) { - $repeaterWrappers[] = $form; - } - $f = $form->getParent(); - if($f) $form = $f; - if(++$n > 10) break; - } while($f && $f->className() != 'InputfieldForm'); - } else { - $form = null; - } - // find variables identified by: page.field or page.field.subfield - if(strpos($selector, '=page.') !== false) { - preg_match_all('/=page\.([_.a-zA-Z0-9]+)/', $selector, $matches); + if(strpos($selector, '=page.') !== false || strpos($selector, '=item.') !== false) { + + // if an $inputfield is passed in, then we want to retrieve dependent values directly + // from the form, rather than from the $page + $repeaterWrappers = array(); // 0, 1, or 2+ if nested repeaters + + /** @var InputfieldWrapper $form */ + if($inputfield) { + // locate the $form + $n = 0; + $form = $inputfield; + do { + if($form instanceof InputfieldWrapper && $form->hasClass('InputfieldRepeaterItem')) { + $repeaterWrappers[] = $form; + } + $f = $form->getParent(); + if($f) $form = $f; + if(++$n > 10) break; + } while($f && !wireInstanceOf($f, 'InputfieldForm')); + } else { + $form = null; + } + + preg_match_all('/=(page|item)\.([_.a-zA-Z0-9]+)/', $selector, $matches); + foreach($matches[0] as $key => $tag) { - $field = $matches[1][$key]; + $type = $matches[1][$key]; // page or item + $field = $matches[2][$key]; $subfield = ''; if(strpos($field, '.')) list($field, $subfield) = explode('.', $field); $value = null; if($form && (!$subfield || $subfield == 'id')) { // attempt to get value from the form, to account for ajax changes that would not yet be reflected on the page - $in = $form instanceof InputfieldWrapper ? $form->getChildByName($field) : null; - if($in) { - $value = $in->attr('value'); - } else if(count($repeaterWrappers)) { + $in = $form instanceof InputfieldWrapper ? $form->getChildByName($field) : null; + if($type === 'item' && count($repeaterWrappers)) { // fields in repeaters use a namespaced name attribute so match by hasField instead foreach($repeaterWrappers as $repeaterWrapper) { /** @var InputfieldWrapper $repeaterWrapper */ @@ -467,9 +475,17 @@ class InputfieldPage extends Inputfield implements ConfigurableModule { } if($value !== null) break; } + } else if($in) { + $value = $in->attr('value'); + } + } + if(is_null($value)) { + if($type === 'page' && $page instanceof RepeaterPage) { + $value = $page->getForPageRoot()->get($field); + } else { + $value = $page->get($field); } } - if(is_null($value)) $value = $page->get($field); if(is_object($value) && $subfield) $value = $value->$subfield; if(is_array($value)) $value = implode('|', $value); if(!strlen("$value") && (!$subfield || $subfield == 'id')) $value = '-1'; // force fail