Index: branches/5.2.x/core/kernel/db/db_tag_processor.php
===================================================================
--- branches/5.2.x/core/kernel/db/db_tag_processor.php	(revision 16455)
+++ branches/5.2.x/core/kernel/db/db_tag_processor.php	(revision 16456)
@@ -1,3019 +1,3020 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Portal
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license      GNU/GPL
 * In-Portal is Open Source software.
 * This means that this software may have been modified pursuant
 * the GNU General Public License, and as distributed it includes
 * or is derivative of works licensed under the GNU General Public License
 * or other free or open source software licenses.
 * See http://www.in-portal.org/license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 class kDBTagProcessor extends kTagProcessor {
 
 	/**
 	 * Mapping between "list_name" tag attribute values and generated Specials.
 	 *
 	 * @var array
 	 */
 	protected $nameToSpecialMapping = array();
 
 	/**
 	 * Returns true if "new" button was pressed in toolbar
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function IsNewMode($params)
 	{
 		$object = $this->getObject($params);
 		return $object->GetID() <= 0;
 	}
 
 	/**
 	 * Returns view menu name for current prefix
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function GetItemName($params)
 	{
 		$item_name = $this->Application->getUnitOption($this->Prefix, 'ViewMenuPhrase');
 		return $this->Application->Phrase($item_name);
 	}
 
 	function ViewMenu($params)
 	{
 		$block_params = $params;
 		unset($block_params['block']);
 		$block_params['name'] = $params['block'];
 
 		$list =& $this->GetList($params);
 		$block_params['PrefixSpecial'] = $list->getPrefixSpecial();
 		return $this->Application->ParseBlock($block_params);
 	}
 
 	function SearchKeyword($params)
 	{
 		$list =& $this->GetList($params);
 
 		return $this->Application->RecallVar($list->getPrefixSpecial() . '_search_keyword');
 	}
 
 	/**
 	 * Draw filter menu content (for ViewMenu) based on filters defined in config
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function DrawFilterMenu($params)
 	{
 		$block_params = $this->prepareTagParams($params);
 		$block_params['name'] = $params['spearator_block'];
 		$separator = $this->Application->ParseBlock($block_params);
 		$filter_menu = $this->Application->getUnitOption($this->Prefix,'FilterMenu');
 		if (!$filter_menu) {
 			trigger_error('<span class="debug_error">no filters defined</span> for prefix <b>'.$this->Prefix.'</b>, but <b>DrawFilterMenu</b> tag used', E_USER_NOTICE);
 			return '';
 		}
 
 		// Params: label, filter_action, filter_status
 		$block_params['name'] = $params['item_block'];
 
 		$view_filter = $this->Application->RecallVar($this->getPrefixSpecial().'_view_filter');
 		if ($view_filter === false) {
 			$event_params = Array ('prefix' => $this->Prefix, 'special' => $this->Special, 'name' => 'OnRemoveFilters');
 			$this->Application->HandleEvent( new kEvent($event_params) );
 			$view_filter = $this->Application->RecallVar($this->getPrefixSpecial().'_view_filter');
 		}
 		$view_filter = unserialize($view_filter);
 
 		$filters = Array();
 		$prefix_special = $this->getPrefixSpecial();
 
 		foreach ($filter_menu['Filters'] as $filter_key => $filter_params) {
 			$group_params = isset($filter_params['group_id']) ? $filter_menu['Groups'][ $filter_params['group_id'] ] : Array();
 			if (!isset($group_params['element_type'])) {
 				$group_params['element_type'] = 'checkbox';
 			}
 
 			if (!$filter_params) {
 				$filters[] = $separator;
 				continue;
 			}
 
 			$block_params['label'] = $filter_params['label'];
 
 			if (getArrayValue($view_filter,$filter_key)) {
 				$submit = 0;
 				if (isset($params['old_style'])) {
 					$status = $group_params['element_type'] == 'checkbox' ? 1 : 2;
 				}
 				else {
 					$status = $group_params['element_type'] == 'checkbox' ? '[\'img/check_on.gif\']' : '[\'img/menu_dot.gif\']';
 				}
 			}
 			else {
 				$submit = 1;
 				$status = 'null';
 			}
 			$block_params['filter_action'] = 'set_filter("'.$prefix_special.'","'.$filter_key.'","'.$submit.'",'.$params['ajax'].');';
 			$block_params['filter_status'] = $status; // 1 - checkbox, 2 - radio, 0 - no image
 			$filters[] = $this->Application->ParseBlock($block_params);
 		}
 
 		return implode('', $filters);
 	}
 
 	/**
 	 * Draws auto-refresh submenu in View Menu.
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function DrawAutoRefreshMenu($params)
 	{
 		$refresh_intervals = $this->Application->ConfigValue('AutoRefreshIntervals');
 		if (!$refresh_intervals) {
 			trigger_error('<span class="debug_error">no refresh intervals defined</span> for prefix <strong>'.$this->Prefix.'</strong>, but <strong>DrawAutoRefreshMenu</strong> tag used', E_USER_NOTICE);
 			return '';
 		}
 
 		$refresh_intervals = explode(',', $refresh_intervals);
 		$view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view');
 		$current_refresh_interval = $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_refresh_interval.'.$view_name);
 		if ($current_refresh_interval === false) {
 			// if no interval was selected before, then choose 1st interval
 			$current_refresh_interval = $refresh_intervals[0];
 		}
 
 		$ret = '';
 		$block_params = $this->prepareTagParams($params);
 		$block_params['name'] = $params['render_as'];
 
 		foreach ($refresh_intervals as $refresh_interval) {
 			$block_params['label'] = $this->_formatInterval($refresh_interval);
 			$block_params['refresh_interval'] = $refresh_interval;
 			$block_params['selected'] = $current_refresh_interval == $refresh_interval;
 			$ret .= $this->Application->ParseBlock($block_params);
 		}
 		return $ret;
 	}
 
 	/**
 	 * Tells, that current grid is using auto refresh
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function UseAutoRefresh($params)
 	{
 		$view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view');
 		return $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_auto_refresh.'.$view_name);
 	}
 
 	/**
 	 * Returns current grid refresh interval
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function AutoRefreshInterval($params)
 	{
 		$view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view');
 		return $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_refresh_interval.'.$view_name);
 	}
 
 	/**
 	 * Formats time interval using given text for hours and minutes
 	 *
 	 * @param int $interval minutes
 	 * @param string $hour_text Text for hours
 	 * @param string $min_text Text for minutes
 	 * @return string
 	 */
 	function _formatInterval($interval, $hour_text = 'h', $min_text = 'min')
 	{
 		// 65
 		$minutes = $interval % 60;
 		$hours = ($interval - $minutes) / 60;
 
 		$ret = '';
 		if ($hours) {
 			$ret .= $hours.$hour_text.' ';
 		}
 
 		if ($minutes) {
 			$ret .= $minutes.$min_text;
 		}
 
 		return $ret;
 	}
 
 	function IterateGridFields($params)
 	{
 		$mode = $params['mode'];
 		$def_block = isset($params['block']) ? $params['block'] : '';
 		$force_block = isset($params['force_block']) ? $params['force_block'] : false;
 
 		$grids = $this->Application->getUnitOption($this->Prefix,'Grids');
 		$grid_config = $grids[$params['grid']]['Fields'];
 
 		$picker_helper = new kColumnPickerHelper($this->getPrefixSpecial(), $params['grid']);
 		$grid_config = $picker_helper->apply($grid_config);
 
 		if ($mode == 'fields') {
 			return "'".join("','", array_keys($grid_config))."'";
 		}
 
 		$object =& $this->GetList($params);
 
 		$o = '';
 		$i = 0;
 
 		foreach ($grid_config as $field => $options) {
 			$i++;
 			$block_params = $this->prepareTagParams($params);
 			$block_params = array_merge($block_params, $options);
 
 			$block_params['block_name'] = array_key_exists($mode . '_block', $block_params) ? $block_params[$mode . '_block'] : $def_block;
 			$block_params['name'] = $force_block ? $force_block : $block_params['block_name'];
 			$block_params['field'] = $field;
 			$block_params['sort_field'] = isset($options['sort_field']) ? $options['sort_field'] : $field;
 			$block_params['filter_field'] = isset($options['filter_field']) ? $options['filter_field'] : $field;
 
 			$w = $picker_helper->getWidth($field);
 
 			if ($w) {
 				// column picker width overrides width from unit config
 				$block_params['width'] = $w;
 			}
 
 			$field_options = $object->GetFieldOptions($field);
 			if (array_key_exists('use_phrases', $field_options)) {
 				$block_params['use_phrases'] = $field_options['use_phrases'];
 			}
 
 			$block_params['is_last'] = ($i == count($grid_config));
 
 			$o.= $this->Application->ParseBlock($block_params, 1);
 		}
 
 		return $o;
 	}
 
 	function PickerCRC($params)
 	{
 		$picker_helper = new kColumnPickerHelper($this->getPrefixSpecial(), $params['grid']);
 
 		return $picker_helper->getData()->getChecksum();
 	}
 
 	function FreezerPosition($params)
 	{
 		$picker_helper = new kColumnPickerHelper($this->getPrefixSpecial(), $params['grid']);
 		$data = $picker_helper->getData();
 
 		$freezer_pos = $data->getOrder('__FREEZER__');
 
 		return $freezer_pos === false || $data->isHidden('__FREEZER__') ? 1 : ++$freezer_pos;
 	}
 
 	function GridFieldsCount($params)
 	{
 		$grids = $this->Application->getUnitOption($this->Prefix, 'Grids');
 		$grid_config = $grids[$params['grid']]['Fields'];
 
 		return count($grid_config);
 	}
 
 	/**
 	 * Prints list content using block specified
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function PrintList($params)
 	{
 		$params['no_table'] = 1;
 		return $this->PrintList2($params);
 	}
 
 	function InitList($params)
 	{
 		$list_name = isset($params['list_name']) ? $params['list_name'] : '';
 
 		if ( getArrayValue($this->nameToSpecialMapping, $list_name) === false ) {
 			$list =& $this->GetList($params);
 		}
 	}
 
 	function BuildListSpecial($params)
 	{
 		return $this->Special;
 	}
 
 	/**
 	 * Returns key, that identifies each list on template (used internally, not tag)
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function getUniqueListKey($params)
 	{
 		$types = array_key_exists('types', $params) ? $params['types'] : '';
 		$except = array_key_exists('except', $params) ? $params['except'] : '';
 		$list_name = array_key_exists('list_name', $params) ? $params['list_name'] : '';
 
 		if (!$list_name) {
 			$list_name = $this->Application->Parser->GetParam('list_name');
 		}
 
 		return $types . $except . $list_name;
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param Array $params
 	 * @return kDBList
 	 */
 	function &GetList($params)
 	{
-		$list_name = $this->SelectParam($params, 'list_name,name');
+		$list_name = array_key_exists('list_name', $params) ? $params['list_name'] : '';
+
 		if ( !$list_name ) {
 			$list_name = $this->Application->Parser->GetParam('list_name');
 		}
 
 		$requery = isset($params['requery']) && $params['requery'];
 		$main_list = array_key_exists('main_list', $params) && $params['main_list'];
 
 		if ( $list_name && !$requery ) {
 			// list with "list_name" parameter
 			if ( !array_key_exists($list_name, $this->nameToSpecialMapping) ) {
 				// special missing -> generate one
 				$special = $main_list ? $this->Special : $this->BuildListSpecial($params);
 			}
 			else {
 				// get special, formed during list initialization
 				$special = $this->nameToSpecialMapping[$list_name];
 			}
 		}
 		else {
 			// list without "list_name" parameter
 			$special = $main_list ? $this->Special : $this->BuildListSpecial($params);
 		}
 
 		$prefix_special = rtrim($this->Prefix . '.' . $special, '.');
 		$params['skip_counting'] = true;
 
 		$list = $this->Application->recallObject($prefix_special, $this->Prefix . '_List', $params);
 		/* @var $list kDBList */
 
 		if ( !array_key_exists('skip_quering', $params) || !$params['skip_quering'] ) {
 			if ( $requery ) {
 				$this->Application->HandleEvent(new kEvent($prefix_special . ':OnListBuild', $params));
 			}
 
 			if ( array_key_exists('offset', $params) ) {
 				$list->SetOffset($list->GetOffset() + $params['offset']); // apply custom offset
 			}
 
 			$list->Query($requery);
 
 			if ( array_key_exists('offset', $params) ) {
 				$list->SetOffset($list->GetOffset() - $params['offset']); // remove custom offset
 			}
 		}
 
 		$this->Init($this->Prefix, $special);
 
 		if ( $list_name ) {
 			$this->nameToSpecialMapping[$list_name] = $special;
 		}
 
 		return $list;
 	}
 
 	function ListMarker($params)
 	{
 		$list =& $this->GetList($params);
 		$ret = $list->getPrefixSpecial();
 
 		if (array_key_exists('as_preg', $params) && $params['as_preg']) {
 			$ret = preg_quote($ret, '/');
 		}
 
 		return $ret;
 	}
 
 	function CombinedSortingDropDownName($params)
 	{
 		$list =& $this->GetList($params);
 
 		return $list->getPrefixSpecial() . '_CombinedSorting';
 	}
 
 	/**
 	 * Prepares name for field with event in it (used only on front-end)
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function SubmitName($params)
 	{
 		$list =& $this->GetList($params);
 
 		$prefix_special = $list->getPrefixSpecial();
 
 		return 'events[' . $prefix_special . '][' . $params['event'] . ']';
 	}
 
 	/**
 	 * Prints list content using block specified
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function PrintList2($params)
 	{
 		$per_page = $this->SelectParam($params, 'per_page,max_items');
 		if ( $per_page !== false ) {
 			$params['per_page'] = $per_page;
 		}
 
 		$list =& $this->GetList($params);
 		$o = '';
 
 		$direction = (isset($params['direction']) && $params['direction'] == "H") ? "H" : "V";
 		$columns = (isset($params['columns'])) ? $params['columns'] : 1;
 
 		$id_field = (isset($params['id_field'])) ? $params['id_field'] : $this->Application->getUnitOption($this->Prefix, 'IDField');
 
 		if ( $columns > 1 && $direction == 'V' ) {
 			$records_left = array_splice($list->Records, $list->GetSelectedCount()); // because we have 1 more record for "More..." link detection (don't need to sort it)
 			$list->Records = $this->LinearToVertical($list->Records, $columns, $list->GetPerPage());
 			$list->Records = array_merge($list->Records, $records_left);
 		}
 
 		$list->GoFirst();
 
 		$block_params = $this->prepareTagParams($params);
 		$block_params['name'] = $this->SelectParam($params, 'render_as,block');
 		$block_params['pass_params'] = 'true';
 		$block_params['column_width'] = $params['column_width'] = 100 / $columns;
 		$block_start_row_params = $this->prepareTagParams($params);
 		$block_start_row_params['name'] = $this->SelectParam($params, 'row_start_render_as,block_row_start,row_start_block');
 
 		$block_end_row_params = $this->prepareTagParams($params);
 		$block_end_row_params['name'] = $this->SelectParam($params, 'row_end_render_as,block_row_end,row_end_block');
 
 		$block_empty_cell_params = $this->prepareTagParams($params);
 		$block_empty_cell_params['name'] = $this->SelectParam($params, 'empty_cell_render_as,block_empty_cell,empty_cell_block');
 
 		$i = 0;
 
 		$backup_id = $this->Application->GetVar($this->Prefix . '_id');
 		$displayed = Array ();
 		$column_number = 1;
 
 		$cache_mod_rw = $this->Application->getUnitOption($this->Prefix, 'CacheModRewrite') &&
 						$this->Application->RewriteURLs() && !$this->Application->isCachingType(CACHING_TYPE_MEMORY);
 
 		$limit = isset($params['limit']) ? $params['limit'] : false;
 
 		while (!$list->EOL() && (!$limit || $i<$limit)) {
 			$this->Application->SetVar($this->getPrefixSpecial() . '_id', $list->GetDBField($id_field)); // for edit/delete links using GET
 			$this->Application->SetVar($this->Prefix . '_id', $list->GetDBField($id_field));
 			$block_params['is_last'] = ($i == $list->GetSelectedCount() - 1);
 			$block_params['last_row'] = ($i + (($i + 1) % $columns) >= $list->GetSelectedCount() - 1);
 			$block_params['not_last'] = !$block_params['is_last']; // for front-end
 
 			if ( $cache_mod_rw ) {
 				$serial_name = $this->Application->incrementCacheSerial($this->Prefix, $list->GetDBField($id_field), false);
 
 				if ( $this->Prefix == 'c' ) {
 					// for listing subcategories in category
 					$this->Application->setCache('filenames[%' . $serial_name . '%]', $list->GetDBField('NamedParentPath'));
 					$this->Application->setCache('category_tree[%CIDSerial:' . $list->GetDBField($id_field) . '%]', $list->GetDBField('TreeLeft') . ';' . $list->GetDBField('TreeRight'));
 				}
 				else {
 					// for listing items in category
 					$this->Application->setCache('filenames[%' . $serial_name . '%]', $list->GetDBField('Filename'));
 
 					$serial_name = $this->Application->incrementCacheSerial('c', $list->GetDBField('CategoryId'), false);
 					$this->Application->setCache('filenames[%' . $serial_name . '%]', $list->GetDBField('CategoryFilename'));
 				}
 			}
 
 			if ( $i % $columns == 0 ) {
 				// record in this iteration is first in row, then open row
 				$column_number = 1;
 				$o .= $block_start_row_params['name'] ? $this->Application->ParseBlock($block_start_row_params) : (!isset($params['no_table']) ? '<tr>' : '');
 			}
 			else {
 				$column_number++;
 			}
 
 			$block_params['first_col'] = $column_number == 1 ? 1 : 0;
 			$block_params['last_col'] = $column_number == $columns ? 1 : 0;
 
 			$block_params['column_number'] = $column_number;
 			$block_params['num'] = ($i + 1);
 
 			$this->PrepareListElementParams($list, $block_params); // new, no need to rewrite PrintList
 			$o .= $this->Application->ParseBlock($block_params);
 			array_push($displayed, $list->GetDBField($id_field));
 
 			if ( $direction == 'V' && $list->GetSelectedCount() % $columns > 0 && $column_number == ($columns - 1) && ceil(($i + 1) / $columns) > $list->GetSelectedCount() % ceil($list->GetSelectedCount() / $columns) ) {
 				// if vertical output, then draw empty cells vertically, not horizontally
 				$o .= $block_empty_cell_params['name'] ? $this->Application->ParseBlock($block_empty_cell_params) : '<td>&nbsp;</td>';
 				$i++;
 			}
 
 			if ( ($i + 1) % $columns == 0 ) {
 				// record in next iteration is first in row too, then close this row
 				$o .= $block_end_row_params['name'] ? $this->Application->ParseBlock($block_end_row_params) : (!isset($params['no_table']) ? '</tr>' : '');
 			}
 
 			if ( $this->Special && $this->Application->hasObject($this->Prefix) ) {
 				// object, produced by "kDBList::linkToParent" method, that otherwise would keep it's id
 				$item = $this->Application->recallObject($this->Prefix);
 				/* @var $item kDBBase */
 
 				if ( $item instanceof kDBItem ) {
 					$this->Application->removeObject($this->Prefix);
 				}
 			}
 
 			$list->GoNext();
 			$i++;
 		}
 
 		// append empty cells in place of missing cells in last row
 		while ($i % $columns != 0) {
 			// until next cell will be in new row append empty cells
 			$o .= $block_empty_cell_params['name'] ? $this->Application->ParseBlock($block_empty_cell_params) : '<td>&nbsp;</td>';
 
 			if ( ($i + 1) % $columns == 0 ) {
 				// record in next iteration is first in row too, then close this row
 				$o .= $block_end_row_params['name'] ? $this->Application->ParseBlock($block_end_row_params) : '</tr>';
 			}
 			$i++;
 		}
 
 		$cur_displayed = $this->Application->GetVar($this->Prefix . '_displayed_ids');
 		if ( !$cur_displayed ) {
 			$cur_displayed = Array ();
 		}
 		else {
 			$cur_displayed = explode(',', $cur_displayed);
 		}
 
 		$displayed = array_unique(array_merge($displayed, $cur_displayed));
 		$this->Application->SetVar($this->Prefix . '_displayed_ids', implode(',', $displayed));
 
 		$this->Application->SetVar($this->Prefix . '_id', $backup_id);
 		$this->Application->SetVar($this->getPrefixSpecial() . '_id', '');
 
 		if ( isset($params['more_link_render_as']) ) {
 			$block_params = $params;
 			$params['render_as'] = $params['more_link_render_as'];
 			$o .= $this->MoreLink($params);
 		}
 
 		return $o;
 	}
 
 	/**
 	 * Returns ID of previous record (related to current) in list.
 	 * Use only on item detail pages.
 	 *
 	 * @param Array $params
 	 * @return int
 	 * @access protected
 	 */
 	protected function PreviousResource($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$list_helper = $this->Application->recallObject('ListHelper');
 		/* @var $list_helper ListHelper */
 
 		$select_clause = $this->Application->getUnitOption($object->Prefix, 'NavigationSelectClause', null);
 
 		return $list_helper->getNavigationResource($object, $params['list'], false, $select_clause);
 	}
 
 	/**
 	 * Returns ID of next record (related to current) in list.
 	 * Use only on item detail pages.
 	 *
 	 * @param Array $params
 	 * @return int
 	 * @access protected
 	 */
 	protected function NextResource($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$list_helper = $this->Application->recallObject('ListHelper');
 		/* @var $list_helper ListHelper */
 
 		$select_clause = $this->Application->getUnitOption($object->Prefix, 'NavigationSelectClause', null);
 
 		return $list_helper->getNavigationResource($object, $params['list'], true, $select_clause);
 	}
 
 	/**
 	 * Allows to modify block params & current list record before PrintList parses record
 	 *
 	 * @param kDBList $object
 	 * @param Array $block_params
 	 * @return void
 	 * @access protected
 	 */
 	protected function PrepareListElementParams(&$object, &$block_params)
 	{
 //		$fields_hash =& $object->getCurrentRecord();
 
 	}
 
 	/**
 	 * Renders given block name, when there there is more data in list, then are displayed right now
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function MoreLink($params)
 	{
 		$per_page = $this->SelectParam($params, 'per_page,max_items');
 
 		if ( $per_page !== false ) {
 			$params['per_page'] = $per_page;
 		}
 
 		$list =& $this->GetList($params);
 
 		if ( $list->isCounted() ) {
 			$has_next_page = $list->GetPage() < $list->GetTotalPages();
 		}
 		else {
 			// selected more, then on the page -> has more
 			$has_next_page = $list->GetPerPage() < $list->GetRecordsCount();
 		}
 
 		if ( $has_next_page ) {
 			$block_params = Array ('name' => $this->SelectParam($params, 'render_as,block'));
 
 			return $this->Application->ParseBlock($block_params);
 		}
 
 		return '';
 	}
 
 	function PageLink($params)
 	{
 		static $default_per_page = Array ();
 
 		$object =& $this->GetList($params);
 		/* @var $object kDBList */
 
 		// process sorting
 		if ($object->isMainList()) {
 			if (!array_key_exists('sort_by', $params)) {
 				$sort_by = $this->Application->GetVar('sort_by');
 
 				if ($sort_by !== false) {
 					$params['sort_by'] = $sort_by;
 				}
 			}
 		}
 
 		$prefix_special = $this->getPrefixSpecial();
 
 		// process page
 		$page = array_key_exists('page', $params) ? $params['page'] : $this->Application->GetVar($prefix_special . '_Page');
 
 		if (!$page) {
 			// ensure, that page is always present
 			if ($object->isMainList()) {
 				$params[$prefix_special . '_Page'] = $this->Application->GetVar('page', 1);
 			}
 			else {
 				$params[$prefix_special . '_Page'] = 1;
 			}
 		}
 
 		if (array_key_exists('page', $params)) {
 			$params[$prefix_special . '_Page'] = $params['page'];
 			unset($params['page']);
 		}
 
 		// process per-page
 		$per_page = array_key_exists('per_page', $params) ? $params['per_page'] : $this->Application->GetVar($prefix_special . '_PerPage');
 
 		if (!$per_page) {
 			// ensure, that per-page is always present
 			list ($prefix, ) = explode('.', $prefix_special);
 
 			if (!array_key_exists($prefix, $default_per_page)) {
 				$list_helper = $this->Application->recallObject('ListHelper');
 				/* @var $list_helper ListHelper */
 
 				$default_per_page[$prefix] = $list_helper->getDefaultPerPage($prefix);
 			}
 
 			if ($object->isMainList()) {
 				$params[$prefix_special . '_PerPage'] = $this->Application->GetVar('per_page', $default_per_page[$prefix]);
 			}
 			else {
 				$params[$prefix_special . '_PerPage'] = $default_per_page[$prefix];
 			}
 		}
 
 		if (array_key_exists('per_page', $params)) {
 			$params[$prefix_special . '_PerPage'] = $params['per_page'];
 			unset($params['per_page']);
 		}
 
 		if (!array_key_exists('pass', $params)) {
 			$params['pass'] = 'm,' . $prefix_special;
 		}
 
 		// process template
 		$t = array_key_exists('template', $params) ? $params['template'] : '';
 		unset($params['template']);
 
 		if (!$t) {
 			$t = $this->Application->GetVar('t');
 		}
 
 		return $this->Application->HREF($t, '', $params);
 	}
 
 	/**
 	 * Deprecated
 	 *
 	 * @param array $params
 	 * @return int
 	 * @deprecated Parameter "column_width" of "PrintList" tag does that
 	 */
 	function ColumnWidth($params)
 	{
 		$columns = $this->Application->Parser->GetParam('columns');
 
 		return round(100/$columns).'%';
 	}
 
 	/**
 	 * Append prefix and special to tag
 	 * params (get them from tagname) like
 	 * they were really passed as params
 	 *
 	 * @param Array $tag_params
 	 * @return Array
 	 * @access protected
 	 */
 	function prepareTagParams($tag_params = Array())
 	{
 		$ret = $tag_params;
 		$ret['Prefix'] = $this->Prefix;
 		$ret['Special'] = $this->Special;
 		$ret['PrefixSpecial'] = $this->getPrefixSpecial();
 		return $ret;
 	}
 
 	function GetISO($currency, $field_currency = '')
 	{
 		if ( $currency == 'selected' ) {
 			return $this->Application->RecallVar('curr_iso');
 		}
 
 		if ( $currency == 'primary' || $currency == '' ) {
 			return $this->Application->GetPrimaryCurrency();
 		}
 
 		// explicit currency
 		return $currency == 'field' && $field_currency ? $field_currency : $currency;
 	}
 
 	/**
 	 * Convert primary currency to selected (if they are the same, converter will just return)
 	 *
 	 * @param float $value
 	 * @param string $target_iso
 	 * @param string $source_iso
 	 * @return float
 	 */
 	function ConvertCurrency($value, $target_iso, $source_iso = 'PRIMARY')
 	{
 		$converter = $this->Application->recallObject('CurrencyRates');
 		/* @var $converter CurrencyRates */
 
 		return $converter->Convert($value, $source_iso, $target_iso);
 	}
 
 	function AddCurrencySymbol($value, $iso, $decimal_tag = '')
 	{
 		$converter = $this->Application->recallObject('CurrencyRates');
 		/* @var $converter CurrencyRates */
 
 		return $converter->AddCurrencySymbol($value, $iso, $decimal_tag);
 	}
 
 	/**
 	 * Get's requested field value
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function Field($params)
 	{
 		$field = $this->SelectParam($params, 'name,field');
 
 		if (!$this->Application->isAdmin) {
 			// don't apply kUtil::escape() on any field value on Front-End
 			$params['no_special'] = 'no_special';
 		}
 
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		if (array_key_exists('db', $params) && $params['db']) {
 			$value = $object->GetDBField($field);
 		}
 		else {
 			if (array_key_exists('currency', $params) && $params['currency']) {
 				$source_iso = isset($params['currency_field']) ? $object->GetDBField($params['currency_field']) : 'PRIMARY';
 				$target_iso = $this->GetISO($params['currency'], $source_iso);
 				$original = $object->GetDBField($field);
 
 				$value = $this->ConvertCurrency($original, $target_iso, $source_iso);
 
 				$object->SetDBField($field, $value);
 				$object->SetFieldOption($field, 'converted', true);
 			}
 
 			$format = array_key_exists('format', $params) ? $params['format'] : false;
 			if (!$format || $format == '$format') {
 				$format = NULL;
 			}
 
 			$value = $object->GetField($field, $format);
 
 			if (array_key_exists('negative', $params) && $params['negative']) {
 				if (strpos($value, '-') === 0) {
 					$value = substr($value, 1);
 				}
 				else {
 					$value = '-' . $value;
 				}
 			}
 
 			if (array_key_exists('currency', $params) && $params['currency']) {
 				$decimal_tag = isset($params['decimal_tag']) ? $params['decimal_tag'] : '';
 				$value = $this->AddCurrencySymbol($value, $target_iso, $decimal_tag);
 				$params['no_special'] = 1;
 			}
 		}
 
 		if (!array_key_exists('no_special', $params) || !$params['no_special']) {
 			$value = kUtil::escape($value);
 		}
 
 		if (array_key_exists('checked', $params) && $params['checked']) {
 			$value = ($value == ( isset($params['value']) ? $params['value'] : 1)) ? 'checked' : '';
 		}
 
 		if (array_key_exists('plus_or_as_label', $params) && $params['plus_or_as_label']) {
 			$value = substr($value, 0,1) == '+' ? substr($value, 1) : $this->Application->Phrase($value);
 		}
 		elseif (array_key_exists('as_label', $params) && $params['as_label']) {
 			$value = $this->Application->Phrase($value);
 		}
 
 		$first_chars = $this->SelectParam($params,'first_chars,cut_first');
 
 		if ($first_chars) {
 			$stripped_value = strip_tags($value, $this->SelectParam($params, 'allowed_tags'));
 
 			if ( mb_strlen($stripped_value) > $first_chars ) {
 				$value = preg_replace('/\s+?(\S+)?$/', '', mb_substr($stripped_value, 0, $first_chars + 1)) . ' ...';
 			}
 		}
 
 		if (array_key_exists('nl2br', $params) && $params['nl2br']) {
 			$value = nl2br($value);
 		}
 
 		if ($value != '') {
 			$this->Application->Parser->DataExists = true;
 		}
 
 		if (array_key_exists('currency', $params) && $params['currency']) {
 			// restoring value in original currency, for other Field tags to work properly
 			$object->SetDBField($field, $original);
 		}
 
 		return $value;
 	}
 
 	function FieldHintLabel($params)
 	{
 		if ( isset($params['direct_label']) && $params['direct_label'] ) {
 			$label = $params['direct_label'];
 			$hint = $this->Application->Phrase($label, false);
 		}
 		else {
 			$label = $params['title_label'];
 			$hint = $this->Application->Phrase('hint:' . $label, false);
 		}
 
 		return $hint != strtoupper('!' . $label . '!') ? $hint : ''; // $hint
 	}
 
 	/**
 	 * Returns formatted date + time on current language
 	 *
 	 * @param $params
 	 */
 	function DateField($params)
 	{
 		$field = $this->SelectParam($params, 'name,field');
 
 		if ($field) {
 			$object = $this->getObject($params);
 			/* @var $object kDBItem */
 
 			$timestamp = $object->GetDBField($field);
 		}
 		else {
 			$timestamp = $params['value'];
 		}
 
 		$date = $timestamp;
 
 		// prepare phrase replacements
 		$replacements = Array (
 			'l' => 'la_WeekDay',
 			'D' => 'la_WeekDay',
 			'M' => 'la_Month',
 			'F' => 'la_Month',
 		);
 
 		// cases allow to append phrase suffix based on requested case (e.g. Genitive)
 		$case_suffixes = array_key_exists('case_suffixes', $params) ? $params['case_suffixes'] : false;
 
 		if ($case_suffixes) {
 			// apply case suffixes (for russian language only)
 			$case_suffixes = explode(',', $case_suffixes);
 
 			foreach ($case_suffixes as $case_suffux) {
 				list ($replacement_name, $case_suffix_value) = explode('=', $case_suffux, 2);
 				$replacements[$replacement_name] .= $case_suffix_value;
 			}
 		}
 
 		$format = array_key_exists('format', $params) ? $params['format'] : false;
 
 		if (preg_match('/_regional_(.*)/', $format, $regs)) {
 			$language = $this->Application->recallObject('lang.current');
 			/* @var $language kDBItem */
 
 			$format = $language->GetDBField($regs[1]);
 		}
 		elseif (!$format) {
 			$format = null;
 		}
 
 		// escape formats, that are resolved to words by adodb_date
 		foreach ($replacements as $format_char => $phrase_prefix) {
 			if (strpos($format, $format_char) === false) {
 				unset($replacements[$format_char]);
 				continue;
 			}
 
 			$replacements[$format_char] = $this->Application->Phrase($phrase_prefix . adodb_date($format_char, $date));
 			$format = str_replace($format_char, '#' . ord($format_char) . '#', $format);
 		}
 
 		$date_formatted = adodb_date($format, $date);
 
 		// unescape formats, that are resolved to words by adodb_date
 		foreach ($replacements as $format_char => $format_replacement) {
 			$date_formatted = str_replace('#' . ord($format_char) . '#', $format_replacement, $date_formatted);
 		}
 
 		return $date_formatted;
 	}
 
 	function SetField($params)
 	{
 		// <inp2:SetField field="Value" src=p:cust_{$custom_name}"/>
 
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$dst_field = $this->SelectParam($params, 'name,field');
 		list($prefix_special, $src_field) = explode(':', $params['src']);
 
 		$src_object = $this->Application->recallObject($prefix_special);
 		/* @var $src_object kDBItem */
 
 		$object->SetDBField($dst_field, $src_object->GetDBField($src_field));
 	}
 
 	/**
 	 * Depricated
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @deprecated parameter "as_label" of "Field" tag does the same
 	 */
 	function PhraseField($params)
 	{
 		$field_label = $this->Field($params);
 		$translation = $this->Application->Phrase( $field_label );
 		return $translation;
 	}
 
 	function Error($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$field = $this->SelectParam($params, 'name,field');
 
 		return $object->GetErrorMsg($field, false);
 	}
 
 	function HasError($params)
 	{
 		if ($params['field'] == 'any') {
 			$object = $this->getObject($params);
 			/* @var $object kDBItem */
 
 			$skip_fields = array_key_exists('except', $params) ? $params['except'] : false;
 			$skip_fields = $skip_fields ? explode(',', $skip_fields) : Array();
 
 			return $object->HasErrors($skip_fields);
 		}
 		else {
 			$res = false;
 			$fields = explode(',', $this->SelectParam($params, 'field,fields'));
 
 			foreach ($fields as $field) {
 				// call kDBTagProcessor::Error instead of kDBItem::GetErrorPseudo to have ability to override Error tag
 				$params['field'] = $field;
 				$res = $res || ($this->Error($params) != '');
 			}
 
 			return $res;
 		}
 	}
 
 	/**
 	 * Renders error message block, when there are errors on a form
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function ErrorWarning($params)
 	{
 		if ( !isset($params['field']) ) {
 			$params['field'] = 'any';
 		}
 
 		if ( $this->HasError($params) ) {
 			$params['prefix'] = $this->getPrefixSpecial();
 
 			return $this->Application->ParseBlock($params);
 		}
 
 		return '';
 	}
 
 	function IsRequired($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$field = $params['field'];
 		$formatter_class = $object->GetFieldOption($field, 'formatter');
 
 		if ( $formatter_class == 'kMultiLanguage' ) {
 			$formatter = $this->Application->recallObject($formatter_class);
 			/* @var $formatter kMultiLanguage */
 
 			$field = $formatter->LangFieldName($field);
 		}
 
 		return $object->isRequired($field);
 	}
 
 	function FieldOption($params)
 	{
 		$object = $this->getObject($params);;
 		$options = $object->GetFieldOptions($params['field']);
 		$ret =  isset($options[$params['option']]) ? $options[$params['option']] : '';
 		if (isset($params['as_label']) && $params['as_label']) $ret = $this->Application->ReplaceLanguageTags($ret);
 		return $ret;
 	}
 
 	/**
 	 * Prints list a all possible field options
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function PredefinedOptions($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBList */
 
 		$field = $params['field'];
 		$value = array_key_exists('value', $params) ? $params['value'] : $object->GetDBField($field);
 		$field_options = $object->GetFieldOptions($field);
 		if (!array_key_exists('options', $field_options) || !is_array($field_options['options'])) {
 			trigger_error('Options not defined for <strong>'.$object->Prefix.'</strong> field <strong>'.$field.'</strong>', E_USER_WARNING);
 			return '';
 		}
 
 		$options = $field_options['options'];
 
 		if ( array_key_exists('has_empty', $params) && $params['has_empty'] ) {
 			$empty_value = array_key_exists('empty_value', $params) ? $params['empty_value'] : '';
 			$empty_label = isset($params['empty_label']) ? $params['empty_label'] : '';
 
 			if ( $empty_label ) {
 				if ( mb_substr($empty_label, 0, 1) == '+' ) {
 					// using plain text instead of phrase label
 					$empty_label = mb_substr($empty_label, 1);
 				}
 				else {
 					$empty_label = $this->Application->Phrase($empty_label, false);
 				}
 			}
 
 			// don't use other array merge function, because they will reset keys !!!
 			$options = kUtil::array_merge_recursive(Array ($empty_value => $empty_label), $options);
 		}
 
 		$block_params = $this->prepareTagParams($params);
 		$block_params['name'] = $this->SelectParam($params, 'render_as,block');
 		$block_params['pass_params'] = 'true';
 		if (method_exists($object, 'EOL') && count($object->Records) == 0) {
 			// for drawing grid column filter
 			$block_params['field_name'] = '';
 		}
 		else {
 			$block_params['field_name'] = $this->InputName($params); // depricated (produces warning when used as grid filter), but used in Front-End (submission create), admin (submission view)
 		}
 
 		$selected_param_name = array_key_exists('selected_param', $params) ? $params['selected_param'] : false;
 		if (!$selected_param_name) {
 			$selected_param_name = $params['selected'];
 		}
 		$selected = $params['selected'];
 
 		$o = '';
 		if (array_key_exists('no_empty', $params) && $params['no_empty'] && !getArrayValue($options, '')) {
 			// removes empty option, when present (needed?)
 			array_shift($options);
 		}
 
 		$index = 0;
 		$option_count = count($options);
 
 		if (strpos($value, '|') !== false) {
 			// multiple checkboxes OR multiselect
 			$value = explode('|', substr($value, 1, -1) );
 			foreach ($options as $key => $val) {
 				$block_params['key'] = $key;
 				$block_params['option'] = $val;
 				$block_params[$selected_param_name] = ( in_array($key, $value) ? ' '.$selected : '');
 				$block_params['is_last'] = $index == $option_count - 1;
 				$o .= $this->Application->ParseBlock($block_params);
 
 				$index++;
 			}
 		}
 		else {
 			// single selection radio OR checkboxes OR dropdown
 			foreach ($options as $key => $val) {
 				$block_params['key'] = $key;
 				$block_params['option'] = $val;
 				$block_params[$selected_param_name] = (strlen($key) == strlen($value) && ($key == $value) ? ' '.$selected : '');
 				$block_params['is_last'] = $index == $option_count - 1;
 				$o .= $this->Application->ParseBlock($block_params);
 
 				$index++;
 			}
 		}
 		return $o;
 	}
 
 	function PredefinedSearchOptions($params)
 	{
 		$object =& $this->GetList($params);
 		/* @var $object kDBList */
 
 		$params['value'] = $this->SearchField($params);
 
 		return $this->PredefinedOptions($params);
 	}
 
 	function Format($params, $object = null)
 	{
 		$field = $this->SelectParam($params, 'name,field');
 
         if ( !isset($object) ) {
             $object = $this->getObject($params);
             /* @var $object kDBItem */
         }
 
         $options = $object->GetFieldOptions($field);
 		$format = $options[$this->SelectParam($params, 'input_format') ? 'input_format' : 'format'];
 		$formatter_class = array_key_exists('formatter', $options) ? $options['formatter'] : false;
 
 		if ( $formatter_class ) {
 			$formatter = $this->Application->recallObject($formatter_class);
 			/* @var $formatter kFormatter */
 
 			$human_format = array_key_exists('human', $params) ? $params['human'] : false;
 			$edit_size = array_key_exists('edit_size', $params) ? $params['edit_size'] : false;
 			$sample = array_key_exists('sample', $params) ? $params['sample'] : false;
 
 			if ( $sample ) {
 				return $formatter->GetSample($field, $options, $object);
 			}
 			elseif ( $human_format || $edit_size ) {
 				$format = $formatter->HumanFormat($format);
 
 				return $edit_size ? strlen($format) : $format;
 			}
 		}
 
 		return $format;
 	}
 
 	/**
 	 * Returns grid padination information
 	 * Can return links to pages
 	 *
 	 * @param Array $params
 	 * @return mixed
 	 */
 	function PageInfo($params)
 	{
 		$object =& $this->GetList($params);
 		/* @var $object kDBList */
 
 		$type = $params['type'];
 		unset($params['type']); // remove parameters used only by current tag
 
 		$ret = '';
 		switch ($type) {
 			case 'current':
 				$ret = $object->GetPage();
 				break;
 
 			case 'total':
 				$ret = $object->GetTotalPages();
 				break;
 
 			case 'prev':
 				$ret = $object->GetPage() > 1 ? $object->GetPage() - 1 : false;
 				break;
 
 			case 'next':
 				$ret = $object->GetPage() < $object->GetTotalPages() ? $object->GetPage() + 1 : false;
 				break;
 		}
 
 		if ($ret && isset($params['as_link']) && $params['as_link']) {
 			unset($params['as_link']); // remove parameters used only by current tag
 			$params['page']	= $ret;
 			$current_page = $object->GetPage(); // backup current page
 			$ret = $this->PageLink($params);
 			$this->Application->SetVar($object->getPrefixSpecial().'_Page', $current_page); // restore page
 		}
 
 		return $ret;
 	}
 
 	/**
 	 * Print grid pagination using
 	 * block names specified
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function PrintPages($params)
 	{
 		$list =& $this->GetList($params);
 		$prefix_special = $list->getPrefixSpecial();
 		$total_pages = $list->GetTotalPages();
 
 		if ( $total_pages > 1 ) {
 			$this->Application->Parser->DataExists = true;
 		}
 
 		if ( $total_pages == 0 ) {
 			// display 1st page as selected in case if we have no pages at all
 			$total_pages = 1;
 		}
 
 		$o = '';
 
 		// what are these 2 lines for?
 		$this->Application->SetVar($prefix_special . '_event', '');
 		$this->Application->SetVar($prefix_special . '_id', '');
 
 		$current_page = $list->GetPage(); //  $this->Application->RecallVar($prefix_special.'_Page');
 
 		$block_params = $this->prepareTagParams($params);
 
 		$split = (isset($params['split']) ? $params['split'] : 10);
 		$split_start = $current_page - ceil($split / 2);
 
 		if ( $split_start < 1 ) {
 			$split_start = 1;
 		}
 
 		$split_end = $split_start + $split - 1;
 
 		if ( $split_end > $total_pages ) {
 			$split_end = $total_pages;
 			$split_start = max($split_end - $split + 1, 1);
 		}
 
 		if ( $current_page > 1 ) {
 			$prev_block_params = $this->prepareTagParams($params);
 
 			if ( $total_pages > $split ) {
 				$prev_block_params['page'] = max($current_page - $split, 1);
 				$prev_block_params['name'] = $this->SelectParam($params, 'prev_page_split_render_as,prev_page_split_block');
 
 				if ( $prev_block_params['name'] ) {
 					$this->Application->SetVar($this->getPrefixSpecial() . '_Page', $prev_block_params['page']);
 					$o .= $this->Application->ParseBlock($prev_block_params);
 				}
 			}
 
 			$prev_block_params['name'] = 'page';
 			$prev_block_params['page'] = $current_page - 1;
 			$prev_block_params['name'] = $this->SelectParam($params, 'prev_page_render_as,block_prev_page,prev_page_block');
 
 			if ( $prev_block_params['name'] ) {
 				$this->Application->SetVar($this->getPrefixSpecial() . '_Page', $prev_block_params['page']);
 				$o .= $this->Application->ParseBlock($prev_block_params);
 			}
 		}
 		else {
 			$no_prev_page_block = $this->SelectParam($params, 'no_prev_page_render_as,block_no_prev_page');
 
 			if ( $no_prev_page_block ) {
 				$block_params['name'] = $no_prev_page_block;
 				$o .= $this->Application->ParseBlock($block_params);
 			}
 		}
 
 		$total_records = $list->GetRecordsCount();
 		$separator_params['name'] = $this->SelectParam($params, 'separator_render_as,block_separator');
 
 		for ($i = $split_start; $i <= $split_end; $i++) {
 			$from_record = ($i - 1) * $list->GetPerPage();
 			$to_record = $from_record + $list->GetPerPage();
 
 			if ( $to_record > $total_records ) {
 				$to_record = $total_records;
 			}
 
 			$block_params['from_record'] = $from_record + 1;
 			$block_params['to_record'] = $to_record;
 
 			if ( $i == $current_page ) {
 				$block = $this->SelectParam($params, 'current_render_as,active_render_as,block_current,active_block');
 			}
 			else {
 				$block = $this->SelectParam($params, 'link_render_as,inactive_render_as,block_link,inactive_block');
 			}
 
 			$block_params['name'] = $block;
 			$block_params['page'] = $i;
 			$this->Application->SetVar($this->getPrefixSpecial() . '_Page', $block_params['page']);
 			$o .= $this->Application->ParseBlock($block_params);
 
 			if ( $this->SelectParam($params, 'separator_render_as,block_separator') && $i < $split_end ) {
 				$o .= $this->Application->ParseBlock($separator_params);
 			}
 		}
 
 		if ( $current_page < $total_pages ) {
 			$next_block_params = $this->prepareTagParams($params);
 			$next_block_params['page'] = $current_page + 1;
 			$next_block_params['name'] = $this->SelectParam($params, 'next_page_render_as,block_next_page,next_page_block');
 
 			if ( $next_block_params['name'] ) {
 				$this->Application->SetVar($this->getPrefixSpecial() . '_Page', $next_block_params['page']);
 				$o .= $this->Application->ParseBlock($next_block_params);
 			}
 
 			if ( $total_pages > $split ) {
 				$next_block_params['page'] = min($current_page + $split, $total_pages);
 				$next_block_params['name'] = $this->SelectParam($params, 'next_page_split_render_as,next_page_split_block');
 
 				if ( $next_block_params['name'] ) {
 					$this->Application->SetVar($this->getPrefixSpecial() . '_Page', $next_block_params['page']);
 					$o .= $this->Application->ParseBlock($next_block_params);
 				}
 			}
 		}
 		else {
 			$no_next_page_block = $this->SelectParam($params, 'no_next_page_render_as,block_no_next_page');
 
 			if ( $no_next_page_block ) {
 				$block_params['name'] = $no_next_page_block;
 				$o .= $this->Application->ParseBlock($block_params);
 			}
 		}
 
 		$this->Application->SetVar($this->getPrefixSpecial() . '_Page', $current_page);
 
 		return $o;
 	}
 
 	/**
 	 * Print grid pagination using
 	 * block names specified
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function PaginationBar($params)
 	{
 		return $this->PrintPages($params);
 	}
 
 	function PerPageBar($params)
 	{
 		$object =& $this->GetList($params);
 
 		$ret = '';
 		$per_pages = explode(';', $params['per_pages']);
 		$block_params = $this->prepareTagParams($params);
 		$block_params['name'] = $params['render_as'];
 
 		foreach ($per_pages as $per_page) {
 			$block_params['per_page'] = $per_page;
 			$this->Application->SetVar($this->getPrefixSpecial() . '_PerPage', $per_page);
 			$block_params['selected'] = $per_page == $object->GetPerPage();
 
 			$ret .= $this->Application->ParseBlock($block_params, 1);
 		}
 
 		$this->Application->SetVar($this->getPrefixSpecial() . '_PerPage', $object->GetPerPage());
 
 		return $ret;
 	}
 
 	/**
 	 * Returns field name (processed by kMultiLanguage formatter
 	 * if required) and item's id from it's IDField or field required
 	 *
 	 * @param Array $params
 	 * @return Array (id,field)
 	 * @access private
 	 */
 	function prepareInputName($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$field = $this->SelectParam($params, 'name,field');
 		$formatter_class = $object->GetFieldOption($field, 'formatter');
 
 		if ($formatter_class == 'kMultiLanguage') {
 			$formatter = $this->Application->recallObject($formatter_class);
 			/* @var $formatter kMultiLanguage */
 
 			$force_primary = $object->GetFieldOption($field, 'force_primary');
 			$field = $formatter->LangFieldName($field, $force_primary);
 		}
 
 		if (array_key_exists('force_id', $params)) {
 			$id = $params['force_id'];
 		}
 		else {
 			$id_field = array_key_exists('IdField', $params) ? $params['IdField'] : false;
 			$id = $id_field ? $object->GetDBField($id_field) : $object->GetID();
 		}
 
 		return Array($id, $field);
 	}
 
 
 	/**
 	 * Returns input field name to
 	 * be placed on form (for correct
 	 * event processing)
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function InputName($params)
 	{
 		list($id, $field) = $this->prepareInputName($params);
 
 		$ret = $this->getPrefixSpecial().'['.$id.']['.$field.']';
 
 		if (array_key_exists('as_preg', $params) && $params['as_preg']) {
 			$ret = preg_quote($ret, '/');
 		}
 
 		return $ret;
 	}
 
 	/**
 	 * Allows to override various field options through hidden fields with specific names in submit.
 	 * This tag generates this special names
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @author Alex
 	 */
 	function FieldModifier($params)
 	{
 		list($id, $field) = $this->prepareInputName($params);
 
 		$ret = 'field_modifiers['.$this->getPrefixSpecial().']['.$field.']['.$params['type'].']';
 
 		if (array_key_exists('as_preg', $params) && $params['as_preg']) {
 			$ret = preg_quote($ret, '/');
 		}
 
 		if (isset($params['value'])) {
 			$object = $this->getObject($params);
 			$field_modifiers[$field][$params['type']] = $params['value'];
 			$object->ApplyFieldModifiers($field_modifiers);
 		}
 
 		return $ret;
 	}
 
 	/**
 	 * Returns index where 1st changable sorting field begins
 	 *
 	 * @return int
 	 * @access private
 	 */
 	function getUserSortIndex()
 	{
 		$list_sortings = $this->Application->getUnitOption($this->Prefix, 'ListSortings', Array ());
 		$sorting_prefix = getArrayValue($list_sortings, $this->Special) ? $this->Special : '';
 
 		$user_sorting_start = 0;
 		$forced_sorting = getArrayValue($list_sortings, $sorting_prefix, 'ForcedSorting');
 
 		return $forced_sorting ? count($forced_sorting) : $user_sorting_start;
 	}
 
 	/**
 	 * Returns order direction for given field
 	 *
 	 *
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function Order($params)
 	{
 		$field = $params['field'];
 		$user_sorting_start = $this->getUserSortIndex();
 
 		$list =& $this->GetList($params);
 
 		if ($list->GetOrderField($user_sorting_start) == $field)
 		{
 			return strtolower($list->GetOrderDirection($user_sorting_start));
 		}
 		elseif($this->Application->ConfigValue('UseDoubleSorting') && $list->GetOrderField($user_sorting_start+1) == $field)
 		{
 			return '2_'.strtolower($list->GetOrderDirection($user_sorting_start+1));
 		}
 		else
 		{
 			return 'no';
 		}
 	}
 
 	/**
 	 * Detects, that current sorting is not default
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function OrderChanged($params)
 	{
 		$list =& $this->GetList($params);
 
 		$list_helper = $this->Application->recallObject('ListHelper');
 		/* @var $list_helper ListHelper */
 
 		return $list_helper->hasUserSorting($list);
 	}
 
 	/**
 	 * Gets information of sorting field at "pos" position,
 	 * like sorting field name (type="field") or sorting direction (type="direction")
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function OrderInfo($params)
 	{
 		$user_sorting_start = $this->getUserSortIndex() + --$params['pos'];
 		$list =& $this->GetList($params);
 
 		if ( $params['type'] == 'field' ) {
 			return $list->GetOrderField($user_sorting_start);
 		}
 
 		if ( $params['type'] == 'direction' ) {
 			return $list->GetOrderDirection($user_sorting_start);
 		}
 
 		return '';
 	}
 
 	/**
 	 * Checks if sorting field/direction matches passed field/direction parameter
 	 *
 	 * @param Array $params
 	 * @return bool
 	 * @access protected
 	 */
 	protected function IsOrder($params)
 	{
 		$params['type'] = isset($params['field']) ? 'field' : 'direction';
 		$value = $this->OrderInfo($params);
 
 		if ( isset($params['field']) ) {
 			return $params['field'] == $value;
 		}
 		elseif ( isset($params['direction']) ) {
 			return $params['direction'] == $value;
 		}
 
 		return false;
 	}
 
 	/**
 	 * Returns list per-page
 	 *
 	 * @param Array $params
 	 * @return int
 	 */
 	function PerPage($params)
 	{
 		$object =& $this->GetList($params);
 
 		return $object->GetPerPage();
 	}
 
 	/**
 	 * Checks if list perpage matches value specified
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function PerPageEquals($params)
 	{
 		$object =& $this->GetList($params);
 
 		return $object->GetPerPage() == $params['value'];
 	}
 
 	function SaveEvent($params)
 	{
 		// SaveEvent is set during OnItemBuild, but we may need it before any other tag calls OnItemBuild
 		$object = $this->getObject($params);
 		return $this->Application->GetVar($this->getPrefixSpecial().'_SaveEvent');
 	}
 
 	function NextId($params)
 	{
 		$object = $this->getObject($params);
 
 		$wid = $this->Application->GetTopmostWid($this->Prefix);
 		$session_name = rtrim($this->getPrefixSpecial().'_selected_ids_'.$wid, '_');
 		$ids = explode(',', $this->Application->RecallVar($session_name));
 
 		$cur_id = $object->GetID();
 
 		$i = array_search($cur_id, $ids);
 		if ($i !== false) {
 			return $i < count($ids) - 1 ? $ids[$i + 1] : '';
 		}
 		return '';
 	}
 
 	function PrevId($params)
 	{
 		$object = $this->getObject($params);
 
 		$wid = $this->Application->GetTopmostWid($this->Prefix);
 		$session_name = rtrim($this->getPrefixSpecial().'_selected_ids_'.$wid, '_');
 		$ids = explode(',', $this->Application->RecallVar($session_name));
 
 		$cur_id = $object->GetID();
 
 		$i = array_search($cur_id, $ids);
 		if ($i !== false) {
 			return $i > 0 ? $ids[$i - 1] : '';
 		}
 		return '';
 	}
 
 	function IsSingle($params)
 	{
 		return ($this->NextId($params) === '' && $this->PrevId($params) === '');
 	}
 
 	function IsLast($params)
 	{
 		return ($this->NextId($params) === '');
 	}
 
 	function IsFirst($params)
 	{
 		return ($this->PrevId($params) === '');
 	}
 
 	/**
 	 * Checks if field value is equal to proposed one
 	 *
 	 * @param Array $params
 	 * @return bool
 	 * @deprecated
 	 */
 	function FieldEquals($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		return $object->GetDBField( $this->SelectParam($params, 'name,field') ) == $params['value'];
 	}
 
 	/**
 	 * Checks, that grid has icons defined and they should be shown
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function UseItemIcons($params)
 	{
 		$grids = $this->Application->getUnitOption($this->Prefix, 'Grids');
 		return array_key_exists('Icons', $grids[ $params['grid'] ]);
 	}
 
 	/**
 	 * Returns corresponding to grid layout selector column width
 	 *
 	 * @param Array $params
 	 * @return int
 	 */
 	function GridSelectorColumnWidth($params)
 	{
 		$width = 0;
 		if ($params['selector']) {
 			$width += $params['selector_width'];
 		}
 
 		if ($this->UseItemIcons($params)) {
 			$width += $params['icon_width'];
 		}
 
 		return $width;
 	}
 
 	/**
 	 * Returns grids item selection mode (checkbox, radio, )
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function GridSelector($params)
 	{
 		$grids = $this->Application->getUnitOption($this->Prefix, 'Grids');
 
 		return array_key_exists('Selector', $grids[ $params['grid'] ]) ? $grids[ $params['grid'] ]['Selector'] : $params['default'];
 	}
 
 	function ItemIcon($params)
 	{
 		$grids = $this->Application->getUnitOption($this->Prefix, 'Grids');
 		$grid = $grids[ $params['grid'] ];
 
 		if ( !isset($grid['Icons']) ) {
 			return '';
 		}
 
 		$icons = $grid['Icons'];
 
 		if ( isset($params['name']) ) {
 			$icon_name = $params['name'];
 
 			return isset($icons[$icon_name]) ? $icons[$icon_name] : '';
 		}
 
 		$status_fields = $this->Application->getUnitOption($this->Prefix, 'StatusField', Array ());
 		/* @var $status_fields Array */
 
 		if ( !$status_fields ) {
 			return $icons['default'];
 		}
 
 		$object = $this->getObject($params);
 		/* @var $object kDBList */
 
 		$icon = '';
 
 		foreach ($status_fields as $status_field) {
 			$icon .= $object->GetDBField($status_field) . '_';
 		}
 
 		$icon = rtrim($icon, '_');
 
 		return isset($icons[$icon]) ? $icons[$icon] : $icons['default'];
 	}
 
 	/**
 	 * Generates bluebar title + initializes prefixes used on page
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function SectionTitle($params)
 	{
 		$preset_name = kUtil::replaceModuleSection($params['title_preset']);
 		$title_presets = $this->Application->getUnitOption($this->Prefix,'TitlePresets');
 		$title_info = array_key_exists($preset_name, $title_presets) ? $title_presets[$preset_name] : false;
 
 		if ($title_info === false) {
 			$title = str_replace('#preset_name#', $preset_name, $params['title']);
 			if ($this->Application->ConfigValue('UseSmallHeader') && isset($params['group_title']) && $params['group_title']) {
 				$title .= ' - '.$params['group_title'];
 			}
 			return $title;
 		}
 
 		if (array_key_exists('default', $title_presets) && $title_presets['default']) {
 			// use default labels + custom labels specified in preset used
 			$title_info = kUtil::array_merge_recursive($title_presets['default'], $title_info);
 		}
 
 		$title = $title_info['format'];
 
 		// 1. get objects in use for title construction
 		$objects = Array();
 		$object_status = Array();
 		$status_labels = Array();
 
 		$prefixes = array_key_exists('prefixes', $title_info) ? $title_info['prefixes'] : false;
 		$all_tag_params = array_key_exists('tag_params', $title_info) ? $title_info['tag_params'] : false;
 		/* @var $prefixes Array */
 
 		if ($prefixes) {
 			// extract tag_params passed directly to SectionTitle tag for specific prefix
 			foreach ($params as $tp_name => $tp_value) {
 				if (preg_match('/(.*)\[(.*)\]/', $tp_name, $regs)) {
 					$all_tag_params[ $regs[1] ][ $regs[2] ] = $tp_value;
 					unset($params[$tp_name]);
 				}
 			}
 
 			$tag_params = Array();
 			foreach ($prefixes as $prefix_special) {
 				$prefix_data = $this->Application->processPrefix($prefix_special);
 				$prefix_data['prefix_special'] = rtrim($prefix_data['prefix_special'],'.');
 
 				if ($all_tag_params) {
 					$tag_params = getArrayValue($all_tag_params, $prefix_data['prefix_special']);
 					if (!$tag_params) {
 						$tag_params = Array();
 					}
 				}
 
 				$tag_params = array_merge($params, $tag_params);
 				$objects[ $prefix_data['prefix_special'] ] = $this->Application->recallObject($prefix_data['prefix_special'], $prefix_data['prefix'], $tag_params);
 				$object_status[ $prefix_data['prefix_special'] ] = $objects[ $prefix_data['prefix_special'] ]->IsNewItem() ? 'new' : 'edit';
 
 				// a. set object's status field (adding item/editing item) for each object in title
 				if (getArrayValue($title_info[ $object_status[ $prefix_data['prefix_special'] ].'_status_labels' ],$prefix_data['prefix_special'])) {
 					$status_labels[ $prefix_data['prefix_special'] ] = $title_info[ $object_status[ $prefix_data['prefix_special'] ].'_status_labels' ][ $prefix_data['prefix_special'] ];
 					$title = str_replace('#'.$prefix_data['prefix_special'].'_status#', $status_labels[ $prefix_data['prefix_special'] ], $title);
 				}
 
 				// b. setting object's titlefield value (in titlebar ONLY) to default in case if object beeing created with no titlefield filled in
 				if ($object_status[ $prefix_data['prefix_special'] ] == 'new') {
 					$new_value = $this->getInfo( $objects[ $prefix_data['prefix_special'] ], 'titlefield' );
 					if(!$new_value && getArrayValue($title_info['new_titlefield'],$prefix_data['prefix_special']) ) $new_value = $this->Application->Phrase($title_info['new_titlefield'][ $prefix_data['prefix_special'] ]);
 					$title = str_replace('#'.$prefix_data['prefix_special'].'_titlefield#', $new_value, $title);
 				}
 			}
 		}
 
 		// replace to section title
 		$section = array_key_exists('section', $params) ? $params['section'] : false;
 		if ($section) {
 			$sections_helper = $this->Application->recallObject('SectionsHelper');
 			/* @var $sections_helper kSectionsHelper */
 
 			$section_data =& $sections_helper->getSectionData($section);
 			$title = str_replace('#section_label#', '!' . $section_data['label'] . '!', $title);
 		}
 
 		// 2. replace phrases if any found in format string
 		$title = $this->Application->ReplaceLanguageTags($title, false);
 
 		// 3. find and replace any replacement vars
 		preg_match_all('/#(.*_.*)#/Uis',$title,$rets);
 		if ($rets[1]) {
 			$replacement_vars = array_keys( array_flip($rets[1]) );
 			foreach ($replacement_vars as $replacement_var) {
 				$var_info = explode('_',$replacement_var,2);
 				$object =& $objects[ $var_info[0] ];
 				$new_value = $this->getInfo($object,$var_info[1]);
 				$title = str_replace('#'.$replacement_var.'#', $new_value, $title);
 			}
 		}
 
 		// replace trailing spaces inside title preset + '' occurences into single space
 		$title = preg_replace('/[ ]*\'\'[ ]*/', ' ', $title);
 
 		if ($this->Application->ConfigValue('UseSmallHeader') && isset($params['group_title']) && $params['group_title']) {
 			$title .= ' - '.$params['group_title'];
 		}
 
 		$first_chars = $this->SelectParam($params, 'first_chars,cut_first');
 
 		if ($first_chars && !preg_match('/<a href="(.*)".*>(.*)<\/a>/', $title)) {
 			// don't cut titles, that contain phrase translation links
 			$stripped_title = strip_tags($title, $this->SelectParam($params, 'allowed_tags'));
 
 			if (mb_strlen($stripped_title) > $first_chars) {
 				$title = mb_substr($stripped_title, 0, $first_chars) . ' ...';
 			}
 		}
 
 		return $title;
 	}
 
 	/**
 	 * Returns information about list
 	 *
 	 * @param kDBList $object
 	 * @param string $info_type
 	 * @return string
 	 * @access protected
 	 */
 	protected function getInfo(&$object, $info_type)
 	{
 		switch ( $info_type ) {
 			case 'titlefield':
 				$field = $this->Application->getUnitOption($object->Prefix, 'TitleField');
 				return $field !== false ? $object->GetField($field) : 'TitleField Missing';
 				break;
 
 			case 'recordcount':
 				if ( $object->GetRecordsCount(false) != $object->GetRecordsCount() ) {
 					$of_phrase = $this->Application->Phrase('lc_of');
 					return $object->GetRecordsCount() . ' ' . $of_phrase . ' ' . $object->GetRecordsCount(false);
 				}
 
 				return $object->GetRecordsCount();
 				break;
 		}
 
 		return $object->GetField($info_type);
 	}
 
 	function GridInfo($params)
 	{
 		$object =& $this->GetList($params);
 		/* @var $object kDBList */
 
 		switch ( $params['type'] ) {
 			case 'filtered':
 				return $object->GetRecordsCount();
 
 			case 'total':
 				return $object->GetRecordsCount(false);
 
 			case 'from':
 				return $object->GetRecordsCount() ? $object->GetOffset() + 1 : 0; //0-based
 
 			case 'to':
 				$record_count = $object->GetRecordsCount();
 				return $object->GetPerPage(true) != -1 ? min($object->GetOffset() + $object->GetPerPage(), $record_count) : $record_count;
 
 			case 'total_pages':
 				return $object->GetTotalPages();
 
 			case 'needs_pagination':
 				return ($object->GetPerPage(true) != -1) && (($object->GetRecordsCount() > $object->GetPerPage()) || ($object->GetPage() > 1));
 		}
 
 		return false;
 	}
 
 	/**
 	 * Parses block depending on its element type.
 	 * For radio and select elements values are taken from 'value_list_field' in key1=value1,key2=value2
 	 * format. key=value can be substituted by <SQL>SELECT f1 AS OptionName, f2 AS OptionValue... FROM <PREFIX>TableName </SQL>
 	 * where prefix is TABLE_PREFIX
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function ConfigFormElement($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$field = $params['field'];
 
 		$helper = $this->Application->recallObject('InpCustomFieldsHelper');
 		/* @var $helper InpCustomFieldsHelper */
 
 		$element_type = $object->GetDBField($params['element_type_field']);
 
 		if ($element_type == 'label') {
 			$element_type = 'text';
 		}
 
 		$formatter_class = $object->GetFieldOption($field, 'formatter');
 
 		switch ($element_type) {
 			case 'select':
 			case 'multiselect':
 			case 'radio':
 				if ($object->GetDBField('DirectOptions')) {
 					// used for custom fields
 					$options = $object->GetDBField('DirectOptions');
 				}
 				else {
 					// used for configuration
 					$options = $helper->GetValuesHash( $object->GetDBField($params['value_list_field']) );
 				}
 
 				$object->SetFieldOption($field, 'formatter', 'kOptionsFormatter');
 				$object->SetFieldOption($field, 'options', $options);
 				break;
 
 			case 'text':
 			case 'textarea':
 			case 'upload':
 				$params['field_params'] = $helper->ParseConfigSQL($object->GetDBField($params['value_list_field']));
 				break;
 
 			case 'password':
 			case 'checkbox':
 			default:
 				break;
 		}
 
 		if (!$element_type) {
 			throw new Exception('Element type missing for "<strong>' . $object->GetDBField('VariableName') . '</strong>" configuration variable');
 			return '';
 		}
 
 		$params['name'] = $params['blocks_prefix'] . $element_type;
 
 		// use $pass_params to pass 'SourcePrefix' parameter from PrintList to CustomInputName tag
 		$ret = $this->Application->ParseBlock($params, 1);
 
 		$object->SetFieldOption($field, 'formatter', $formatter_class);
 
 		return $ret;
 	}
 
 	/**
 	 * Get's requested custom field value
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function CustomField($params)
 	{
 		$params['name'] = 'cust_'.$this->SelectParam($params, 'name,field');
 		return $this->Field($params);
 	}
 
 	function CustomFieldLabel($params)
 	{
 		$object = $this->getObject($params);
 
 		$field = $this->SelectParam($params, 'name,field');
 
 		$sql = 'SELECT FieldLabel
 				FROM '.$this->Application->getUnitOption('cf', 'TableName').'
 				WHERE FieldName = '.$this->Conn->qstr($field);
 		return $this->Application->Phrase($this->Conn->GetOne($sql));
 	}
 
 	/**
 	 * transposes 1-dimensional array elements for vertical alignment according to given columns and per_page parameters
 	 *
 	 * @param array $arr
 	 * @param int $columns
 	 * @param int $per_page
 	 * @return array
 	 */
 	function LinearToVertical(&$arr, $columns, $per_page)
 	{
 		$rows = $columns;
 		// in case if after applying per_page limit record count less then
 		// can fill requrested column count, then fill as much as we can
 		$cols = min(ceil($per_page / $columns), ceil(count($arr) / $columns));
 		$imatrix = array();
 		for ($row = 0; $row < $rows; $row++) {
 			for ($col = 0; $col < $cols; $col++) {
 				$source_index = $row * $cols + $col;
 				if (!isset($arr[$source_index])) {
 					// in case if source array element count is less then element count in one row
 					continue;
 				}
 				$imatrix[$col * $rows + $row] = $arr[$source_index];
 			}
 		}
 
 		ksort($imatrix);
 		return array_values($imatrix);
 	}
 
 	/**
 	 * If data was modified & is in TempTables mode, then parse block with name passed;
 	 * remove modification mark if not in TempTables mode
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function SaveWarning($params)
 	{
 		$main_prefix = array_key_exists('main_prefix', $params) ? $params['main_prefix'] : false;
 
 		if ( $main_prefix ) {
 			$top_prefix = $main_prefix;
 		}
 		else {
 			$top_prefix = $this->Application->GetTopmostPrefix($this->Prefix);
 		}
 
 		$temp_tables = substr($this->Application->GetVar($top_prefix . '_mode'), 0, 1) == 't';
 		$modified = $this->Application->RecallVar($top_prefix . '_modified');
 
 		if ( $temp_tables && $modified ) {
 			$block_params = $this->prepareTagParams($params);
 			$block_params['name'] = $this->SelectParam($params, 'render_as,name');
 			$block_params['edit_mode'] = $temp_tables ? 1 : 0;
 			return $this->Application->ParseBlock($block_params);
 		}
 
 		$this->Application->RemoveVar($top_prefix . '_modified');
 		return '';
 	}
 
 	/**
 	 * Returns list record count queries (on all pages)
 	 *
 	 * @param Array $params
 	 * @return int
 	 */
 	function TotalRecords($params)
 	{
 		$list =& $this->GetList($params);
 
 		return $list->GetRecordsCount();
 	}
 
 	/**
 	 * Range filter field name
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function SearchInputName($params)
 	{
 		$field = $this->SelectParam($params, 'field,name');
 
 		$ret = 'custom_filters['.$this->getPrefixSpecial().']['.$params['grid'].']['.$field.']['.$params['filter_type'].']';
 
 		if (isset($params['type'])) {
 			$ret .= '['.$params['type'].']';
 		}
 
 		if (array_key_exists('as_preg', $params) && $params['as_preg']) {
 			$ret = preg_quote($ret, '/');
 		}
 
 		return $ret;
 	}
 
 	/**
 	 * Return range filter field value
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function SearchField($params) // RangeValue
 	{
 		$field = $this->SelectParam($params, 'field,name');
 
 		$view_name = $this->Application->RecallVar($this->getPrefixSpecial() . '_current_view');
 		$custom_filter = $this->Application->RecallPersistentVar($this->getPrefixSpecial() . '_custom_filter.' . $view_name /*, ALLOW_DEFAULT_SETTINGS*/);
 		$custom_filter = $custom_filter ? unserialize($custom_filter) : Array ();
 
 		if ( isset($custom_filter[$params['grid']][$field]) ) {
 			$ret = $custom_filter[$params['grid']][$field][$params['filter_type']]['submit_value'];
 			if ( isset($params['type']) ) {
 				$ret = $ret[$params['type']];
 			}
 
 			if ( array_key_exists('formatted', $params) && $params['formatted'] ) {
 				$object =& $this->GetList($params);
 				$formatter_class = $object->GetFieldOption($field, 'formatter');
 
 				if ( $formatter_class ) {
 					$formatter = $this->Application->recallObject($formatter_class);
 					/* @var $formatter kFormatter */
 
 					$ret = $formatter->Format($ret, $field, $object);
 				}
 			}
 
 			if ( !array_key_exists('no_special', $params) || !$params['no_special'] ) {
 				$ret = kUtil::escape($ret);
 			}
 
 			return $ret;
 		}
 
 		return '';
 	}
 
 	/**
 	 * Tells, that at least one of search filters is used by now
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function SearchActive($params)
 	{
 		if ($this->Application->RecallVar($this->getPrefixSpecial() . '_search_keyword')) {
 			// simple search filter is used
 			return true;
 		}
 
 		$view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view');
 		$custom_filter = $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_custom_filter.'.$view_name/*, ALLOW_DEFAULT_SETTINGS*/);
 		$custom_filter = $custom_filter ? unserialize($custom_filter) : Array();
 
 		return array_key_exists($params['grid'], $custom_filter);
 	}
 
 	function SearchFormat($params)
 	{
 		$object =& $this->GetList($params);
 
         return $this->Format($params, $object);
 	}
 
 	/**
 	 * Returns error of range field
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function SearchError($params)
 	{
 		$field = $this->SelectParam($params, 'field,name');
 
 		$error_var_name = $this->getPrefixSpecial() . '_' . $field . '_error';
 		$pseudo = $this->Application->RecallVar($error_var_name);
 		if ( $pseudo ) {
 			$this->Application->RemoveVar($error_var_name);
 		}
 
 		$object = $this->Application->recallObject($this->Prefix . '.' . $this->Special . '-item', null, Array ('skip_autoload' => true));
 		/* @var $object kDBItem */
 
 		$object->SetError($field, $pseudo);
 		return $object->GetErrorMsg($field, false);
 	}
 
 	/**
 	 * Returns object used in tag processor
 	 *
 	 * @param Array $params
 	 * @access public
 	 * @return kDBItem|kDBList
 	 */
 	function getObject($params = Array())
 	{
 		$object = $this->Application->recallObject($this->getPrefixSpecial(), $this->Prefix, $params);
 		/* @var $object kDBItem */
 
 		if ( isset($params['requery']) && $params['requery'] ) {
 			$this->Application->HandleEvent(new kEvent($this->getPrefixSpecial() . ':LoadItem', $params));
 		}
 
 		return $object;
 	}
 
 	/**
 	 * Checks if object propery value matches value passed
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function PropertyEquals($params)
 	{
 		$object = $this->getObject($params);
 		$property_name = $this->SelectParam($params, 'name,var,property');
 		return $object->$property_name == $params['value'];
 	}
 
 	function DisplayOriginal($params)
 	{
 		return false;
 	}
 
 	/*function MultipleEditing($params)
 	{
 		$wid = $this->Application->GetTopmostWid($this->Prefix);
 		$session_name = rtrim($this->getPrefixSpecial().'_selected_ids_'.$wid, '_');
 		$selected_ids = explode(',', $this->Application->RecallVar($session_name));
 
 		$ret = '';
 		if ($selected_ids) {
 			$selected_ids = explode(',', $selected_ids);
 			$object = $this->getObject( kUtil::array_merge_recursive($params, Array('skip_autoload' => true)) );
 			$params['name'] = $params['render_as'];
 			foreach ($selected_ids as $id) {
 				$object->Load($id);
 				$ret .= $this->Application->ParseBlock($params);
 			}
 		}
 
 		return $ret;
 	}*/
 
 	/**
 	 * Returns import/export process percent
 	 *
 	 * @param Array $params
 	 * @return int
 	 * @deprecated Please convert to event-model, not tag based
 	 */
 	function ExportStatus($params)
 	{
 		$export_object = $this->Application->recallObject('CatItemExportHelper');
 		/* @var $export_object kCatDBItemExportHelper */
 
 		$event = new kEvent($this->getPrefixSpecial().':OnDummy');
 
 		$action_method = 'perform'.ucfirst($this->Special);
 		$field_values = $export_object->$action_method($event);
 
 		// finish code is done from JS now
 		if ($field_values['start_from'] >= $field_values['total_records'])
 		{
 			if ($this->Special == 'import') {
 				// this is used?
 				$this->Application->StoreVar('PermCache_UpdateRequired', 1);
 				$this->Application->Redirect('categories/cache_updater', Array('m_opener' => 'r', 'pass' => 'm', 'continue' => 1));
 			}
 			elseif ($this->Special == 'export') {
 				// used for orders export in In-Commerce
 				$finish_t = $this->Application->RecallVar('export_finish_t');
 				$this->Application->Redirect($finish_t, Array('pass' => 'all'));
 				$this->Application->RemoveVar('export_finish_t');
 			}
 		}
 
 		$export_options = $export_object->loadOptions($event);
 		return $export_options['start_from']  * 100 / $export_options['total_records'];
 	}
 
 	/**
 	 * Returns path where exported category items should be saved
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function ExportPath($params)
 	{
 		$export_options = unserialize($this->Application->RecallVar($this->getPrefixSpecial() . '_options'));
 		$extension = $export_options['ExportFormat'] == 1 ? 'csv' : 'xml';
 		$filename = preg_replace('/(.*)\.' . $extension . '$/', '\1', $export_options['ExportFilename']) . '.' . $extension;
 
 		$path = EXPORT_PATH . '/';
 
 		if ( array_key_exists('as_url', $params) && $params['as_url'] ) {
 			$path = str_replace(FULL_PATH . '/', $this->Application->BaseURL(), $path);
 		}
 
 		return $path . $filename;
 	}
 
 	function FieldTotal($params)
 	{
 		$list =& $this->GetList($params);
 		$field = $this->SelectParam($params, 'field,name');
 		$total_function = array_key_exists('function', $params) ? $params['function'] : $list->getTotalFunction($field);
 
 		if (array_key_exists('function_only', $params) && $params['function_only']) {
 			return $total_function;
 		}
 
 		if (array_key_exists('currency', $params) && $params['currency']) {
 			$iso = $this->GetISO($params['currency']);
 			$original = $list->getTotal($field, $total_function);
 			$value = $this->ConvertCurrency($original, $iso);
 			$list->setTotal($field, $total_function, $value);
 		}
 
 		$value = $list->GetFormattedTotal($field, $total_function);
 
 		if (array_key_exists('currency', $params) && $params['currency']) {
 			$value = $this->AddCurrencySymbol($value, $iso);
 		}
 
 		return $value;
 	}
 
 	function FCKEditor($params)
 	{
 		$editor_name = array_key_exists('name', $params) ? $params['name'] : $this->InputName($params);
 
 		$fck_helper = $this->Application->recallObject('FCKHelper');
 		/* @var $fck_helper fckFCKHelper */
 
 		if ( isset($params['mode']) && $params['mode'] == 'inline' ) {
 			return $fck_helper->CKEditorInlineTag($editor_name, $params);
 		}
 
 		return $fck_helper->CKEditorTag($editor_name, $this->CKEditorValue($params), $params);
 	}
 
 	/**
 	 * Returns value, used by FCKEditor tag
 	 *
 	 * @param array $params
 	 *
 	 * @return string
 	 */
 	protected function CKEditorValue($params)
 	{
 		$params['no_special'] = 1;
 		$params['format'] = array_key_exists('format', $params) ? $params['format'] . ';fck_ready' : 'fck_ready';
 
 		return $this->Field($params);
 	}
 
 	function IsNewItem($params)
 	{
 		$object = $this->getObject($params);
 		return $object->IsNewItem();
 	}
 
 	/**
 	 * Creates link to an item including only it's id
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function ItemLink($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		if ( !isset($params['pass']) ) {
 			$params['pass'] = 'm';
 		}
 
 		$params[ $object->getPrefixSpecial() . '_id' ] = $object->GetID();
 
 		return $this->Application->ProcessParsedTag('m', 'T', $params);
 	}
 
 	/**
 	 * Creates a button for editing item in Admin Console
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function AdminEditButton($params)
 	{
 		if ( EDITING_MODE != EDITING_MODE_CONTENT ) {
 			return '';
 		}
 
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$item_prefix = isset($params['item_prefix']) ? $params['item_prefix'] : $this->Prefix;
 
 		if ( isset($params['template']) ) {
 			$template = $params['template'];
 		}
 		else {
 			$admin_template_prefix = $this->Application->getUnitOption($item_prefix, 'AdminTemplatePrefix');
 			$template = $this->Application->getUnitOption($item_prefix, 'AdminTemplatePath') . '/' . $admin_template_prefix . 'edit';
 
 			if ( !$admin_template_prefix ) {
 				throw new InvalidArgumentException('Automatic admin editing template detection failed because of missing "AdminTemplatePrefix" unit config option in "' . $this->Prefix . '" unit config');
 			}
 		}
 
 		$form_name = 'kf_' . str_replace('-', '_', $item_prefix) . '_' . $object->GetID();
 		$form_name .= '_' . kUtil::crc32(json_encode($params));
 		$button_icon = isset($params['button_icon']) ? $params['button_icon'] : 'content_mode.png';
 		$button_class = isset($params['button_class']) ? $params['button_class'] : 'admin-edit-btn';
 		$button_title = isset($params['button_title']) ? $params['button_title'] : 'la_btn_AdminEditItem';
 
 		if ( substr($button_title, 0, 1) == '+' ) {
 			$button_title = substr($button_title, 1);
 		}
 		else {
 			$button_title = $this->Application->Phrase($button_title, false, true);
 		}
 
 		$icon_url = $this->Application->BaseURL() . 'core/admin_templates/img/top_frame/icons/' . $button_icon;
 		$button_onclick = '$form_name = ' . json_encode($form_name) . '; std_edit_item(' . json_encode($item_prefix) . ', ' . json_encode($template) . ');';
 
 		$button_code = '<button
 			style="background-image: url(' . $icon_url . ');"
 			onclick="' . kUtil::escape($button_onclick, kUtil::ESCAPE_HTML) . '"
 			class="cms-btn-new ' . $button_class . '">' .
 			kUtil::escape($button_title, kUtil::ESCAPE_HTML) . '
 		</button>';
 
 		if ( !isset($params['pass']) ) {
 			$params['pass'] = 'm,' . $item_prefix;
 		}
 
 		$params['m_opener'] = 'd';
 		$params[$item_prefix . '_id'] = $object->GetID();
 
 		if ( !isset($params['temp_mode']) || (isset($params['temp_mode']) && $params['temp_mode']) ) {
 			$params[$item_prefix . '_mode'] = 't';
 			$params[$item_prefix . '_event'] = 'OnEdit';
 		}
 
 		$params['front'] = 1; // to make opener stack work properly
 		$params['__NO_REWRITE__'] = 1; // since admin link
 
 		unset($params['button_icon'], $params['button_class'], $params['button_title'], $params['template'], $params['item_prefix'], $params['temp_mode']);
 
 		// link from Front-End to Admin, don't remove "index.php"
 		$form_name_escaped = kUtil::escape($form_name, kUtil::ESCAPE_HTML);
 		$edit_url = kUtil::escape($this->Application->HREF($template, ADMIN_DIRECTORY, $params, 'index.php'), kUtil::ESCAPE_HTML);
 		$edit_form = '<form method="POST" style="display: inline; margin: 0px" name="' . $form_name_escaped . '" id="' . $form_name_escaped . '" action="' . $edit_url . '"></form>';
 
 		if ( isset($params['forms_later']) && $params['forms_later'] ) {
 			$all_forms = $this->Application->GetVar('all_forms');
 			$this->Application->SetVar('all_forms', $all_forms . $edit_form);
 		}
 		else {
 			$button_code .= $edit_form;
 		}
 
 		return $button_code;
 	}
 
 	/**
 	 * Calls OnNew event from template, when no other event submitted
 	 *
 	 * @param Array $params
 	 */
 	function PresetFormFields($params)
 	{
 		$prefix = $this->getPrefixSpecial();
 		if ( !$this->Application->GetVar($prefix . '_event') ) {
 			$this->Application->HandleEvent(new kEvent($prefix . ':OnNew'));
 		}
 	}
 
 	function PrintSerializedFields($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$field = $this->SelectParam($params, 'field');
 		$data = unserialize($object->GetDBField($field));
 		$o = '';
 		$std_params['name'] = $params['render_as'];
 		$std_params['field'] = $params['field'];
 		$std_params['pass_params'] = true;
 
 		foreach ($data as $key => $row) {
 			$block_params = array_merge($std_params, $row, array('key'=>$key));
 			$o .= $this->Application->ParseBlock($block_params);
 		}
 
 		return $o;
 	}
 	/**
 	 * Checks if current prefix is main item
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function IsTopmostPrefix($params)
 	{
 		return $this->Prefix == $this->Application->GetTopmostPrefix($this->Prefix);
 	}
 
 	function PermSection($params)
 	{
 		$section = $this->SelectParam($params, 'section,name');
 		$perm_sections = $this->Application->getUnitOption($this->Prefix, 'PermSection');
 		return isset($perm_sections[$section]) ? $perm_sections[$section] : '';
 	}
 
 	function PerPageSelected($params)
 	{
 		$list =& $this->GetList($params);
 
 		return $list->GetPerPage(true) == $params['per_page'] ? $params['selected'] : '';
 	}
 
 	/**
 	 * Returns prefix + generated sepcial + any word
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function VarName($params)
 	{
 		$list =& $this->GetList($params);
 
 		return $list->getPrefixSpecial() . '_' . $params['type'];
 	}
 
 	/**
 	 * Returns edit tabs by specified preset name or false in case of error
 	 *
 	 * @param string $preset_name
 	 * @return mixed
 	 */
 	function getEditTabs($preset_name)
 	{
 		$presets = $this->Application->getUnitOption($this->Prefix, 'EditTabPresets');
 
 		if (!$presets || !isset($presets[$preset_name]) || count($presets[$preset_name]) == 0) {
 			return false;
 		}
 
 		return count($presets[$preset_name]) > 1 ? $presets[$preset_name] : false;
 	}
 
 	/**
 	 * Detects if specified preset has tabs in it
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function HasEditTabs($params)
 	{
 		return $this->getEditTabs($params['preset_name']) ? true : false;
 	}
 
 	/**
 	 * Sorts edit tabs based on their priority
 	 *
 	 * @param Array $tab_a
 	 * @param Array $tab_b
 	 * @return int
 	 */
 	function sortEditTabs($tab_a, $tab_b)
 	{
 		if ($tab_a['priority'] == $tab_b['priority']) {
 			return 0;
 		}
 
 		return $tab_a['priority'] < $tab_b['priority'] ? -1 : 1;
 	}
 
 	/**
 	 * Prints edit tabs based on preset name specified
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function PrintEditTabs($params)
 	{
 		$edit_tabs = $this->getEditTabs($params['preset_name']);
 		if ( !$edit_tabs ) {
 			return '';
 		}
 		usort($edit_tabs, Array (&$this, 'sortEditTabs'));
 
 		$ret = '';
 		$block_params = $this->prepareTagParams($params);
 		$block_params['name'] = $params['render_as'];
 
 		foreach ($edit_tabs as $tab_info) {
 			$block_params['title'] = $tab_info['title'];
 			$block_params['template'] = $tab_info['t'];
 			$ret .= $this->Application->ParseBlock($block_params);
 		}
 
 		return $ret;
 	}
 
 	/**
 	 * Performs image resize to required dimensions and returns resulting url (cached resized image)
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function ImageSrc($params)
 	{
 		$max_width = isset($params['MaxWidth']) ? $params['MaxWidth'] : false;
 		$max_height = isset($params['MaxHeight']) ? $params['MaxHeight'] : false;
 
 		$logo_filename = isset($params['LogoFilename']) ? $params['LogoFilename'] : false;
 		$logo_h_margin = isset($params['LogoHMargin']) ? $params['LogoHMargin'] : false;
 		$logo_v_margin = isset($params['LogoVMargin']) ? $params['LogoVMargin'] : false;
 		$object = $this->getObject($params);
 
 		$field = $this->SelectParam($params, 'name,field');
 		return $object->GetField($field, 'resize:'.$max_width.'x'.$max_height.';wm:'.$logo_filename.'|'.$logo_h_margin.'|'.$logo_v_margin);
 	}
 
 	/**
 	 * Allows to retrieve given setting from unit config
 	 *
 	 * @param Array $params
 	 * @return mixed
 	 */
 	function UnitOption($params)
 	{
 		return $this->Application->getUnitOption($this->Prefix, $params['name']);
 	}
 
 	/**
 	 * Returns list of allowed toolbar buttons or false, when all is allowed
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function VisibleToolbarButtons($params)
 	{
 		$preset_name = kUtil::replaceModuleSection($params['title_preset']);
 		$title_presets = $this->Application->getUnitOption($this->Prefix, 'TitlePresets');
 
 		if (!array_key_exists($preset_name, $title_presets)) {
 			trigger_error('Title preset not specified or missing (in tag "<strong>' . $this->getPrefixSpecial() . ':' . __METHOD__ . '</strong>")', E_USER_NOTICE);
 			return false;
 		}
 
 		$preset_info = $title_presets[$preset_name];
 		if (!array_key_exists('toolbar_buttons', $preset_info) || !is_array($preset_info['toolbar_buttons'])) {
 			return false;
 		}
 
 		// always add search buttons
 		array_push($preset_info['toolbar_buttons'], 'search', 'search_reset_alt');
 		$toolbar_buttons = array_values($preset_info['toolbar_buttons']); // reset index
 
 		return $toolbar_buttons ? trim(json_encode($toolbar_buttons), '[]') : 'false';
 	}
 
 	/**
 	 * Checks, that "To" part of at least one of range filters is used
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function RangeFiltersUsed($params)
 	{
 		$search_helper = $this->Application->recallObject('SearchHelper');
 		/* @var $search_helper kSearchHelper */
 
 		return $search_helper->rangeFiltersUsed($this->getPrefixSpecial(), $params['grid']);
 	}
 
 	/**
 	 * This is abstract tag, used to modify unit config data based on template, where it's used.
 	 * Tag is called from "combined_header" block in admin only.
 	 *
 	 * @param Array $params
 	 */
 	function ModifyUnitConfig($params)
 	{
 
 	}
 
 	/**
 	 * Checks, that field is visible on edit form
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function FieldVisible($params)
 	{
 		$check_field = $params['field'];
 		$fields = $this->Application->getUnitOption($this->Prefix, 'Fields');
 
 		if (!array_key_exists($check_field, $fields)) {
 			// field not found in real fields array -> it's 100% virtual then
 			$fields = $this->Application->getUnitOption($this->Prefix, 'VirtualFields', Array ());
 		}
 
 		if (!array_key_exists($check_field, $fields)) {
 			$params['field'] = 'Password';
 			return $check_field == 'VerifyPassword' ? $this->FieldVisible($params) : true;
 		}
 
 		$show_mode = array_key_exists('show_mode', $fields[$check_field]) ? $fields[$check_field]['show_mode'] : true;
 
 		if ($show_mode === smDEBUG) {
 			return defined('DEBUG_MODE') && DEBUG_MODE;
 		}
 
 		return $show_mode;
 	}
 
 	/**
 	 * Checks, that there area visible fields in given section on edit form
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function FieldsVisible($params)
 	{
 		if (!$params['fields']) {
 			return true;
 		}
 
 		$check_fields = explode(',', $params['fields']);
 		$fields = $this->Application->getUnitOption($this->Prefix, 'Fields');
 		$virtual_fields = $this->Application->getUnitOption($this->Prefix, 'VirtualFields');
 
 		foreach ($check_fields as $check_field) {
 			// when at least one field in subsection is visible, then subsection is visible too
 
 			if (array_key_exists($check_field, $fields)) {
 				$show_mode = array_key_exists('show_mode', $fields[$check_field]) ? $fields[$check_field]['show_mode'] : true;
 			}
 			else {
 				$show_mode = array_key_exists('show_mode', $virtual_fields[$check_field]) ? $virtual_fields[$check_field]['show_mode'] : true;
 			}
 
 			if (($show_mode === true) || (($show_mode === smDEBUG) && (defined('DEBUG_MODE') && DEBUG_MODE))) {
 				// field is visible
 				return true;
 			}
 		}
 
 		return false;
 	}
 
 	/**
 	 * Checks, that requested option is checked inside field value.
 	 *
 	 * @param array $params Tag params.
 	 *
 	 * @return boolean
 	 */
 	protected function Selected(array $params)
 	{
 		/** @var kDBItem $object */
 		$object = $this->getObject($params);
 
 		$field = $this->SelectParam($params, 'name,field');
 		$value = $object->GetDBField($field);
 
 		if ( strpos($value, '|') !== false ) {
 			$selected_values = explode('|', substr($value, 1, -1));
 		}
 		else {
 			$selected_values = array((string)$value);
 		}
 
 		return in_array((string)$params['value'], $selected_values, true);
 	}
 
 	/**
 	 * Displays option name by it's value
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function OptionValue($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$value = $params['value'];
 		$field = $this->SelectParam($params, 'name,field');
 
 		$field_options = $object->GetFieldOptions($field);
 
 		if ( isset($field_options['options'][$value]) ) {
 			$value = $field_options['options'][$value];
 			$use_phrases = isset($field_options['use_phrases']) ? $field_options['use_phrases'] : false;
 
 			return $use_phrases ? $this->Application->Phrase($value) : $value;
 		}
 
 		return '';
 	}
 
 	/**
 	 * Returns/sets form name for current object
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function FormName($params)
 	{
 		$form_name = $this->SelectParam($params, 'name,form,form_name');
 
 		if ( $form_name ) {
 			$prefix = $this->getPrefixSpecial();
 
 			if ( $this->Application->hasObject( $this->getPrefixSpecial() ) ) {
 				$object = $this->getObject($params);
 				/* @var $object kDBItem */
 
 				if ( $object->getFormName() != $form_name ) {
 					trigger_error('Setting form to "<strong>' . $form_name . '</strong>" failed, since object "<strong>' . $this->getPrefixSpecial() . '</strong>" is created before FormName tag (e.g. in event or another tag).', E_USER_WARNING);
 				}
 			}
 			else {
 				$forms = $this->Application->GetVar('forms', Array ());
 				$forms[ $this->getPrefixSpecial() ] = $form_name;
 				$this->Application->SetVar('forms', $forms);
 			}
 
 			return '';
 		}
 
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		return $object->getFormName();
 	}
 
 	/**
 	 * Just reloads the object using given parameters
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function ReloadItem($params)
 	{
 		$params['requery'] = 1;
 
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		return '';
 	}
 }
Index: branches/5.2.x/core/units/visits/visits_tag_processor.php
===================================================================
--- branches/5.2.x/core/units/visits/visits_tag_processor.php	(revision 16455)
+++ branches/5.2.x/core/units/visits/visits_tag_processor.php	(revision 16456)
@@ -1,179 +1,180 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Portal
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license      GNU/GPL
 * In-Portal is Open Source software.
 * This means that this software may have been modified pursuant
 * the GNU General Public License, and as distributed it includes
 * or is derivative of works licensed under the GNU General Public License
 * or other free or open source software licenses.
 * See http://www.in-portal.org/license for copyright notices and details.
 */
 
 	defined('FULL_PATH') or die('restricted access!');
 
 	class VisitsTagProcessor extends kDBTagProcessor {
 
 		function UserFound($params)
 		{
 			$virtual_users = Array(USER_ROOT, USER_GUEST, 0);
 
 			$object = $this->getObject($params);
 			/* @var $object kDBItem */
 
 			return !in_array( $object->GetDBField( $params['user_field'] ) , $virtual_users );
 		}
 
 		/**
 		 * Returns link for user editing
 		 *
 		 * @param Array $params
 		 *
 		 * @return string
 		 * @access protected
 		 */
 		protected function UserLink($params)
 		{
 			$object = $this->getObject($params);
 			/* @var $object kDBItem */
 
 			$user_id = $object->GetDBField( $params['user_field'] );
 
 			if (!$user_id) {
 				return '';
 			}
 
 			$url_params =  Array (
 				'm_opener' => 'd',
 				'u_mode' => 't',
 				'u_event' => 'OnEdit',
 				'u_id' => $user_id,
 				'pass' => 'all,u'
 			);
 
 			return $this->Application->HREF($params['edit_template'], '', $url_params);
 		}
 
 		function getDateLimitClause($field)
 		{
 			$search_filter = $this->Application->RecallVar( $this->getPrefixSpecial().'_search_filter');
 			if($search_filter)
 			{
 				$search_filter = unserialize($search_filter);
 				return $search_filter[$field]['value'];
 			}
 			return '';
 		}
 
 		function AffiliateOrderInfo($params)
 		{
 			$list =& $this->GetList($params);
 
 			$date_limit = str_replace($list->TableName, 'vis', $this->getDateLimitClause('VisitDate') );
 
 			$affil_table = $this->Application->getUnitOption('affil', 'TableName');
 			$affil_idfield = $this->Application->getUnitOption('affil', 'IDField');
 			$sql = 'SELECT '.$affil_idfield.' FROM '.$affil_table.' WHERE PortalUserId = '.$this->Application->RecallVar('user_id');
 			$affiliate_id = $this->Conn->GetOne($sql);
 
 			$sql = 'SELECT COUNT(ord.OrderId) AS OrderCount
 					FROM '.$list->TableName.' vis
 					LEFT JOIN '.TABLE_PREFIX.'Orders ord ON ord.VisitId = vis.VisitId
 					WHERE (vis.AffiliateId = '.$affiliate_id.') AND (ord.Status = '.ORDER_STATUS_PROCESSED.')'.($date_limit ? ' AND '.$date_limit : '');
 
 			$result = $this->Conn->GetRow($sql);
 
 			$sql = 'SELECT COUNT(*) FROM '.$list->TableName.' vis
 					WHERE AffiliateId = '.$affiliate_id.($date_limit ? ' AND '.$date_limit : '');
 
 			$result['TotalVisitors'] = $this->Conn->GetOne($sql);
 			$result['OrderTotalAmount'] = $list->getTotal('OrderTotalAmount', 'SUM');
 			$result['OrderAffiliateCommission'] = $list->getTotal('OrderAffiliateCommission', 'SUM');
 
 			$block_params = $this->prepareTagParams($params);
 			$block_params['name'] = $params['render_as'];
 
 			$format_fields = Array('OrderTotalAmount', 'OrderAffiliateCommission');
 
 			if (array_key_exists('currency', $params) && $params['currency']) {
 				$iso = $this->GetISO($params['currency']);
 				foreach($format_fields as $format_field)
 				{
 					$format = $list->GetFieldOption($format_field, 'format');
 					$value = sprintf($format, $result[$format_field]);
 					$value = $this->ConvertCurrency($value, $iso);
 					$value = $this->AddCurrencySymbol($value, $iso);
 					$result[$format_field] = $value;
 				}
 			}
 
 			$block_params = array_merge($block_params, $result);
 
 			return $this->Application->ParseBlock($block_params);
 		}
 
 		function ListVisitors($params)
 		{
 			$o = '';
 
 			$params['render_as'] = $params['item_render_as'];
 
 			$o_visitors = $this->PrintList2($params);
 
 			if($o_visitors)
 			{
 				$header = '';
 				$footer = '';
 
 				$block_params = $this->prepareTagParams($params);
 
 				$header_block = getArrayValue($params, 'header_render_as');
 				if($header_block)
 				{
 					$block_params['name'] = $header_block;
 					$header = $this->Application->ParseBlock($block_params);
 				}
 
 				$footer_block = getArrayValue($params, 'footer_render_as');
 				if($footer_block)
 				{
 					$block_params['name'] = $footer_block;
 					$footer = $this->Application->ParseBlock($block_params);
 				}
 
 				$o = $header.$o_visitors.$footer;
 			}
 			else
 			{
 				$visitors_params = array('name' => $params['empty_myvisitors_render_as']);
 				$o = $this->Application->ParseBlock($visitors_params);
 			}
 
 			return $o;
 
 		}
 
 		/**
 		 * Enter description here...
 		 *
 		 * @param string $params
 		 * @return kDBList
 		 */
 		function &GetList($params)
 		{
-			$list_name = $this->SelectParam($params, 'list_name,name');
+			$list_name = array_key_exists('list_name', $params) ? $params['list_name'] : '';
+
 			if ( !$list_name ) {
 				$list_name = $this->Application->Parser->GetParam('list_name');
 			}
 
 			$types = $this->SelectParam($params, 'types');
 
 			if ( $types == 'myvisitororders' || $types == 'myvisitors' ) {
 				$this->nameToSpecialMapping[$list_name] = 'incommerce';
 			}
 
 			return parent::GetList($params);
 		}
 	}
