Last active
December 18, 2020 14:17
-
-
Save andronex/b5f95c50f1a8b453435f1cb7d07a3ad1 to your computer and use it in GitHub Desktop.
Фильтрация с предсказанием кол-ва результатов. //TODO
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var mSearch2 = {}, | |
selectorFilter = '.js-filter', | |
selectorInput = selectorFilter+' input', | |
selectorClear = selectorFilter+' .js-filter-clean', | |
selectorExe = selectorFilter+' .js-execute', | |
selectorToggle = selectorFilter+' .js-filter-toggle', | |
selectorFormWrap = selectorFilter+' .js-filter-form-wrap', | |
selectorRows = '.js-rows'; | |
mSearch2.Hash = { | |
get: function() { | |
var vars = {}, hash, splitter, hashes; | |
if (!this.oldbrowser()) { | |
var pos = window.location.href.indexOf('?'); | |
hashes = (pos != -1) ? decodeURIComponent(window.location.href.substr(pos + 1)) : ''; | |
splitter = '&'; | |
} | |
else { | |
hashes = decodeURIComponent(window.location.hash.substr(1)); | |
splitter = '/'; | |
} | |
if (hashes.length == 0) {return vars;} | |
else {hashes = hashes.split(splitter);} | |
for (var i in hashes) { | |
if (hashes.hasOwnProperty(i)) { | |
hash = hashes[i].split('='); | |
if (typeof hash[1] == 'undefined') { | |
vars['anchor'] = hash[0]; | |
} | |
else { | |
vars[hash[0]] = hash[1]; | |
} | |
} | |
} | |
return vars; | |
} | |
,set: function(vars) { | |
var hash = ''; | |
for (var i in vars) { | |
if (vars.hasOwnProperty(i)) { | |
hash += '&' + i + '=' + vars[i]; | |
} | |
} | |
if (!this.oldbrowser()) { | |
if (hash.length != 0) { | |
hash = '?' + hash.substr(1); | |
} | |
window.history.pushState(hash, '', document.location.pathname + hash); | |
} | |
else { | |
window.location.hash = hash.substr(1); | |
} | |
} | |
,add: function(key, val) { | |
var hash = this.get(); | |
hash[key] = val; | |
this.set(hash); | |
} | |
,remove: function(key) { | |
var hash = this.get(); | |
delete hash[key]; | |
this.set(hash); | |
} | |
,clear: function() { | |
let hashs = this.get(); | |
let hash = {}; | |
for(var k in hashs) { | |
if(k == 'text' || k == 'video'){ | |
hash[k] = hashs[k]; | |
} | |
} | |
this.set(hash); | |
} | |
,oldbrowser: function() { | |
return !(window.history); // && history.pushState); | |
} | |
}; | |
var setHashs = function(){ | |
if((hashs = mSearch2.Hash.get()) && $( selectorFilter ).length){ | |
let isset = false; | |
for(let k in hashs) { | |
if( $('input[name='+k+']').length ){ | |
$('input[name='+k+']').prop('checked', false); | |
isset = true; | |
array = hashs[k].toString().split(','); | |
for (let i = 0; i < array.length; i++) { | |
$('input[name='+k+'][value='+array[i]+']').prop('checked', true); | |
} | |
} | |
} | |
if(isset){ | |
$(selectorToggle).addClass('open'); | |
$(selectorFormWrap).show(); | |
} | |
} | |
} | |
var getProps = function (obj, name = '') { | |
for (var property in obj) { | |
if (obj.hasOwnProperty(property) && obj[property] != null) { | |
if (obj[property].constructor == Object) { | |
getProps(obj[property], property); | |
} else if (obj[property].constructor == Array) { | |
for (var i = 0; i < obj[property].length; i++) { | |
getProps(obj[property][i]); | |
} | |
} else { | |
//console.log( $(selectorFilter).find('input[name="'+name+'"][value="'+property+'"]') ); | |
$(selectorFilter).find('input[name="'+name+'"][value="'+property+'"]').prop('disabled', false); | |
$(selectorFilter).find('input[name="'+name+'"][value="'+property+'"]').parent().find('.js-num').text(obj[property]); | |
if(obj[property] == 0){ | |
if($(selectorFilter).find('input[name="'+name+'"][value="'+property+'"]').is(':checked')){ | |
$(selectorFilter).find('input[name="'+name+'"][value="'+property+'"]').trigger('click'); | |
} | |
$(selectorFilter).find('input[name="'+name+'"][value="'+property+'"]').prop('disabled', true); | |
} | |
} | |
} | |
} | |
} | |
var exeFilter = function(th){ | |
var $this = $(th), | |
otherInp = $this.parents('form').find('input:checkbox:not(:checked)'), | |
other = [], | |
checkInp = $this.parents('form').find('input:checkbox:checked'), | |
check = []; | |
otherInp.each(function(){ | |
other.push({"name":$(this).prop('name'), "value":$(this).val()}); | |
}); | |
checkInp.each(function(){ | |
check.push({"name":$(this).prop('name'), "value":$(this).val()}); | |
}); | |
$this.prop('disabled', true); | |
$(selectorRows).css({"opacity":"0.5"}); | |
var hashs = mSearch2.Hash.get(), | |
count = Object.keys(hashs).length; | |
hashs["action"] = 'filter'; | |
hashs["other"] = other; | |
hashs["check"] = check; | |
hashs["parent"] = $(selectorFormWrap).find('[name=parent]').val()||4; | |
$.ajax({ | |
type: 'POST', | |
url: '/assets/components/wefilter/action.php', | |
dataType: 'json', | |
data: hashs, | |
success: function (x) { | |
if(x.success){ | |
if(count){ | |
$(selectorRows).html(x.data?x.data:'<h3>По данным параметрам ничего не найдено</h3>'); | |
$(selectorRows).css({"opacity":"1"}); | |
$this.prop('disabled', false); | |
} | |
else{ | |
$(selectorRows).load(location.href+" "+selectorRows+" >*",function(html, success){ | |
$(selectorRows).css({"opacity":"1"}); | |
$this.prop('disabled', false); | |
}); | |
} | |
if(x.suggestion){ | |
//getProps(x.suggestion); | |
$(selectorFormWrap).css({"opacity":"0.5"}); | |
if(x.data){ | |
hashs["action"] = 'suggest'; | |
$.ajax({ | |
type: 'POST', | |
url: '/assets/components/wefilter/action.php', | |
dataType: 'json', | |
data: hashs, | |
success: function (x) { | |
if(x.success){ | |
getProps(x.suggestion); | |
} | |
$(selectorFormWrap).css({"opacity":"1"}); | |
} | |
}); | |
} | |
} | |
} | |
else{ | |
$(selectorRows).css({"opacity":"1"}); | |
$this.prop('disabled', false); | |
} | |
} | |
}); | |
} | |
$(document).ready(function() { | |
//сброс фильтра | |
$(document).on('click touch', selectorClear, function(){ | |
mSearch2.Hash.clear(); | |
$(selectorInput).prop('checked', false); | |
exeFilter(selectorExe); | |
}); | |
//установка фильтров при посещении страницы | |
if( $(selectorExe).length ){ | |
setHashs(); | |
exeFilter(selectorExe); | |
} | |
//фильтрация в каталоге | |
$(document).on('change', selectorInput, function(){ | |
let name = $(this).attr('name'), | |
val = $(this).val(), | |
hashs = mSearch2.Hash.get(), | |
isset = false; | |
//console.log(hashs); | |
for(let k in hashs) { | |
if(k == name && val && $(this).prop('checked')){ | |
isset = true; | |
array = hashs[k].toString().split(','); | |
array.push(val); | |
array = array.filter(item => item != ''); | |
hashs[k] = array.join(); | |
} | |
if(k == name && (!$(this).prop('checked'))){ | |
isset = true; | |
array = hashs[k].toString().split(','); | |
array = array.filter(item => (item != val && item != '')); | |
hashs[k] = array.join(); | |
if(!hashs[k].length){ | |
delete hashs[k]; | |
} | |
} | |
} | |
//console.log(hashs); | |
if(!isset && val && $(this).prop('checked')){ | |
mSearch2.Hash.add(name, val); | |
hashs = mSearch2.Hash.get(); | |
} | |
if(!isset && (!$(this).prop('checked') || val == '')){ | |
mSearch2.Hash.remove(name); | |
hashs = mSearch2.Hash.get(); | |
} | |
mSearch2.Hash.set(hashs); | |
exeFilter(selectorExe); | |
}); | |
//применение фильтра в каталоге | |
$(document).on('click touch', selectorExe, function(e){ | |
e.preventDefault(); | |
exeFilter(selectorExe); | |
}); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
header('Access-Control-Allow-Origin: *'); | |
header('Content-type: application/json; charset=utf-8'); | |
if (!isset($modx)) { | |
define('MODX_API_MODE', true); | |
while (!isset($modx) && ($i = isset($i) ? --$i : 10)) { | |
if (($file = dirname(!empty($file) ? dirname($file) : __FILE__) . '/index.php') AND !file_exists($file)) { | |
continue; | |
} | |
require_once $file; | |
} | |
if (!is_object($modx)) { | |
exit('{"success":false,"message":"Access denied"}'); | |
} | |
$modx->getService('error', 'error.modError'); | |
$modx->getRequest(); | |
$modx->setLogLevel(modX::LOG_LEVEL_ERROR); | |
$modx->setLogTarget('FILE'); | |
$modx->error->message = null; | |
} | |
$ctx = !empty($_REQUEST['ctx']) ? $_REQUEST['ctx'] : $modx->context->get('key'); | |
if ($ctx != $modx->context->get('key')) { | |
$modx->switchContext($ctx); | |
} | |
function Sanitize($input = '', $length = 0){ | |
global $modx; | |
if (is_array($input)) { | |
$output = array(); | |
foreach ($input as $key => $value) { | |
$output[$key] = Sanitize($value, $length); | |
} | |
} else { | |
$expr = $modx->getOption('office_sanitize_pcre', null, '/[^-_0-9\p{L}\s@.,:\/\\+()]+/iu', true); | |
$string = html_entity_decode($input, ENT_QUOTES, 'UTF-8'); | |
$output = trim(preg_replace($expr, '', $string)); | |
return !empty($length) | |
? mb_substr($output, 0, $length, 'UTF-8') | |
: $output; | |
} | |
return $input; | |
}; | |
$data = Sanitize($_POST); | |
$action = $data['action']?:''; | |
$other = $data['other']?:array(); | |
$check = $data['check']?:array(); | |
$is_success = false; | |
unset($data['action'], $data['other']); | |
$output = ''; | |
$count = 0; | |
$suggestion = array(); | |
function setWhere($query, $data, &$suggestion = array()){ | |
global $modx, $ctx; | |
foreach($data as $key => $val){ | |
$val = array_map('trim', explode(',', $val)); | |
switch($key){ | |
case 'parent': | |
$parents = $val; | |
foreach($val as $v){ | |
$parents = array_merge($parents, $modx->getChildIds($v, 10, array('context' => $ctx))); | |
} | |
$exclude = array(1510, 906, 907); | |
foreach($exclude as $v){ | |
$exclude = array_merge($exclude, $modx->getChildIds($v, 10, array('context' => $ctx))); | |
} | |
$parents = array_diff($parents, $exclude); | |
$where = array(); | |
$where[ $key.':IN' ] = $parents; | |
$query->where($where); | |
//$query_all->where($where); | |
break; | |
case 'length': | |
$where = array(); | |
foreach($val as $v){ | |
$where[][ 'OR:'.$key.'.value:LIKE' ] = '%x'.$v.'x%'; | |
$suggestion[$key][$v] = -1; | |
} | |
//$select[] = 'COALESCE(`length`.`value`, 0) as `length`'; | |
$query->where($where); | |
break; | |
case 'load': | |
$where = array(); | |
foreach($val as $v){ | |
$where[][ 'OR:'.$key.'.value:=' ] = $v; | |
$suggestion[$key][$v] = -1; | |
} | |
//$select[] = 'COALESCE(`'.$key.'`.`value`, 0) as `'.$key.'`'; | |
$query->where($where); | |
break; | |
case 'stand': | |
$where = array(); | |
foreach($val as $v){ | |
$where[][ 'OR:'.$key.'.value:=' ] = $v; | |
$suggestion[$key][$v] = -1; | |
if($v == 0){ | |
$where[][ 'OR:'.$key.'.value:IS' ] = NULL; | |
} | |
} | |
//$select[] = 'COALESCE(`'.$key.'`.`value`, 0) as `'.$key.'`'; | |
$query->where($where); | |
break; | |
} | |
} | |
return $query; | |
} | |
switch($action){ | |
case 'suggest': | |
$suggestion_etalon = array(); | |
$query = $modx->newQuery('msProduct', array('class_key:=' => 'msProduct', 'published:=' => 1, 'deleted:=' => 0, 'hidemenu:=' => 0)); | |
$query->leftJoin('msProductOption', 'length', '`length`.`product_id` = `msProduct`.`id` AND `length`.`key` = "size"'); | |
$query->leftJoin('msProductOption', 'load', '`load`.`product_id` = `msProduct`.`id` AND `load`.`key` = "load"'); | |
$query->leftJoin('msProductOption', 'stand', '`stand`.`product_id` = `msProduct`.`id` AND `stand`.`key` = "stand"'); | |
$query->select(array_merge(array( | |
'`msProduct`.`id`' | |
), array( | |
'COALESCE(`length`.`value`, 0) as `length`', | |
'COALESCE(`load`.`value`, 0) as `load`', | |
'COALESCE(`stand`.`value`, 0) as `stand`', | |
))); | |
$query = setWhere($query, $data); | |
if($query->prepare() && $query->stmt->execute()){ | |
if($ids = $query->stmt->fetchAll(PDO::FETCH_ASSOC)){ | |
$count = count($ids); | |
foreach($ids as $item){ | |
if( $item['length'] ){ | |
$output_array = array(); | |
preg_match('/x(?P<length>\d+)x/', $item['length'], $output_array); | |
if($output_array['length']){ | |
$suggestion_etalon['length'][$output_array['length']] = isset($suggestion_etalon['length'][$output_array['length']])?$suggestion_etalon['length'][$output_array['length']]+1:1; | |
} | |
} | |
if( isset($item['load']) ){ | |
$suggestion_etalon['load'][$item['load']] = isset($suggestion_etalon['load'][$item['load']])?$suggestion_etalon['load'][$item['load']]+1:1; | |
} | |
if( isset($item['stand']) ){ | |
$suggestion_etalon['stand'][$item['stand']] = isset($suggestion_etalon['stand'][$item['stand']])?$suggestion_etalon['stand'][$item['stand']]+1:1; | |
} | |
} | |
} | |
} | |
foreach(array_merge($other, $check) as $o){ | |
$prop = $data; | |
$prop[ $o['name'] ] = $o['value']; | |
$query = $modx->newQuery('msProduct', array('class_key:=' => 'msProduct', 'published:=' => 1, 'deleted:=' => 0, 'hidemenu:=' => 0)); | |
$query->leftJoin('msProductOption', 'length', '`length`.`product_id` = `msProduct`.`id` AND `length`.`key` = "size"'); | |
$query->leftJoin('msProductOption', 'load', '`load`.`product_id` = `msProduct`.`id` AND `load`.`key` = "load"'); | |
$query->leftJoin('msProductOption', 'stand', '`stand`.`product_id` = `msProduct`.`id` AND `stand`.`key` = "stand"'); | |
$query->select(array_merge(array( | |
'`msProduct`.`id`' | |
), array( | |
'COALESCE(`length`.`value`, 0) as `length`', | |
'COALESCE(`load`.`value`, 0) as `load`', | |
'COALESCE(`stand`.`value`, 0) as `stand`', | |
))); | |
$query = setWhere($query, $prop); | |
if($query->prepare() && $query->stmt->execute()){ | |
if($ids = $query->stmt->fetchAll(PDO::FETCH_ASSOC)){ | |
$suggestion_etalon[ $o['name'] ][ $o['value'] ] = count($ids); | |
} | |
else $suggestion_etalon[ $o['name'] ][ $o['value'] ] = 0; | |
} | |
else $suggestion_etalon[ $o['name'] ][ $o['value'] ] = 0; | |
} | |
$is_success = true; | |
$suggestion = $suggestion_etalon; | |
break; | |
case 'filter': | |
$where = array(); | |
//$select = array(); | |
$query = $modx->newQuery('msProduct', array('class_key:=' => 'msProduct', 'published:=' => 1, 'deleted:=' => 0, 'hidemenu:=' => 0)); | |
$query->leftJoin('msProductOption', 'length', '`length`.`product_id` = `msProduct`.`id` AND `length`.`key` = "size"'); | |
$query->leftJoin('msProductOption', 'load', '`load`.`product_id` = `msProduct`.`id` AND `load`.`key` = "load"'); | |
$query->leftJoin('msProductOption', 'stand', '`stand`.`product_id` = `msProduct`.`id` AND `stand`.`key` = "stand"'); | |
$query->select(array_merge(array( | |
'`msProduct`.`id`' | |
), array( | |
'COALESCE(`length`.`value`, 0) as `length`', | |
'COALESCE(`load`.`value`, 0) as `load`', | |
'COALESCE(`stand`.`value`, 0) as `stand`', | |
))); | |
$query_all = $modx->newQuery('msProduct', array('class_key' => 'msProduct')); | |
$query_all->leftJoin('msProductOption', 'length', '`length`.`product_id` = `msProduct`.`id` AND `length`.`key` = "size"'); | |
$query_all->leftJoin('msProductOption', 'load', '`load`.`product_id` = `msProduct`.`id` AND `load`.`key` = "load"'); | |
$query_all->leftJoin('msProductOption', 'stand', '`stand`.`product_id` = `msProduct`.`id` AND `stand`.`key` = "stand"'); | |
$query_all->select(array_merge(array( | |
'`msProduct`.`id`' | |
), array( | |
'COALESCE(`length`.`value`, 0) as `length`', | |
'COALESCE(`load`.`value`, 0) as `load`', | |
'COALESCE(`stand`.`value`, 0) as `stand`', | |
))); | |
$query_all = setWhere($query_all, $data); | |
$suggestion_etalon = array(); | |
if($query_all->prepare() && $query_all->stmt->execute()){ | |
if($ids = $query_all->stmt->fetchAll(PDO::FETCH_ASSOC)){ | |
foreach($ids as $item){ | |
if( $item['length'] ){ | |
$output_array = array(); | |
preg_match('/x(?P<length>\d+)x/', $item['length'], $output_array); | |
if($output_array['length']){ | |
$suggestion_etalon['length'][$output_array['length']] = isset($suggestion_etalon['length'][$output_array['length']])?$suggestion_etalon['length'][$output_array['length']]+1:1; | |
} | |
} | |
if( isset($item['load']) ){ | |
$suggestion_etalon['load'][$item['load']] = isset($suggestion_etalon['load'][$item['load']])?$suggestion_etalon['load'][$item['load']]+1:1; | |
} | |
if( isset($item['stand']) ){ | |
$suggestion_etalon['stand'][$item['stand']] = isset($suggestion_etalon['stand'][$item['stand']])?$suggestion_etalon['stand'][$item['stand']]+1:1; | |
} | |
} | |
} | |
} | |
$query = setWhere($query, $data, $suggestion); | |
if($query->prepare() && $query->stmt->execute()){ | |
$is_success = true; | |
if($ids = $query->stmt->fetchAll(PDO::FETCH_ASSOC)){ | |
$count = count($ids); | |
$resources = array(); | |
foreach($ids as $item){ | |
$resources[] = $item['id']; | |
} | |
$message = 'Фильтр применён'; | |
$output = $modx->runSnippet('msProducts', array( | |
'resources' => implode(',', $resources), | |
'parents' => $parents?implode(',', $parents):4, | |
'includeTVs' => 'image', | |
'limit' => 0, | |
'sortby' => 'menuindex', | |
'sortdir' => 'ASC' | |
)); | |
$output .= '<li style="clear:both"></li>'; | |
foreach($other as $o){ | |
$prop = $data; | |
if(isset( $prop[ $o['name'] ] )){ | |
$val = array_map('trim', explode(',', $prop[ $o['name'] ])); | |
$val[] = $o['value']; | |
$prop[ $o['name'] ] = implode(',', $val); | |
} | |
else{ | |
$prop[ $o['name'] ] = $o['value']; | |
} | |
$query = $modx->newQuery('msProduct', array('class_key:=' => 'msProduct', 'published:=' => 1, 'deleted:=' => 0, 'hidemenu:=' => 0)); | |
$query->leftJoin('msProductOption', 'length', '`length`.`product_id` = `msProduct`.`id` AND `length`.`key` = "size"'); | |
$query->leftJoin('msProductOption', 'load', '`load`.`product_id` = `msProduct`.`id` AND `load`.`key` = "load"'); | |
$query->leftJoin('msProductOption', 'stand', '`stand`.`product_id` = `msProduct`.`id` AND `stand`.`key` = "stand"'); | |
$query->select(array_merge(array( | |
'`msProduct`.`id`' | |
), array( | |
'COALESCE(`length`.`value`, 0) as `length`', | |
'COALESCE(`load`.`value`, 0) as `load`', | |
'COALESCE(`stand`.`value`, 0) as `stand`', | |
))); | |
$query = setWhere($query, $prop, $suggestion); | |
if($query->prepare() && $query->stmt->execute()){ | |
if($ids = $query->stmt->fetchAll(PDO::FETCH_ASSOC)){ | |
if(count($ids) > $count){ | |
$suggestion[ $o['name'] ][ $o['value'] ] = count($ids)-$count; | |
} | |
else{ | |
$suggestion[ $o['name'] ][ $o['value'] ] = !$suggestion_etalon[ $o['name'] ][ $o['value'] ]?0:count($ids); | |
} | |
} | |
else{ | |
$suggestion[ $o['name'] ][ $o['value'] ] = 0; | |
} | |
} | |
else{ | |
$suggestion[ $o['name'] ][ $o['value'] ] = 0; | |
} | |
//print_r($prop); | |
} | |
foreach($suggestion as $key => &$sugs){ | |
$tmp = $data; | |
unset($tmp['parent']); | |
foreach($sugs as $p => &$sug){ | |
$prop = array('parent' => $data['parent'], $key => $p); | |
$query = $modx->newQuery('msProduct', array('class_key:=' => 'msProduct', 'published:=' => 1, 'deleted:=' => 0, 'hidemenu:=' => 0)); | |
$query->leftJoin('msProductOption', 'length', '`length`.`product_id` = `msProduct`.`id` AND `length`.`key` = "size"'); | |
$query->leftJoin('msProductOption', 'load', '`load`.`product_id` = `msProduct`.`id` AND `load`.`key` = "load"'); | |
$query->leftJoin('msProductOption', 'stand', '`stand`.`product_id` = `msProduct`.`id` AND `stand`.`key` = "stand"'); | |
$query->select(array_merge(array( | |
'`msProduct`.`id`' | |
), array( | |
'COALESCE(`length`.`value`, 0) as `length`', | |
'COALESCE(`load`.`value`, 0) as `load`', | |
'COALESCE(`stand`.`value`, 0) as `stand`', | |
))); | |
$query = setWhere($query, $prop); | |
if($query->prepare() && $query->stmt->execute()){ | |
if($ids = $query->stmt->fetchAll(PDO::FETCH_ASSOC)){ | |
if(isset($data[$key])){ | |
$val = array_map('trim', explode(',', $data[$key])); | |
if(count($val) > 1 && in_array($p, $val)){ | |
//print_r($p); | |
//$suggestion[ $key ][ $p ] = $suggestion_etalon[ $key ][ $p ]-count($ids)+$suggestion[ $key ][ $p ]; | |
if(count($tmp) == 1){ | |
$suggestion[ $key ][ $p ] = count($ids); | |
} | |
} | |
} | |
//$suggestion[ $key ][ $p ] = count($ids); | |
} | |
else{ | |
$suggestion[ $key ][ $p ] = 0; | |
} | |
} | |
else{ | |
$suggestion[ $key ][ $p ] = 0; | |
} | |
if($sug == -1){ | |
$sug = $count; | |
} | |
} | |
} | |
} | |
} | |
break; | |
} | |
$out = array('success' => $is_success, 'message' => $message?:'Не могу обработать запрос', 'data' => $output, 'suggestion' => $suggestion, 'count' => $count); | |
die(json_encode($out, JSON_FORCE_OBJECT)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment