Доработка хака «Выпадающее меню стран и городов»

Переписал код ajax-запросов. Теперь нет ajax-ошибки. И есть кеш запросов. Работать стало немного быстрее вроде как… Но я сравнивал тока по ощущениям, а они могут быть обманчивы.
Сделано 2 варианта. Для 0.3.1 и для последней SVN. Смотрим, устанавливаем, проверяем, комментим.

Это в profile.tpl
/*##### [hack] country_list #####*/
function country_list_action(){
    var objCountry=$('country_list');
    var objCity=$('city_list');
    var objCityDiv=$('city_list_div');
    var objCountryAjax=$('countryAjax');

    if (objCountry.get('value')=='_full_list_') {
		var params = new Hash();
		params['type']='country';
		params['full']='yes';
		//params['security_ls_key']=LIVESTREET_SECURITY_KEY;
		
		JsHttpRequest.query(
			'POST '+DIR_WEB_ROOT+'/include/ajax/country_list.php',
			params,
			function(result, errors) {  
				if (!result) {
					msgErrorBox.alert(result.sMsgTitle,result.sMsg);           
				}
				if (result.bStateError) {
					msgErrorBox.alert(result.sMsgTitle,result.sMsg);
				} else {
					objCountry.set('html',result.sText);
					objCountry.options[0].selected=true;
				}
				objCountryAjax.setStyle('display','none');
			},
			true
		);
	
        objCountryAjax.setStyle('display','block');
        objCityDiv.setStyle('display','none');
    } else if (objCountry.get('value')!='') {
		var arr=objCountry.getElements('option');
		var cid=''; for(var opt in arr) if(arr[opt].value==objCountry.value) cid=arr[opt].id.substr(3);
		
		var params = new Hash();
		params['cid']=cid;
		params['full']='no';
		//params['security_ls_key']=LIVESTREET_SECURITY_KEY;
		
		JsHttpRequest.query(
			'POST '+DIR_WEB_ROOT+'/include/ajax/country_list.php',
			params,
			function(result, errors) {  
				if (!result) {
					msgErrorBox.alert(result.sMsgTitle,result.sMsg);
					objCityDiv.setStyle('display','none');
				}
				if (result.bStateError) {
					msgErrorBox.alert(result.sMsgTitle,result.sMsg);
					objCityDiv.setStyle('display','none');
				} else {
					objCity.set('html',result.sText);
					objCityDiv.setStyle('display','block');
				}
				objCountryAjax.setStyle('display','none');
			},
			true
		);

		objCountryAjax.setStyle('display','block');
		objCityDiv.setStyle('display','none');
    }else{
		objCountryAjax.setStyle('display','none');
		objCityDiv.setStyle('display','none');
    }
}
function city_list_action(){
    var objCountry=$('country_list');
    var objCity=$('city_list');
    var objCountryAjax=$('countryAjax');
    var objCityDiv=$('city_list_div');

    if(objCity.get('value')=='_full_list_'){
        var arr=objCountry.getElements('option');
        var cid=''; for(var opt in arr) if(arr[opt].value==objCountry.value) cid=arr[opt].id.substr(3);

		var params = new Hash();
		params['type']='city';
		params['cid']=cid;
		params['full']='yes';
		//params['security_ls_key']=LIVESTREET_SECURITY_KEY;
		
		JsHttpRequest.query(
			'POST '+DIR_WEB_ROOT+'/include/ajax/country_list.php',
			params,
			function(result, errors) {  
				if (!result) {
					msgErrorBox.alert(result.sMsgTitle,result.sMsg);
					objCityDiv.setStyle('display','none');
				}
				if (result.bStateError) {
					msgErrorBox.alert(result.sMsgTitle,result.sMsg);
					objCityDiv.setStyle('display','none');
				} else {
					objCity.set('html',result.sText);
                	objCityDiv.setStyle('display','block');
                	objCity.options[0].selected=true;
				}
				objCountryAjax.setStyle('display','none');
			},
			true
		);
		
        objCountryAjax.setStyle('display','block');
		objCityDiv.setStyle('display','none');
    }else if(objCity.get('value')=='_other_name_'){
    	objCityDiv.set('html','<label for="profile_city">{/literal}{$aLang.settings_profile_city}{literal}:</label><br /><input type="text" class="w300" id="profile_city" name="profile_city"/>');
		$('profile_city').focus();
    }
}
document.addEvent('domready',country_list_action);
/*##### [hack] country_list #####*/

