mirror of
https://github.com/processwire/processwire.git
synced 2025-08-25 15:51:37 +02:00
Some additional adjustments to the live search, including the addition of a "help" option, which you can access just by typing "help" into the search box. Bumped version to 3.0.108
This commit is contained in:
@@ -534,6 +534,7 @@ interface SearchableModule {
|
||||
* 'title' => 'Title of these items',
|
||||
* 'total' => 999, // total number of items found, or omit if pagination not supported or active
|
||||
* 'url' => '', // optional URL to view all items, or omit for a PW-generated one
|
||||
* 'properties' => array(), // optional list of supported search properties, only looked for if $options['info'] === true;
|
||||
* 'items' => array(
|
||||
* [0] => array(
|
||||
* 'id' => 123, // Unique ID of item (optional)
|
||||
@@ -549,25 +550,35 @@ interface SearchableModule {
|
||||
* [1] => array(
|
||||
* ...
|
||||
* ),
|
||||
* )
|
||||
* ),
|
||||
* );
|
||||
*
|
||||
* Please note: When ProcessWire calls this method, if the module is not already loaded (autoload),
|
||||
* PLEASE NOTE:
|
||||
* When ProcessWire calls this method, if the module is not already loaded (autoload),
|
||||
* it instantiates the module but DOES NOT call the init() or ready() methods. That’s because the
|
||||
* search method is generally self contained. If you need either of those methods to be called,
|
||||
* and your module is not autoload, you should call the method(s) from your search() method.
|
||||
*
|
||||
* About the optional “properties” index:
|
||||
* If ProcessWire calls your search() method with $options['info'] == true; then it is likely wanting to see
|
||||
* what properties are available for search. For instance, properties for a Module search might be:
|
||||
* [ 'name', 'title', 'summary' ]. Implementation of the properties index is optional, and for PW’s informational
|
||||
* purposes only.
|
||||
*
|
||||
* @param string $text Text to search for
|
||||
* @param array $options Options array provided to search() calls:
|
||||
* - `edit` (bool): True if any 'url' returned should be to edit items rather than view them
|
||||
* - `edit` (bool): True if any 'url' returned should be to edit rather than view items, where access allows. (default=true)
|
||||
* - `multilang` (bool): If true, search all languages rather than just current (default=true).
|
||||
* - `start` (int): Start index (0-based), if pagination active (default=0).
|
||||
* - `limit` (int): Limit to this many items, or 0 for no limit. (default=0).
|
||||
* - `type` (string): If search should only be of a specific type, i.e. "pages", "modules", etc. then it is
|
||||
* specified here. This corresponds with the getModuleInfo()['searchable'] name or item 'group' property.
|
||||
* Note that ProcessWire won’t call your search() method if the type cannot match this search.
|
||||
* - `operator` (string): Selector operator type requested, if more than one is supported (default is %=).
|
||||
* - `property` (string): If search should limit to a particular property/fieldj, it is named here.
|
||||
* - `verbose` (bool): True if output can optionally be more verbose, false if not. (default=false)
|
||||
* - `debug` (bool): True if DEBUG option was specified in query. (default=false)
|
||||
* - `help` (bool): True if we are just querying for help/info and are not using the search results. (default=false)
|
||||
* @return array
|
||||
*
|
||||
*/
|
||||
|
@@ -1538,7 +1538,7 @@ class Modules extends WireArray {
|
||||
* ~~~~~
|
||||
*
|
||||
* @param string $prefix Specify prefix, i.e. "Process", "Fieldtype", "Inputfield", etc.
|
||||
* @param bool|int $instantiate Specify one of the following:
|
||||
* @param bool|int $load Specify one of the following:
|
||||
* - Boolean true to return array of instantiated modules.
|
||||
* - Boolean false to return array of module names (default).
|
||||
* - Integer 1 to return array of module info for each matching module.
|
||||
@@ -1546,16 +1546,16 @@ class Modules extends WireArray {
|
||||
* @return array Returns array of module class names or Module objects. In either case, array indexes are class names.
|
||||
*
|
||||
*/
|
||||
public function findByPrefix($prefix, $instantiate = false) {
|
||||
public function findByPrefix($prefix, $load = false) {
|
||||
$results = array();
|
||||
foreach($this as $key => $value) {
|
||||
$className = wireClassName($value->className(), false);
|
||||
if(strpos($className, $prefix) !== 0) continue;
|
||||
if($instantiate === 1) {
|
||||
if($load === 1) {
|
||||
$results[$className] = $this->getModuleInfo($className);
|
||||
} else if($instantiate === 2) {
|
||||
} else if($load === 2) {
|
||||
$results[$className] = $this->getModuleInfoVerbose($className);
|
||||
} else if($instantiate === true) {
|
||||
} else if($load === true) {
|
||||
$results[$className] = $this->getModule($className);
|
||||
} else {
|
||||
$results[$className] = $className;
|
||||
@@ -1571,7 +1571,7 @@ class Modules extends WireArray {
|
||||
* - Selector string to match module info.
|
||||
* - Array of [ 'property' => 'value' ] to match in module info (this is not a selector array).
|
||||
* - Name of property that will match module if not empty in module info.
|
||||
* @param bool|int $instantiate Specify one of the following:
|
||||
* @param bool|int $load Specify one of the following:
|
||||
* - Boolean true to return array of instantiated modules.
|
||||
* - Boolean false to return array of module names (default).
|
||||
* - Integer 1 to return array of module info for each matching module.
|
||||
@@ -1579,13 +1579,13 @@ class Modules extends WireArray {
|
||||
* @return array Array of modules, module names or module info arrays, indexed by module name.
|
||||
*
|
||||
*/
|
||||
public function findByInfo($selector, $instantiate = false) {
|
||||
public function findByInfo($selector, $load = false) {
|
||||
|
||||
$selectors = null;
|
||||
$infos = null;
|
||||
$keys = null;
|
||||
$results = array();
|
||||
$verbose = $instantiate === 2;
|
||||
$verbose = $load === 2;
|
||||
$properties = array();
|
||||
$has = '';
|
||||
|
||||
@@ -1612,7 +1612,12 @@ class Modules extends WireArray {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach($this->getModuleInfo('*', array('verbose' => $verbose)) as $info) {
|
||||
$moduleInfoOptions = array(
|
||||
'verbose' => $verbose,
|
||||
'minify' => false
|
||||
);
|
||||
|
||||
foreach($this->getModuleInfo('*', $moduleInfoOptions) as $info) {
|
||||
$isMatch = false;
|
||||
|
||||
if($has) {
|
||||
@@ -1650,9 +1655,9 @@ class Modules extends WireArray {
|
||||
|
||||
if($isMatch) {
|
||||
$moduleName = $info['name'];
|
||||
if(is_int($instantiate)) {
|
||||
if(is_int($load)) {
|
||||
$results[$moduleName] = $info;
|
||||
} else if($instantiate === true) {
|
||||
} else if($load === true) {
|
||||
$results[$moduleName] = $this->getModule($moduleName);
|
||||
} else {
|
||||
$results[$moduleName] = $moduleName;
|
||||
@@ -3166,6 +3171,27 @@ class Modules extends WireArray {
|
||||
return $this->getConfig($className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the URL where the module can be edited, configured or uninstalled
|
||||
*
|
||||
* If module is not installed, it just returns the URL to ProcessModule.
|
||||
*
|
||||
* #pw-group-configuration
|
||||
*
|
||||
* @param string|Module $className
|
||||
* @param bool $collapseInfo
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function getModuleEditUrl($className, $collapseInfo = true) {
|
||||
if(!is_string($className)) $className = $this->getModuleClass($className);
|
||||
$url = $this->wire('config')->urls->admin . 'module/';
|
||||
if(empty($className) || !$this->isInstalled($className)) return $url;
|
||||
$url .= "edit/?name=$className";
|
||||
if($collapseInfo) $url .= "&collapse_info=1";
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a module name, return an associative array of configuration data for it
|
||||
*
|
||||
|
@@ -45,7 +45,7 @@ class ProcessWire extends Wire {
|
||||
* Reversion revision number
|
||||
*
|
||||
*/
|
||||
const versionRevision = 107;
|
||||
const versionRevision = 108;
|
||||
|
||||
/**
|
||||
* Version suffix string (when applicable)
|
||||
|
@@ -108,6 +108,7 @@ var ProcessWireAdminTheme = {
|
||||
.attr('title', item.tip)
|
||||
.append($label)
|
||||
.append($("<small class='uk-text-muted'></small>").text(item.template));
|
||||
if(item.edit_url == '#' || !item.edit_url.length) $a.removeAttr('href');
|
||||
return $("<li></li>").append($a).appendTo(ul);
|
||||
}
|
||||
});
|
||||
@@ -154,6 +155,7 @@ var ProcessWireAdminTheme = {
|
||||
// follow the link if the Enter/Return key is tapped
|
||||
if(typeof event.key != 'undefined') {
|
||||
event.preventDefault();
|
||||
if(ui.item.edit_url == '#' || !ui.item.edit_url.length) return false;
|
||||
window.location = ui.item.edit_url;
|
||||
}
|
||||
}
|
||||
|
@@ -1 +1 @@
|
||||
var ProcessWireAdminTheme={init:function(){var b=$("#head_button > button.pw-dropdown-toggle").hide();this.setupCloneButton();ProcessWireAdmin.init();this.setupSearch();this.setupMobile();var a=$("body");if(a.hasClass("hasWireTabs")&&$("ul.WireTabs").length==0){a.removeClass("hasWireTabs")}$("#content").removeClass("pw-fouc-fix");a.removeClass("pw-init").addClass("pw-ready");if(b.length>0){b.show()}},setupCloneButton:function(){if($("body").is(".modal")){return}var b=$("button.pw-head-button, button.head_button_clone");if(b.length==0){return}var a=$("#head_button");if(a.length==0){a=$("<div id='head_button'></div>").prependTo("#breadcrumbs .pw-container")}b.each(function(){var e=$(this);var d=e.parent("a");var c;if(d.length>0){c=e.parent("a").clone(true);a.prepend(c)}else{if(e.hasClass("pw-head-button")||e.hasClass("head_button_clone")){c=e.clone(true);c.attr("data-from_id",e.attr("id")).attr("id",e.attr("id")+"_copy");c.click(function(){$("#"+$(this).attr("data-from_id")).click();return false});a.prepend(c)}}});a.show()},setupSearch:function(){$.widget("custom.adminsearchautocomplete",$.ui.autocomplete,{_renderMenu:function(e,c){var f=this;var d="";e.attr("id","ProcessPageSearchAutocomplete");$.each(c,function(g,h){if(h.type!=d){$("<li>"+h.type+"</li>").addClass("ui-widget-header").appendTo(e);d=h.type}f._renderItemData(e,h)})},_renderItem:function(e,f){if(f.label==f.template){f.template=""}var c=$("<span></span>").text(f.label).css("margin-right","3px");if(f.unpublished){c.css("text-decoration","line-through")}if(f.hidden){c.addClass("ui-priority-secondary")}if(typeof f.icon!="undefined"&&f.icon.length){var d=$("<i></i>").addClass("fa fa-fw fa-"+f.icon).css("margin-right","2px");c.prepend(d)}var g=$("<a></a>").attr("href",f.edit_url).attr("title",f.tip).append(c).append($("<small class='uk-text-muted'></small>").text(f.template));return $("<li></li>").append(g).appendTo(e)}});var b=$("#ProcessPageSearchQuery");var a=$("#ProcessPageSearchStatus");b.adminsearchautocomplete({minLength:2,position:{my:"right top",at:"right bottom"},search:function(c,d){a.html("<img src='"+ProcessWire.config.urls.modules+"Process/ProcessPageList/images/loading.gif'>")},open:function(c,d){$("#topnav").hide()},close:function(c,d){$("#topnav").show()},source:function(e,c){var d=b.parents("form").attr("action")+"?q="+e.term;$.getJSON(d,function(g){var f=g.matches.length;if(f<g.total){a.text(g.matches.length+"/"+g.total)}else{a.text(f)}c($.map(g.matches,function(h){return{label:h.title,value:h.title,page_id:h.id,template:h.template_label?h.template_label:"",edit_url:h.editUrl,type:h.type,tip:h.tip,unpublished:(typeof h.unpublished!="undefined"?h.unpublished:false),hidden:(typeof h.hidden!="undefined"?h.hidden:false),locked:(typeof h.locked!="undefined"?h.locked:false),icon:(typeof h.icon!="undefined"?h.icon:"")}}))})},select:function(c,d){if(typeof c.key!="undefined"){c.preventDefault();window.location=d.item.edit_url}}}).focus(function(){$(this).siblings("label").find("i").hide()}).blur(function(){a.text("");$(this).siblings("label").find("i").show()})},setupMobile:function(){var a=0;var c=0;var b=function(){var h=$("#topnav");var g=$("body");var e=h.height();if(e>50){if(!g.hasClass("collapse-topnav")){g.addClass("collapse-topnav");a=g.width()}}else{if(a>0){var f=g.width();if(g.hasClass("collapse-topnav")&&f>a){g.removeClass("collapse-topnav");a=0}}}h.children(".collapse-topnav-menu").children("a").click(function(){if($(this).is(".hover")){$(this).mouseleave()}else{$(this).mouseenter()}return false});var d=$(".WireTabs");if(d.length<1){return}d.each(function(){var j=$(this);var i=j.height();if(i>65){if(!g.hasClass("collapse-wiretabs")){g.addClass("collapse-wiretabs");c=g.width()}}else{if(c>0){var k=g.width();if(g.hasClass("collapse-wiretabs")&&k>c){g.removeClass("collapse-wiretabs");c=0}}}})};b();$(window).resize(b)}};$(document).ready(function(){ProcessWireAdminTheme.init();$("a.notice-remove","#notices").click(function(){$("#notices").slideUp("fast",function(){$(this).remove()});return false})});
|
||||
var ProcessWireAdminTheme={init:function(){var b=$("#head_button > button.pw-dropdown-toggle").hide();this.setupCloneButton();ProcessWireAdmin.init();this.setupSearch();this.setupMobile();var a=$("body");if(a.hasClass("hasWireTabs")&&$("ul.WireTabs").length==0){a.removeClass("hasWireTabs")}$("#content").removeClass("pw-fouc-fix");a.removeClass("pw-init").addClass("pw-ready");if(b.length>0){b.show()}},setupCloneButton:function(){if($("body").is(".modal")){return}var b=$("button.pw-head-button, button.head_button_clone");if(b.length==0){return}var a=$("#head_button");if(a.length==0){a=$("<div id='head_button'></div>").prependTo("#breadcrumbs .pw-container")}b.each(function(){var e=$(this);var d=e.parent("a");var c;if(d.length>0){c=e.parent("a").clone(true);a.prepend(c)}else{if(e.hasClass("pw-head-button")||e.hasClass("head_button_clone")){c=e.clone(true);c.attr("data-from_id",e.attr("id")).attr("id",e.attr("id")+"_copy");c.click(function(){$("#"+$(this).attr("data-from_id")).click();return false});a.prepend(c)}}});a.show()},setupSearch:function(){$.widget("custom.adminsearchautocomplete",$.ui.autocomplete,{_renderMenu:function(e,c){var f=this;var d="";e.attr("id","ProcessPageSearchAutocomplete");$.each(c,function(g,h){if(h.type!=d){$("<li>"+h.type+"</li>").addClass("ui-widget-header").appendTo(e);d=h.type}f._renderItemData(e,h)})},_renderItem:function(e,f){if(f.label==f.template){f.template=""}var c=$("<span></span>").text(f.label).css("margin-right","3px");if(f.unpublished){c.css("text-decoration","line-through")}if(f.hidden){c.addClass("ui-priority-secondary")}if(typeof f.icon!="undefined"&&f.icon.length){var d=$("<i></i>").addClass("fa fa-fw fa-"+f.icon).css("margin-right","2px");c.prepend(d)}var g=$("<a></a>").attr("href",f.edit_url).attr("title",f.tip).append(c).append($("<small class='uk-text-muted'></small>").text(f.template));if(f.edit_url=="#"||!f.edit_url.length){g.removeAttr("href")}return $("<li></li>").append(g).appendTo(e)}});var b=$("#ProcessPageSearchQuery");var a=$("#ProcessPageSearchStatus");b.adminsearchautocomplete({minLength:2,position:{my:"right top",at:"right bottom"},search:function(c,d){a.html("<img src='"+ProcessWire.config.urls.modules+"Process/ProcessPageList/images/loading.gif'>")},open:function(c,d){$("#topnav").hide()},close:function(c,d){$("#topnav").show()},source:function(e,c){var d=b.parents("form").attr("action")+"?q="+e.term;$.getJSON(d,function(g){var f=g.matches.length;if(f<g.total){a.text(g.matches.length+"/"+g.total)}else{a.text(f)}c($.map(g.matches,function(h){return{label:h.title,value:h.title,page_id:h.id,template:h.template_label?h.template_label:"",edit_url:h.editUrl,type:h.type,tip:h.tip,unpublished:(typeof h.unpublished!="undefined"?h.unpublished:false),hidden:(typeof h.hidden!="undefined"?h.hidden:false),locked:(typeof h.locked!="undefined"?h.locked:false),icon:(typeof h.icon!="undefined"?h.icon:"")}}))})},select:function(c,d){if(typeof c.key!="undefined"){c.preventDefault();if(d.item.edit_url=="#"||!d.item.edit_url.length){return false}window.location=d.item.edit_url}}}).focus(function(){$(this).siblings("label").find("i").hide()}).blur(function(){a.text("");$(this).siblings("label").find("i").show()})},setupMobile:function(){var a=0;var c=0;var b=function(){var h=$("#topnav");var g=$("body");var e=h.height();if(e>50){if(!g.hasClass("collapse-topnav")){g.addClass("collapse-topnav");a=g.width()}}else{if(a>0){var f=g.width();if(g.hasClass("collapse-topnav")&&f>a){g.removeClass("collapse-topnav");a=0}}}h.children(".collapse-topnav-menu").children("a").click(function(){if($(this).is(".hover")){$(this).mouseleave()}else{$(this).mouseenter()}return false});var d=$(".WireTabs");if(d.length<1){return}d.each(function(){var j=$(this);var i=j.height();if(i>65){if(!g.hasClass("collapse-wiretabs")){g.addClass("collapse-wiretabs");c=g.width()}}else{if(c>0){var k=g.width();if(g.hasClass("collapse-wiretabs")&&k>c){g.removeClass("collapse-wiretabs");c=0}}}})};b();$(window).resize(b)}};$(document).ready(function(){ProcessWireAdminTheme.init();$("a.notice-remove","#notices").click(function(){$("#notices").slideUp("fast",function(){$(this).remove()});return false})});
|
@@ -338,6 +338,7 @@ var ProcessWireAdminTheme = {
|
||||
.attr('title', item.tip)
|
||||
.append($label)
|
||||
.append($("<small class='uk-text-muted'></small>").text(item.template));
|
||||
if(item.edit_url == '#' || !item.edit_url.length) $a.removeAttr('href');
|
||||
return $("<li></li>").append($a).appendTo(ul);
|
||||
}
|
||||
});
|
||||
@@ -378,6 +379,7 @@ var ProcessWireAdminTheme = {
|
||||
// follow the link if the Enter/Return key is tapped
|
||||
if(typeof event.key != 'undefined') {
|
||||
event.preventDefault();
|
||||
if(ui.item.edit_url == '#' || !ui.item.edit_url.length) return false;
|
||||
window.location = ui.item.edit_url;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@@ -314,6 +314,8 @@ var ProcessWireAdminTheme = {
|
||||
.append($label)
|
||||
.append($("<small class='uk-text-muted'></small>").text(item.template));
|
||||
|
||||
if(item.edit_url == '#' || !item.edit_url.length) $a.removeAttr('href');
|
||||
|
||||
return $("<li></li>").append($a).appendTo(ul);
|
||||
}
|
||||
});
|
||||
@@ -378,6 +380,7 @@ var ProcessWireAdminTheme = {
|
||||
$(this).val('');
|
||||
if(typeof event.key !== 'undefined') {
|
||||
event.preventDefault();
|
||||
if(ui.item.edit_url === '#' || ui.item.edit_url.length < 1) return false;
|
||||
if(typeof parent.isPresent == "undefined") {
|
||||
window.location = ui.item.edit_url;
|
||||
} else {
|
||||
|
File diff suppressed because one or more lines are too long
@@ -710,8 +710,23 @@ class ProcessCommentsManager extends Process {
|
||||
'total' => 0,
|
||||
'url' => '',
|
||||
'items' => array(),
|
||||
'properties' => array(
|
||||
'text',
|
||||
'cite',
|
||||
'email',
|
||||
'status',
|
||||
'created',
|
||||
'website',
|
||||
'ip',
|
||||
'user_agent',
|
||||
'upvotes',
|
||||
'downvotes',
|
||||
'stars'
|
||||
)
|
||||
);
|
||||
|
||||
if($options['help']) return $result;
|
||||
|
||||
$operator = empty($options['operator']) ? '%=' : $options['operator'];
|
||||
$value = $this->wire('sanitizer')->selectorValue($text);
|
||||
$summaryLength = $options['verbose'] ? 1024 : 200;
|
||||
|
@@ -2625,8 +2625,21 @@ class ProcessField extends Process implements ConfigurableModule {
|
||||
$result = array(
|
||||
'title' => $page->id ? $page->title : $this->className(),
|
||||
'items' => array(),
|
||||
'total' => 0,
|
||||
'properties' => array(
|
||||
'name',
|
||||
'type',
|
||||
'label',
|
||||
'description',
|
||||
'notes',
|
||||
'settings',
|
||||
'tags',
|
||||
'icon',
|
||||
)
|
||||
);
|
||||
|
||||
if(!empty($options['help'])) return $result;
|
||||
|
||||
$looseItems = array();
|
||||
$exactItems = array();
|
||||
$property = isset($options['property']) ? $options['property'] : '';
|
||||
@@ -2652,10 +2665,13 @@ class ProcessField extends Process implements ConfigurableModule {
|
||||
if($property == 'notes' || $property == 'all') $search[] = $item->notes;
|
||||
}
|
||||
|
||||
if($property == 'data') {
|
||||
if($property == 'settings' || $property == 'data') {
|
||||
foreach($item->getArray() as $k => $v) {
|
||||
$search[] = (string) $v;
|
||||
}
|
||||
} else if(!in_array($property, $result['properties'])) {
|
||||
$val = $item->get($property);
|
||||
if($val !== null) $search[] = $val;
|
||||
}
|
||||
|
||||
$search = implode(' ', $search);
|
||||
@@ -2663,6 +2679,9 @@ class ProcessField extends Process implements ConfigurableModule {
|
||||
if($pos === false) continue;
|
||||
$exact = stripos($search, " $text");
|
||||
|
||||
$result['total']++;
|
||||
if(!empty($options['limit']) && $cnt >= $options['limit']) break;
|
||||
|
||||
$item = array(
|
||||
'id' => $item->id,
|
||||
'name' => $item->name,
|
||||
@@ -2680,7 +2699,6 @@ class ProcessField extends Process implements ConfigurableModule {
|
||||
}
|
||||
|
||||
$cnt++;
|
||||
if(!empty($options['limit']) && $cnt >= $options['limit']) break;
|
||||
}
|
||||
|
||||
$result['items'] = array_merge($exactItems, $looseItems);
|
||||
|
@@ -52,6 +52,7 @@ class ProcessPageSearchLive extends Wire {
|
||||
'limit' => 15,
|
||||
'verbose' => false,
|
||||
'debug' => false,
|
||||
'help' => false,
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -370,7 +371,8 @@ class ProcessPageSearchLive extends Wire {
|
||||
'multilang' => $this->wire('languages') ? true : false,
|
||||
'language' => $language,
|
||||
'start' => $start,
|
||||
'limit' => $limit
|
||||
'limit' => $limit,
|
||||
'help' => strtolower($q) === 'help',
|
||||
));
|
||||
|
||||
if($this->isViewAll) {
|
||||
@@ -463,12 +465,14 @@ class ProcessPageSearchLive extends Wire {
|
||||
}
|
||||
|
||||
if($this->process) {
|
||||
$headline = $this->labels['search-results'];
|
||||
if($type) $headline .= " - " . ucfirst($type);
|
||||
if($type) {
|
||||
$this->process->headline($this->pagination->getPaginationString(array(
|
||||
'label' => $headline,
|
||||
'label' => $this->labels['search-results'] . " - " . ucfirst($type),
|
||||
'count' => count($results)
|
||||
)));
|
||||
} else {
|
||||
$this->process->headline($this->labels['search-results']);
|
||||
}
|
||||
}
|
||||
|
||||
$out = $this->renderList($results);
|
||||
@@ -517,6 +521,7 @@ class ProcessPageSearchLive extends Wire {
|
||||
$type = $liveSearch['type'];
|
||||
$foundTypes = array();
|
||||
$modulesInfo = array();
|
||||
$help = $liveSearch['help'];
|
||||
|
||||
/** @var Modules $modules */
|
||||
$modules = $this->wire('modules');
|
||||
@@ -564,7 +569,7 @@ class ProcessPageSearchLive extends Wire {
|
||||
// ok
|
||||
}
|
||||
|
||||
if(!$module || empty($result['items'])) continue;
|
||||
if(!$module || (empty($result['items']) && empty($liveSearch['help']))) continue;
|
||||
if(empty($result['total'])) $result['total'] = count($result['items']);
|
||||
|
||||
if(!in_array($thisType, $this->searchTypesOrder)) $this->searchTypesOrder[] = $thisType;
|
||||
@@ -574,6 +579,14 @@ class ProcessPageSearchLive extends Wire {
|
||||
$title = empty($result['title']) ? $info['title'] : $result['title'];
|
||||
$n = $liveSearch['start'];
|
||||
$item = null;
|
||||
|
||||
if($help) {
|
||||
foreach($result['items'] as $key => $item) {
|
||||
if($item['name'] != 'help') unset($result['items'][$key]);
|
||||
}
|
||||
$result['items'] = array_merge($this->makeHelpItems($result, $thisType), $result['items']);
|
||||
}
|
||||
|
||||
foreach($result['items'] as $item) {
|
||||
$n++;
|
||||
$item = array_merge($this->itemTemplate, $item);
|
||||
@@ -582,18 +595,20 @@ class ProcessPageSearchLive extends Wire {
|
||||
$items[$order] = $item;
|
||||
$order++;
|
||||
}
|
||||
if($n && $n < $result['total'] && !$this->isViewAll) {
|
||||
|
||||
if($n && $n < $result['total'] && !$this->isViewAll && !$help) {
|
||||
$url = isset($result['url']) ? $result['url'] : '';
|
||||
$items[$order] = $this->makeViewAllItem($liveSearch, $thisType, $item['group'], $result['total'], $url);
|
||||
}
|
||||
if($this->isViewAll && $this->pagination && $type) {
|
||||
|
||||
if($this->isViewAll && $this->pagination && $type && !$help) {
|
||||
$this->pagination->setTotal($result['total']);
|
||||
$this->pagination->setLimit($liveSearch['limit']);
|
||||
$this->pagination->setStart($liveSearch['start']);
|
||||
}
|
||||
}
|
||||
|
||||
if($type && !count($foundTypes) && !in_array($type, array('pages', 'trash', 'modules'))) {
|
||||
if($type && !$help && !count($foundTypes) && !in_array($type, array('pages', 'trash', 'modules'))) {
|
||||
if(empty($liveSearch['template']) && !count($foundTypes)) {
|
||||
// if no types matched, and it’s going to skip pages, assume type is a property, and do a pages search
|
||||
$liveSearch = $this->init(array(
|
||||
@@ -636,6 +651,8 @@ class ProcessPageSearchLive extends Wire {
|
||||
|
||||
ksort($items);
|
||||
|
||||
if($help) $items = array_merge($this->makeHelpItems(array(), 'help'), $items);
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
@@ -653,6 +670,13 @@ class ProcessPageSearchLive extends Wire {
|
||||
$superuser = $user->isSuperuser();
|
||||
$pages = $this->wire('pages');
|
||||
|
||||
if(!empty($liveSearch['help'])) {
|
||||
$result = array('title' => 'pages', 'items' => array(), 'properties' => array('name', 'title'));
|
||||
if($this->wire('fields')->get('body')) $result['properties'][] = 'body';
|
||||
$result['properties'][] = $this->_('or any field name');
|
||||
return $this->makeHelpItems($result, 'pages');
|
||||
}
|
||||
|
||||
// a $pages->find() search will be included in the live search
|
||||
$selectors = &$liveSearch['selectors'];
|
||||
$selectors[] = "start=$liveSearch[start], limit=$liveSearch[limit]";
|
||||
@@ -766,6 +790,24 @@ class ProcessPageSearchLive extends Wire {
|
||||
$items = array();
|
||||
$forceMatch = false;
|
||||
|
||||
if(!empty($liveSearch['help'])) {
|
||||
$info = $this->wire('modules')->getModuleInfoVerbose('ProcessPageSearch');
|
||||
$properties = array();
|
||||
foreach(array_keys($info) as $property) {
|
||||
$value = $info[$property];
|
||||
if(!is_array($value)) $properties[$property] = $property;
|
||||
}
|
||||
$exclude = array('id', 'file', 'versionStr', 'core');
|
||||
foreach($exclude as $key) unset($properties[$key]);
|
||||
$result = array(
|
||||
'title' => 'Modules',
|
||||
'items' => array(),
|
||||
'properties' => $properties
|
||||
);
|
||||
$items = $this->makeHelpItems($result, 'modules');
|
||||
return $items;
|
||||
}
|
||||
|
||||
if($liveSearch['type'] === 'modules' && !empty($liveSearch['property'])) {
|
||||
// searching for custom module property
|
||||
$forceMatch = true;
|
||||
@@ -779,18 +821,20 @@ class ProcessPageSearchLive extends Wire {
|
||||
}
|
||||
|
||||
foreach($infos as $info) {
|
||||
$id = isset($info['id']) ? $info['id'] : 0;
|
||||
$name = $info['name'];
|
||||
$title = $info['title'];
|
||||
$summary = isset($info['summary']) ? $info['summary'] : '';
|
||||
if(!$forceMatch) {
|
||||
$searchText = "$name $title $info[summary]";
|
||||
$searchText = "$name $title $summary";
|
||||
if(stripos($searchText, $q) === false) continue;
|
||||
}
|
||||
$item = array(
|
||||
'id' => $info['id'],
|
||||
'id' => $id,
|
||||
'name' => $name,
|
||||
'title' => $title,
|
||||
'subtitle' => $name,
|
||||
'summary' => $info['summary'],
|
||||
'summary' => $summary,
|
||||
'url' => $this->wire('config')->urls->admin . "module/edit?name=$name",
|
||||
'group' => $groupLabel,
|
||||
);
|
||||
@@ -867,6 +911,129 @@ class ProcessPageSearchLive extends Wire {
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a search result item that displays property info
|
||||
*
|
||||
* @param array $result Result array returned by a SearchableModule::search() method
|
||||
* @param string $type
|
||||
* @return array
|
||||
*
|
||||
*/
|
||||
protected function makeHelpItems(array $result, $type) {
|
||||
|
||||
$items = array();
|
||||
$helloLabel = $this->_('test');
|
||||
$usage1desc = $this->wire('sanitizer')->unentities($this->_('Searches %1$s for: %2$s'));
|
||||
$usage2desc = $this->wire('sanitizer')->unentities($this->_('Searches “%1$s” property of %2$s for: %3$s'));
|
||||
|
||||
if($type === 'help') {
|
||||
$operators = ProcessPageSearch::getOperators();
|
||||
$summary =
|
||||
$this->_('Examples use the “=” equals operator.') . " \n" .
|
||||
$this->_('In some cases you can also use these:') . "\n";
|
||||
foreach($operators as $op => $label) {
|
||||
$summary .= "$op " . rtrim($label, '*') . "\n";
|
||||
}
|
||||
$items[] = array(
|
||||
'title' => $this->_('operators:'),
|
||||
'subtitle' => implode(', ', array_keys($operators)),
|
||||
'summary' => $summary,
|
||||
'group' => 'help',
|
||||
'url' => 'https://processwire.com/api/selectors/#operators'
|
||||
);
|
||||
if($this->wire('user')->isSuperuser() && $this->process) {
|
||||
$items[] = array(
|
||||
'title' => $this->_('configure'),
|
||||
'subtitle' => $this->_('Click here to configure search settings'),
|
||||
'url' => $url = $this->wire('modules')->getModuleEditUrl('ProcessPageSearch'),
|
||||
'group' => 'help',
|
||||
);
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
// include any items from result that had the name "help"
|
||||
foreach($result['items'] as $item) {
|
||||
if($item['name'] == 'help') $items[] = $item;
|
||||
}
|
||||
|
||||
$items[] = array(
|
||||
'title' => "$type=$helloLabel",
|
||||
'subtitle' => sprintf($usage1desc, $type, $helloLabel),
|
||||
);
|
||||
|
||||
if(!empty($result['properties'])) {
|
||||
|
||||
if($type == 'pages' || $type == 'modules') {
|
||||
$property = 'title';
|
||||
} else if($type == 'fields' || $type == 'templates') {
|
||||
$property = 'label';
|
||||
} else {
|
||||
$property = reset($result['properties']);
|
||||
}
|
||||
|
||||
$items[] = array(
|
||||
'title' => "$type.$property=$helloLabel",
|
||||
'subtitle' => sprintf($usage2desc, $property, $type, $helloLabel)
|
||||
);
|
||||
|
||||
if($type === 'pages') {
|
||||
$items[] = array(
|
||||
'title' => "$property=$helloLabel",
|
||||
'subtitle' => $this->_('Same as above (shorter syntax if no names collide)')
|
||||
);
|
||||
$templateName = 'basic-page';
|
||||
$items[] = array(
|
||||
'title' => "$templateName=$helloLabel",
|
||||
'subtitle' => sprintf($this->_('Limit results to template: %s'), $templateName),
|
||||
);
|
||||
$items[] = array(
|
||||
'title' => "$templateName.$property=$helloLabel",
|
||||
'subtitle' => sprintf($this->_('Limit results to %s field on template'), $property)
|
||||
);
|
||||
|
||||
} else if($type === 'templates') {
|
||||
$fieldName = 'images';
|
||||
$items[] = array(
|
||||
'title' => "templates.fields=$fieldName",
|
||||
'subtitle' => sprintf($this->_('Find templates that have field: %s'), $fieldName)
|
||||
);
|
||||
} else if($type === 'fields') {
|
||||
$items[] = array(
|
||||
'title' => "fields.settings=ckeditor",
|
||||
'subtitle' => $this->_('Find fields with “ckeditor” in settings'),
|
||||
);
|
||||
}
|
||||
|
||||
$properties = implode(', ', $result['properties']);
|
||||
|
||||
if(strlen($properties) > 50) {
|
||||
$properties = $this->wire('sanitizer')->truncate($properties, 50) . ' ' . $this->_('(hover for more)');
|
||||
}
|
||||
|
||||
$summary =
|
||||
sprintf($this->_('The examples use the “%s” property.'), $property) . "\n" .
|
||||
$this->_('You can also use any of these properties:') . "\n • " .
|
||||
implode("\n • ", $result['properties']);
|
||||
|
||||
$items[] = array(
|
||||
'title' => $this->_('properties'),
|
||||
'subtitle' => $properties,
|
||||
'summary' => $summary
|
||||
);
|
||||
}
|
||||
|
||||
$group = sprintf($this->_('%s help'), $type);
|
||||
|
||||
foreach($items as $key => $item) {
|
||||
$item['name'] = 'help';
|
||||
$item['group'] = $group;
|
||||
$items[$key] = array_merge($this->itemTemplate, $item);
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a search result item that displays a “view all” link
|
||||
*
|
||||
@@ -927,11 +1094,17 @@ class ProcessPageSearchLive extends Wire {
|
||||
|
||||
$pagination = $this->pagination->renderPager();
|
||||
$a = array();
|
||||
$group = '';
|
||||
|
||||
$out = "\n<div class='$class'>" . $pagination;
|
||||
|
||||
foreach($items as $item) {
|
||||
$a[] = $this->renderItem($item, $prefix);
|
||||
$headline = '';
|
||||
if($item['group'] != $group) {
|
||||
$group = $item['group'];
|
||||
$headline = "<h2>" . $this->wire('sanitizer')->entities($group) . "</h2>";
|
||||
}
|
||||
$a[] = $headline . $this->renderItem($item, $prefix);
|
||||
}
|
||||
|
||||
$out .= implode('<hr />', $a) . $pagination . "\n</div>";
|
||||
|
@@ -621,6 +621,7 @@ class ProcessPageType extends Process implements ConfigurableModule, WirePageEdi
|
||||
|
||||
$page = $this->getProcessPage();
|
||||
$this->pages = $this->wire($page->name);
|
||||
$templates = $this->pages->getTemplates();
|
||||
|
||||
/** @var Languages $languages */
|
||||
$page = $this->getProcessPage();
|
||||
@@ -630,6 +631,18 @@ class ProcessPageType extends Process implements ConfigurableModule, WirePageEdi
|
||||
'items' => array(),
|
||||
);
|
||||
|
||||
if(!empty($options['help'])) {
|
||||
$result['properties'] = array('name');
|
||||
foreach($templates as $template) {
|
||||
foreach($template->fieldgroup as $field) {
|
||||
if($field->type instanceof FieldtypePassword) continue;
|
||||
if($field->type instanceof FieldtypeFieldsetOpen) continue;
|
||||
$result['properties'][] = $field->name;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
$text = $this->wire('sanitizer')->selectorValue($text);
|
||||
$property = empty($options['property']) ? 'name' : $options['property'];
|
||||
$operator = isset($options['operator']) ? $options['operator'] : '%=';
|
||||
|
@@ -3016,20 +3016,33 @@ class ProcessTemplate extends Process {
|
||||
/** @var Languages $languages */
|
||||
$languages = $this->wire('langauges');
|
||||
$page = $this->getProcessPage();
|
||||
$property = isset($options['property']) ? $options['property'] : '';
|
||||
|
||||
$result = array(
|
||||
'title' => $page->id ? $page->title : $this->className(),
|
||||
'items' => array(),
|
||||
'total' => 0,
|
||||
'properties' => array(
|
||||
'name',
|
||||
'label',
|
||||
'tags',
|
||||
'fields',
|
||||
)
|
||||
);
|
||||
|
||||
if(!empty($options['help'])) return $result;
|
||||
if(!empty($property) && !in_array($property, $result['properties'])) return $result;
|
||||
|
||||
$looseItems = array();
|
||||
$exactItems = array();
|
||||
$cnt = 0;
|
||||
|
||||
foreach($this->wire('templates') as $item) {
|
||||
/** @var Template $item */
|
||||
$search = array(' ', $item->name);
|
||||
$search = array(' ');
|
||||
if(!$property || $property == 'name' ) $search[] = $item->name;
|
||||
|
||||
if(!$property || $property == 'label') {
|
||||
if(!empty($options['multilang']) && $languages) {
|
||||
foreach($languages as $lang) {
|
||||
$search[] = $item->getLabel($lang);
|
||||
@@ -3037,11 +3050,16 @@ class ProcessTemplate extends Process {
|
||||
} else {
|
||||
$search[] = $item->getLabel();
|
||||
}
|
||||
}
|
||||
|
||||
// when search matches field name exactly (that template has), allow template to be matched
|
||||
if($property == 'fields') {
|
||||
foreach($item->fieldgroup as $field) {
|
||||
if(strtolower($text) == strtolower($field->name)) $search[] = $field->name;
|
||||
}
|
||||
} else if($property == 'tags') {
|
||||
$search[] = $item->tags;
|
||||
}
|
||||
|
||||
$search = implode(' ', $search);
|
||||
$pos = stripos($search, $text);
|
||||
@@ -3052,6 +3070,9 @@ class ProcessTemplate extends Process {
|
||||
$label = $item->getLabel();
|
||||
$subtitle = $label == $item->name ? $labelFields : "$label ($labelFields)";
|
||||
|
||||
$result['total']++;
|
||||
if(!empty($options['limit']) && $cnt >= $options['limit']) continue;
|
||||
|
||||
$item = array(
|
||||
'id' => $item->id,
|
||||
'name' => $item->name,
|
||||
@@ -3069,7 +3090,6 @@ class ProcessTemplate extends Process {
|
||||
}
|
||||
|
||||
$cnt++;
|
||||
if(!empty($options['limit']) && $cnt >= $options['limit']) break;
|
||||
}
|
||||
|
||||
$result['items'] = array_merge($exactItems, $looseItems);
|
||||
|
Reference in New Issue
Block a user