mirror of
https://github.com/processwire/processwire.git
synced 2025-08-11 17:24:46 +02:00
Fix issue processwire/processwire-issues#214 and refactoring of dependent selects code in InputfieldPage.js
This commit is contained in:
@@ -1,3 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Initialize InputfieldPage element
|
||||||
|
*
|
||||||
|
* @param $this
|
||||||
|
*
|
||||||
|
*/
|
||||||
function initInputfieldPage($this) {
|
function initInputfieldPage($this) {
|
||||||
|
|
||||||
$this.find("p.InputfieldPageAddButton a").click(function() {
|
$this.find("p.InputfieldPageAddButton a").click(function() {
|
||||||
@@ -7,80 +13,162 @@ function initInputfieldPage($this) {
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
// support for dependent selects
|
initInputfieldPageDependentSelects($this);
|
||||||
$this.find(".findPagesSelector").each(function() {
|
}
|
||||||
|
|
||||||
var $t = $(this);
|
/**
|
||||||
|
* Initialize dependent selects in an .InputfieldPage
|
||||||
|
*
|
||||||
|
* @param $inputfieldPage
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function initInputfieldPageDependentSelects($inputfieldPage) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to be called when a change is made to $select1
|
||||||
|
*
|
||||||
|
* @param $select1 Primary select
|
||||||
|
* @param $select2 Dependent select
|
||||||
|
* @param selector Selector string to find items
|
||||||
|
* @param formatName Name of format sent directly from InputfieldPage to ProcessPageSearch (server side)
|
||||||
|
* @param labelFieldName Name of field to use for labels
|
||||||
|
* @param part Page matching part of selector
|
||||||
|
* @param changed Is this due to a change in $select1? true or false
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function selectChanged($select1, $select2, selector, formatName, labelFieldName, part, changed) {
|
||||||
|
|
||||||
|
var v = $select1.val();
|
||||||
|
|
||||||
|
if(v == null) {
|
||||||
|
// no values selected
|
||||||
|
if($select2.children().length) {
|
||||||
|
$select2.children().remove();
|
||||||
|
$select2.change();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = v.toString();
|
||||||
|
v = v.replace(/,/g, '|'); // if multi-value field, convert commas to pipes
|
||||||
|
|
||||||
|
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'); // mark existing options as to-be-deleted
|
||||||
|
|
||||||
|
for(var n = 0; n < data.matches.length; n++) {
|
||||||
|
|
||||||
|
var selected = false;
|
||||||
|
var page = data.matches[n];
|
||||||
|
var label = '';
|
||||||
|
|
||||||
|
// first see if we can find the existing option already present
|
||||||
|
var $option = $select2.children("[value=" + page.id + "]");
|
||||||
|
|
||||||
|
if($option.length > 0) selected = $option.is(':selected') || $option.is(':checked');
|
||||||
|
if(selected) numSelected++;
|
||||||
|
|
||||||
|
$option.remove();
|
||||||
|
|
||||||
|
// determine label
|
||||||
|
if(formatName.length) label = page[formatName];
|
||||||
|
if(!label.length) label = page[labelFieldName];
|
||||||
|
if(!label.length) label = page.name;
|
||||||
|
|
||||||
|
// create <option>
|
||||||
|
$option = $("<option value='" + page.id + "'>" + label + "</option>");
|
||||||
|
if(selected) $option.attr('selected', 'selected');
|
||||||
|
|
||||||
|
// add the <option> to the <select>
|
||||||
|
$select2.append($option);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lead with a blank option
|
||||||
|
if(!$select2.attr('multiple')) {
|
||||||
|
$blankOption = $("<option value=''> </option>");
|
||||||
|
if(!numSelected) $blankOption.attr('selected', 'selected');
|
||||||
|
$select2.prepend($blankOption);
|
||||||
|
}
|
||||||
|
$select2.children(".option-tbd").remove();
|
||||||
|
if(changed || $select2.closest('.InputfieldAsmSelect').length) {
|
||||||
|
// always trigger change event when asmSelect because that’s what forces it to redraw
|
||||||
|
$select2.change();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize an InputfieldPage dependent select from its input.findPagesSelector element
|
||||||
|
*
|
||||||
|
* The $t argument is one of these:
|
||||||
|
* <input type='hidden' class='findPagesSelector' data-formatname='' data-label='title' value='parent=page.field'>
|
||||||
|
*
|
||||||
|
* @param $t
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function initSelector($t) {
|
||||||
var selector = $t.val();
|
var selector = $t.val();
|
||||||
|
|
||||||
// if there is no "=page." present in the selector, then this can't be a dependent select
|
// if there is no "=page." present in the selector, then this can't be a dependent select
|
||||||
if(selector.indexOf('=page.') == -1) return;
|
if(selector.indexOf('=page.') == -1) return;
|
||||||
|
|
||||||
var labelFieldName = $t.attr('data-label');
|
var labelFieldName = $t.attr('data-label');
|
||||||
var formatName = $t.attr('data-formatname');
|
var formatName = $t.attr('data-formatname');
|
||||||
|
|
||||||
if(!labelFieldName.length) $labelFieldName = 'name';
|
if(!labelFieldName.length) $labelFieldName = 'name';
|
||||||
// if it doesn't contain a dynamic request from the page, then stop now
|
|
||||||
|
|
||||||
var $wrap = $t.parents(".InputfieldPage");
|
var $wrap = $t.parents(".InputfieldPage");
|
||||||
var $select = $('select#' + $wrap.attr('id').replace(/^wrap_/, ''));
|
var $select2 = $('select#' + $wrap.attr('id').replace(/^wrap_/, '')); // dependent select
|
||||||
|
|
||||||
if($select.length < 1) return;
|
if($select2.length < 1) return;
|
||||||
|
|
||||||
var parts = selector.match(/(=page.[_a-zA-Z0-9]+)/g);
|
var parts = selector.match(/(=page.[_a-zA-Z0-9]+)/g);
|
||||||
|
|
||||||
for(var n = 0; n < parts.length; n++) {
|
for(var n = 0; n < parts.length; n++) {
|
||||||
|
|
||||||
var part = parts[n];
|
var part = parts[n]; // page matching part of the selector
|
||||||
var name = part.replace('=page.', '');
|
var name = part.replace('=page.', '');
|
||||||
var $inputfield = $('#Inputfield_' + name);
|
var $select1 = $('#Inputfield_' + name);
|
||||||
if($inputfield.length < 1) return;
|
|
||||||
|
if($select1.length < 1) continue;
|
||||||
|
|
||||||
// monitor changes to the dependency field
|
// monitor changes to the dependency field
|
||||||
$inputfield.change(function() {
|
$select1.change(function() {
|
||||||
var s = selector;
|
selectChanged($select1, $select2, selector, formatName, labelFieldName, part, true)
|
||||||
var v = $inputfield.val();
|
|
||||||
if(v == null) {
|
|
||||||
// no values selected
|
|
||||||
$select.children().remove();
|
|
||||||
$select.change();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
v = v.toString();
|
|
||||||
v = v.replace(/,/g, '|'); // if multi-value field, convert commas to pipes
|
|
||||||
s = s.replace(part, '=' + v);
|
|
||||||
s = s.replace(/,\s*/g, '&');
|
|
||||||
if(s.indexOf('_LPID')) s = s.replace(/_LPID[0-9]+/g, '');
|
|
||||||
var url = ProcessWire.config.urls.admin + 'page/search/for?' + s + '&limit=9999&get=' + labelFieldName;
|
|
||||||
if(formatName.length) url += '&format_name=' + formatName;
|
|
||||||
$.getJSON(url, {}, function(data) {
|
|
||||||
//$select.children().remove();
|
|
||||||
$select.children().addClass('option-tbd'); // mark existing options as to-be-deleted
|
|
||||||
for(n = 0; n < data.matches.length; n++) {
|
|
||||||
var page = data.matches[n];
|
|
||||||
// first see if we can find the existing option already present
|
|
||||||
var $option = $select.children("[value=" + page.id + "]");
|
|
||||||
// if that option isn't already there, then make a new one
|
|
||||||
var selected = false;
|
|
||||||
if($option.size() > 0) selected = $option.is(":checked");
|
|
||||||
$option.remove();
|
|
||||||
var label = '';
|
|
||||||
if(formatName.length) label = page[formatName];
|
|
||||||
if(!label.length) label = page[labelFieldName];
|
|
||||||
if(!label.length) label = page.name;
|
|
||||||
var $option = $("<option value='" + page.id + "'>" + label + "</option>");
|
|
||||||
if(selected) $option.attr('selected', 'selected');
|
|
||||||
// add the <option> to the <select>
|
|
||||||
$select.append($option);
|
|
||||||
}
|
|
||||||
$blankOption = $("<option value=''></option>");
|
|
||||||
$select.prepend($blankOption);
|
|
||||||
$select.children(".option-tbd").remove();
|
|
||||||
$select.change();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// determine if select2 needs to be populated
|
||||||
|
if($select1.val() && !$select2.val() && $select2.children('option[value!=""]').length < 1) {
|
||||||
|
// no options in $select2 select but primary $select1 has something selected…
|
||||||
|
// it’s possible there are just no selectable options, but it’s also possible that
|
||||||
|
// this is a new page or the selects are newly added, so let’s find out…
|
||||||
|
setTimeout(function() {
|
||||||
|
selectChanged($select1, $select2, selector, formatName, labelFieldName, part, false)
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// find all dependent selects and initalize them
|
||||||
|
$inputfieldPage.find('.findPagesSelector').each(function() {
|
||||||
|
initSelector($(this));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Document ready
|
||||||
|
*
|
||||||
|
*/
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$(".InputfieldPage").each(function() {
|
$(".InputfieldPage").each(function() {
|
||||||
initInputfieldPage($(this));
|
initInputfieldPage($(this));
|
||||||
|
@@ -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});$this.find(".findPagesSelector").each(function(){var $t=$(this);var selector=$t.val();if(selector.indexOf("=page.")==-1)return;var labelFieldName=$t.attr("data-label");var formatName=$t.attr("data-formatname");if(!labelFieldName.length)$labelFieldName="name";var $wrap=$t.parents(".InputfieldPage");var $select=$("select#"+$wrap.attr("id").replace(/^wrap_/,""));if($select.length<1)return;var parts=selector.match(/(=page.[_a-zA-Z0-9]+)/g);for(var n=0;n<parts.length;n++){var part=parts[n];var name=part.replace("=page.","");var $inputfield=$("#Inputfield_"+name);if($inputfield.length<1)return;$inputfield.change(function(){var s=selector;var v=$inputfield.val();if(v==null){$select.children().remove();$select.change();return}v=v.toString();v=v.replace(/,/g,"|");s=s.replace(part,"="+v);s=s.replace(/,\s*/g,"&");if(s.indexOf("_LPID"))s=s.replace(/_LPID[0-9]+/g,"");var url=ProcessWire.config.urls.admin+"page/search/for?"+s+"&limit=9999&get="+labelFieldName;if(formatName.length)url+="&format_name="+formatName;$.getJSON(url,{},function(data){$select.children().addClass("option-tbd");for(n=0;n<data.matches.length;n++){var page=data.matches[n];var $option=$select.children("[value="+page.id+"]");var selected=false;if($option.size()>0)selected=$option.is(":checked");$option.remove();var label="";if(formatName.length)label=page[formatName];if(!label.length)label=page[labelFieldName];if(!label.length)label=page.name;var $option=$("<option value='"+page.id+"'>"+label+"</option>");if(selected)$option.attr("selected","selected");$select.append($option)}$blankOption=$("<option value=''></option>");$select.prepend($blankOption);$select.children(".option-tbd").remove();$select.change()})})}})}$(document).ready(function(){$(".InputfieldPage").each(function(){initInputfieldPage($(this))});$(document).on("reloaded",".InputfieldPage",function(){initInputfieldPage($(this))})});
|
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;n<data.matches.length;n++){var selected=false;var page=data.matches[n];var label="";var $option=$select2.children("[value="+page.id+"]");if($option.length>0)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=$("<option value='"+page.id+"'>"+label+"</option>");if(selected)$option.attr("selected","selected");$select2.append($option)}if(!$select2.attr("multiple")){$blankOption=$("<option value=''> </option>");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");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<parts.length;n++){var part=parts[n];var name=part.replace("=page.","");var $select1=$("#Inputfield_"+name);if($select1.length<1)continue;$select1.change(function(){selectChanged($select1,$select2,selector,formatName,labelFieldName,part,true)});if($select1.val()&&!$select2.val()&&$select2.children('option[value!=""]').length<1){setTimeout(function(){selectChanged($select1,$select2,selector,formatName,labelFieldName,part,false)},100)}}}$inputfieldPage.find(".findPagesSelector").each(function(){initSelector($(this))})}$(document).ready(function(){$(".InputfieldPage").each(function(){initInputfieldPage($(this))});$(document).on("reloaded",".InputfieldPage",function(){initInputfieldPage($(this))})});
|
@@ -436,6 +436,7 @@ class InputfieldPage extends Inputfield implements ConfigurableModule {
|
|||||||
if(is_null($value)) $value = $page->get($field);
|
if(is_null($value)) $value = $page->get($field);
|
||||||
if(is_object($value) && $subfield) $value = $value->$subfield;
|
if(is_object($value) && $subfield) $value = $value->$subfield;
|
||||||
if(is_array($value)) $value = implode('|', $value);
|
if(is_array($value)) $value = implode('|', $value);
|
||||||
|
if(!strlen("$value") && (!$subfield || $subfield == 'id')) $value = '-1'; // force fail
|
||||||
$selector = str_replace($tag, "=$value", $selector);
|
$selector = str_replace($tag, "=$value", $selector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1172,6 +1173,7 @@ class InputfieldPage extends Inputfield implements ConfigurableModule {
|
|||||||
|
|
||||||
if($this->hasFieldtype !== false) {
|
if($this->hasFieldtype !== false) {
|
||||||
|
|
||||||
|
/** @var InputfieldMarkup $f */
|
||||||
$f = $this->modules->get('InputfieldMarkup');
|
$f = $this->modules->get('InputfieldMarkup');
|
||||||
$f->label = $this->_('Regarding “Page List” input types');
|
$f->label = $this->_('Regarding “Page List” input types');
|
||||||
$f->icon = 'warning';
|
$f->icon = 'warning';
|
||||||
|
@@ -430,7 +430,7 @@ class InputfieldSelect extends Inputfield {
|
|||||||
* Note: method was protected prior to 3.0.116
|
* Note: method was protected prior to 3.0.116
|
||||||
*
|
*
|
||||||
* @param array|null $options Options array or omit (null) to use already specified options
|
* @param array|null $options Options array or omit (null) to use already specified options
|
||||||
* @param bool $allowBlank Allow first item to be blank when supported? (default=tru)
|
* @param bool $allowBlank Allow first item to be blank when supported? (default=true)
|
||||||
* @return string
|
* @return string
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user