Для обладателей последней SVN раскомментить строки где есть LIVESTREET_SECURITY_KEY

Итак. Теперь файл country_list.php
Это для 0.3.1
<?php
##### [hack] country_list #####
$_SERVER['HTTP_REFERER']='http://'.$_SERVER['HTTP_HOST'].'/';
set_include_path(get_include_path().PATH_SEPARATOR.dirname(dirname(dirname(__FILE__))));
$sDirRoot=dirname(dirname(dirname(__FILE__)));
require_once($sDirRoot."/config/config.ajax.php");
header('Content-Type: text/html; charset=utf-8');

$bStateError=true;
$sTextResult='';
$sMsgTitle='';
$sMsg='';
$bVar=true;

if(isset($_POST['type']) && !in_array($_POST['type'],array("country","city"))) $bVar=false;
if(isset($_POST['full']) && !in_array($_POST['full'],array("yes","no"))) $bVar=false;
if(isset($_POST['cid']) && !is_numeric($_POST['cid'])) $bVar=false;
if(isset($_POST['ext']) && !is_numeric($_POST['ext'])) $bVar=false;

if ($bVar) {
	$type=($_POST['type']=="country")?"country":"city";
	$full=($_POST['full']=='no')?0:1;
	$cid=(!isset($_POST['cid']))?0:$_POST['cid'];
	$ext=(!isset($_POST['ext']))?0:$_POST['ext'];
	
	$aLang=$oEngine->Lang_GetLangMsg();
	$oUserCurrent=$oEngine->User_GetUserCurrent();

	if($type=="city" && $cid!=""){
		$bStateError=false;
		
		$userCity=$oUserCurrent->getProfileCity();
		$userCountry=$oUserCurrent->getProfileCountry();

		$aCity=$oEngine->User_GetCityListByCountry($full,$cid,$ext,$userCity);
		$sTextResult.='<option value="">- '.$aLang['settings_profile_city_not_selected'].' -</option>';
		$sel=false; foreach($aCity as $sCity){
			if($userCity==$sCity) $sel=true;
			$selected=($userCity==$sCity)?"selected":"";
			$sTextResult.='<option value="'.$sCity.'" '.$selected.'>'.$sCity.'</option>';
		}
		if($ext==0 && !$sel && $userCity!=""){
			$cidCountry=$oEngine->User_GetCountryNameByCID($cid);
			if($userCountry==$cidCountry) {
				$sTextResult.='<option value="'.$userCity.'" selected>'.$userCity.'</option>';
			}
		}
		if($full==0) $sTextResult.='<option value="_full_list_">- '.$aLang['settings_profile_full_list'].' -</option>';
		elseif($full==1) $sTextResult.='<option value="_other_name_">- '.$aLang['settings_profile_other_name'].' -</option>';
	}elseif($type=="country" && $full==1){
		$bStateError=false;
		
		$userCountry=$oUserCurrent->getProfileCountry();	

		$aCountries=$oEngine->User_GetCountryList(1,$userCountry);
		$sTextResult.='<option value="">- '.$aLang['settings_profile_country_not_selected'].' -</option>';
		foreach($aCountries as $aCountry){
			$selected=($userCountry==$aCountry['name'])?"selected":"";
			$sTextResult.='<option value="'.$aCountry['name'].'" id="cid'.$aCountry['id'].'" '.$selected.'>'.$aCountry['name'].'</option>';
		}
	}
	else {
		$sMsgTitle=$oEngine->Lang_Get('error');
		$sMsg=$oEngine->Lang_Get('error');
	}
}
else {
	$sMsgTitle=$oEngine->Lang_Get('error');
	$sMsg=$oEngine->Lang_Get('error');
}