Index: branches/5.2.x/core/admin_templates/config/config_universal.tpl
===================================================================
--- branches/5.2.x/core/admin_templates/config/config_universal.tpl	(revision 16455)
+++ branches/5.2.x/core/admin_templates/config/config_universal.tpl	(revision 16456)
@@ -1,151 +1,151 @@
 <inp2:m_include t="incs/header"/>
 
-<inp2:conf_InitList name="Default" per_page="-1"/>
+<inp2:conf_InitList per_page="-1"/>
 <inp2:m_Get name="section" no_html_escape="1" result_to_var="section"/>
 <inp2:m_RenderElement name="combined_header" prefix="conf" section="$section" title_preset="section_label" perm_event="conf:OnLoad"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 	<tbody>
 		<tr>
 			<td>
 				<script type="text/javascript">
 					function validate_password_fields() {
 						var $validated = true;
 
 						$("input[primarytype='password']", '#' + $form_name).each(
 							function ($e) {
 								if ( !validate_password_field(this.id) ) {
 									$validated = false;
 								}
 							}
 						);
 
 						return $validated;
 					}
 
 					function validate_password_field($field_id) {
 						var password_field = document.getElementById($field_id),
 							password_verify_field = document.getElementById('verify_' + $field_id);
 
 						if ( password_field && password_verify_field && password_field.value == password_verify_field.value ) {
 							return true;
 						}
 						else {
 							var password_error_cell = document.getElementById('error_' + $field_id);
 
 							if ( password_error_cell ) {
 								$(window).scrollTop($(password_field).position().top - 15);
 								password_error_cell.innerHTML = '<inp2:m_Phrase name="la_error_PasswordMatch"/>';
 							}
 
 							return false;
 						}
 					}
 
 					function toggle_section($label) {
 						var $row = null,
 							$is_visible = false,
 							$table = document.getElementById('config_table');
 
 						for (var $i = 0; $i < $table.rows.length; $i++) {
 							$row = $table.rows[$i];
 							if ( $row.getAttribute('header_label') != $label ) {
 								continue;
 							}
 
 							if ( !$row.style.display ) {
 								$row.style.display = document.all ? 'block' : 'table-row';
 							}
 
 							$is_visible = !($row.style.display == 'none');
 							$row.style.display = $is_visible ? 'none' : (document.all ? 'block' : 'table-row');
 
 							document.getElementById('toggle_mark[' + $label + ']').innerHTML = '[' + ($is_visible ? '+' : '-') + ']';
 						}
 					}
 
 					var a_toolbar = new ToolBar();
 
 					a_toolbar.AddButton(
 						new ToolBarButton(
 							'select',
 							'<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>',
 							function () {
 								submit_event('conf', '<inp2:conf_SaveEvent/>');
 							}
 						)
 					);
 
 					a_toolbar.AddButton(
 						new ToolBarButton(
 							'cancel',
 							'<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>',
 							function () {
 								submit_event('conf', 'OnCancel');
 							}
 						)
 					);
 
 					<inp2:m_if check="m_IsDebugMode">
 						a_toolbar.AddButton( new ToolBarSeparator('sep1') );
 
 						a_toolbar.AddButton(
 							new ToolBarButton(
 								'new_item',
 								'<inp2:m_phrase label="la_ToolTip_NewSystemSetting" escape="1"/>::<inp2:m_phrase label="la_ToolTip_Add" escape="1"/>',
 								function() {
 									std_precreate_item('conf', 'config/config_edit');
 								}
 							)
 						);
 					</inp2:m_if>
 
 					<inp2:m_ModuleInclude template = "config/custom_toolbar"/>
 
 					a_toolbar.Render();
 				</script>
 			</td>
 		</tr>
 	</tbody>
 </table>
 
 <inp2:m_include t="incs/config_blocks"/>
 
 <inp2:m_RenderElement name="config_updated_notice"/>
 <inp2:conf_SaveWarning name="grid_save_warning"/>
 
 <table width="100%" border="0" cellspacing="0" cellpadding="4" class="bordered" id="config_table">
 	<inp2:conf_PrintList list_name="default" block="config_block" full_block="config_block" half_block1="config_block1" half_block2="config_block2" value_render_as="cf_default_value"/>
 </table>
 
 <script type="text/javascript">
 	<inp2:m_if check="m_Get" name="refresh_tree">
 		getFrame('menu').location.reload();
 	</inp2:m_if>
 
 	<inp2:m_if check="m_Get" name="refresh_all">
 		var $menu_frame = getFrame('menu');
 
 		$menu_frame.parent.location.href = $menu_frame.parent.location.href;
 	</inp2:m_if>
 
 	Application.setHook(
 		'conf:*',
 		function ($event) {
 			$event.status = $event.Name == 'OnCancel' ? true : validate_password_fields();
 		}
 	);
 
 	<inp2:m_if check="m_Get" name="first_error">
 		$(document).ready(function () {
 			var $error_cell = $('.field-<inp2:m_Get name="first_error"/>.error');
 
 			if ( $error_cell.length ) {
 				$(window).scrollTop($error_cell.position().top - 15);
 			}
 		});
 	</inp2:m_if>
 </script>
 
 <inp2:m_include t="incs/footer"/>