$GLOBALS['_RESULT'] = array(
"bStateError"     => $bStateError,
"sText"   => $sTextResult,
"iCurCity" => $iCurCity,
"sMsgTitle" => $sMsgTitle,
"sMsg" => $sMsg,
);
?>


Это тот же файл, но для последней SVN
<?php
##### [hack] country_list #####
$_SERVER['HTTP_REFERER']='http://'.$_SERVER['HTTP_HOST'].'/';
set_include_path(get_include_path().PATH_SEPARATOR.dirname(dirname(dirname(__FILE__))));
$sDirRoot=dirname(dirname(dirname(__FILE__)));
require_once($sDirRoot."/config/config.ajax.php");
header('Content-Type: text/html; charset=utf-8');

$bStateError=true;
$sTextResult='';
$sMsgTitle='';
$sMsg='';
$bVar=true;

if(IsPost('type') && !in_array(getRequest('type',null,'post'),array("country","city"))) $bVar=false;
if(IsPost('full') && !in_array(getRequest('full',null,'post'),array("yes","no"))) $bVar=false;
if(IsPost('cid') && !is_numeric(getRequest('cid',null,'post'))) $bVar=false;
if(IsPost('ext') && !is_numeric(getRequest('ext',null,'post'))) $bVar=false;

if ($bVar) {
	$type=(getRequest('type',null,'post')=="country")?"country":"city";
	$full=(getRequest('full',null,'post')=='no')?0:1;
	$cid=(!getRequest('cid',null,'post'))?0:getRequest('cid',null,'post');
	$ext=(!getRequest('ext',null,'post'))?0:getRequest('ext',null,'post');

	$aLang=$oEngine->Lang_GetLangMsg();
	$oUserCurrent=$oEngine->User_GetUserCurrent();

	if($type=="city" && $cid!=""){
		$bStateError=false;
		
		$userCity=$oUserCurrent->getProfileCity();
		$userCountry=$oUserCurrent->getProfileCountry();

		$aCity=$oEngine->User_GetCityListByCountry($full,$cid,$ext,$userCity);
		$sTextResult.='<option value="">- '.$aLang['settings_profile_city_not_selected'].' -</option>';
		$sel=false; foreach($aCity as $sCity){
			if($userCity==$sCity) {
				$sel=true;
			}
			$selected=($userCity==$sCity)?"selected":"";
			$sTextResult.='<option value="'.$sCity.'" '.$selected.'>'.$sCity.'</option>';
		}
		if($ext==0 && !$sel && $userCity!=""){
			$cidCountry=$oEngine->User_GetCountryNameByCID($cid);
			if($userCountry==$cidCountry) {
				$sTextResult.='<option value="'.$userCity.'" selected>'.$userCity.'</option>';
			}
		}
		if($full==0) $sTextResult.='<option value="_full_list_">- '.$aLang['settings_profile_full_list'].' -</option>';
		elseif($full==1) $sTextResult.='<option value="_other_name_">- '.$aLang['settings_profile_other_name'].' -</option>';
	}elseif($type=="country" && $full==1){
		$bStateError=false;
		
		$userCountry=$oUserCurrent->getProfileCountry();	

		$aCountries=$oEngine->User_GetCountryList(1,$userCountry);
		$sTextResult.='<option value="">- '.$aLang['settings_profile_country_not_selected'].' -</option>';
		foreach($aCountries as $aCountry){
			$selected=($userCountry==$aCountry['name'])?"selected":"";
			$sTextResult.='<option value="'.$aCountry['name'].'" id="cid'.$aCountry['id'].'" '.$selected.'>'.$aCountry['name'].'</option>';
		}
	}
	else {
		$sMsgTitle=$oEngine->Lang_Get('error');
		$sMsg=$oEngine->Lang_Get('error');
	}
}
else {
	$sMsgTitle=$oEngine->Lang_Get('error');
	$sMsg=$oEngine->Lang_Get('error');
}


$GLOBALS['_RESULT'] = array(
"bStateError"     => $bStateError,
"sText"   => $sTextResult,
"iCurCity" => $iCurCity,
"sMsgTitle" => $sMsgTitle,
"sMsg" => $sMsg,
);
?>


Ну и кеш. Файл User.class.php
##### [hack] country_list #####
	public function GetCountryList($full,$userCountry=''){
		if (false === ($data = $this->Cache_Get("country_all_{$full}{$userCountry}"))) {				
				$data = $this->oMapper->GetCountryList($full,$userCountry);
				$this->Cache_Set($data, "country_all_{$full}{$userCountry}", array('country_update'), 60*60*24*3);
			}
		return $data;
	}
	public function GetCityListByCountry($full,$cid,$ext,$userCity=''){
		if (false === ($data = $this->Cache_Get("city_by_country_{$cid}_{$full}{$userCity}"))) {				
				$data = $this->oMapper->GetCityListByCountry($full,$cid,$ext,$userCity);
				$this->Cache_Set($data, "city_by_country_{$cid}_{$full}{$userCity}", array('city_update'), 60*60*24*3);
			}
		return $data;
	}
	public function GetCountryNameByCID($cid){
		if (false === ($data = $this->Cache_Get("country_by_{$cid}"))) {				
				$data = $this->oMapper->GetCountryNameByCID($cid);
				$this->Cache_Set($data, "country_by_{$cid}", array('country_update'), 60*60*24*3);
			}
		return $data;
	}
	##### [hack] country_list #####


Вроде всё. Если будут ошибки — пишите. Мб где ошибся при редактировании кода для публикации в топик… у меня помимо последней SVN ещё своих наворотов хватает… Поэтому мог лишнего удалить/недоудалить.
Также не забудьте отписать ваши доработки, если будут таковые

UPD
Найден баг. Исправляется так:
найдите все req.responseText в js и замените на result.sText (в коде, который выше уже исправлено. Это апдейт для тех кто скопировал код с ошибкой)

UPD2
Если последняя SVN
в файле country_list.php
if(IsPost('full') && !is_numeric(getRequest('full',null,'post'))) $bVar=false;
заменить на
if(IsPost('full') && !in_array(getRequest('full',null,'post'),array("yes","no"))) $bVar=false;


$full=(!getRequest('full',null,'post'))?1:getRequest('full',null,'post');
заменить на
$full=(getRequest('full',null,'post')=='no')?0:1;


Если 0.3.1
в файле country_list.php
if(isset($_POST['full']) && !is_numeric($_POST['full']))
заменить на
if(isset($_POST['full']) && !in_array($_POST['full'],array("yes","no")))


$full=(!isset($_POST['full']))?1:$_POST['full'];
заменит на
$full=($_POST['full']=='no')?0:1;

для ВСЕХ
в файле country_list.php
if($type=="city" && $cid!="" && $full!=""){
заменяется на
if($type=="city" && $cid!=""){


в файле profile.tpl
везде где
params['full']=1; 
поставить
params['full']='yes';

и там где
params['full']=0; 
поставить
params['full']='no';


UPD3
Поправил кеширование. Обновите User.class.php
С каждым годом все больше людей пользуются интернетом, это вынуждает компании постепенно расширять свое присутствие во всемирной паутине. Но создание сайтов в Беларуси задача не тривиальная, поэтому рекомендуется сразу обращать к профессионалам web-разработки.

11 комментариев

avatar
Спасибо!
Но кат в посте просто необходим!
avatar
Вечно про него забываю… у меня просто на проекта AutoCut )
avatar
проекте*
avatar
Если так хорошо разбираешься может регионы прикрутишь? Спасибо за доработку.
avatar
У меня на это к сожалению просто нету времени. Стока багов в ToDo-шнике висит, что ппц…
avatar
P.S. Добавьте рейта… до сих пор не могу писать в блог Tips & tricks
по максимуму ;)
avatar
Спс — тема перенесена.
avatar
Исправлена ошибка. Тем кто скопировал код по времени раньше, чем написан этот коммент просьба обновится по UPD
avatar
Большое спасибо, за доработку нашего хака, весьма приятно!
avatar
Подскажите, пожалуйста, как добавить эти селекты в форму регистрации?

простое копирование кода из profile.tpl в ActionRegistration/index.tpl не помогло, как и следовало ожидать
avatar
Для 4 версии будет?
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.