Index: branches/5.0.x/themes/default2009/platform/designs/default_design.des.tpl
===================================================================
--- branches/5.0.x/themes/default2009/platform/designs/default_design.des.tpl	(revision 12297)
+++ branches/5.0.x/themes/default2009/platform/designs/default_design.des.tpl	(revision 12298)
@@ -1,123 +1,123 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <inp2:m_CheckSSL/>
 <inp2:m_include template="platform/elements/side_boxes.elm" strip_nl="1"/>
 <inp2:m_include template="platform/elements/content_boxes.elm" strip_nl="1"/>
 <inp2:m_include template="platform/elements/forms.elm" strip_nl="1"/>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 	<head>
 		<inp2:m_DefineElement name="cms_page_title">
 			<inp2:st_PageInfo type="htmlhead_title"/>
 		</inp2:m_DefineElement>
 
 		<title><inp2:m_GetConfig name="Site_Name"/> :: <inp2:m_RenderElement name="page_title" default_element="cms_page_title" no_editing="1"/></title>
 
 		<!--## Include module specific HEADER (META INFORMATION inside) template ##-->
 		<inp2:m_ModuleInclude template="elements/html_head.elm" in-portal_template="platform/elements/html_head.elm"/>
 
 		<inp2:st_EditingScripts/>
 		<!--## /Include module specific HEADER template ##-->
 	</head>
 	<body>
 		<inp2:st_EditPage mode="start"/>
 		<div align="left">
 			<div align="left" style="width:100%">
 				<table class="fullwidth">
 					<tr>
 						<td>
 							<inp2:m_include template="platform/elements/header.elm"/>
 						</td>
 					</tr>
 					<tr>
 						<td>
 							<inp2:m_include template="platform/elements/menu.elm"/>
 						</td>
 					</tr>
 				</table>
 
 				<img src="<inp2:m_TemplatesBase module="In-Portal"/>img/s.gif" width="1" height="1" alt=""/><br />
 				<img src="<inp2:m_TemplatesBase module="In-Portal"/>img/grey_pix.gif" width="100%" height="1" alt=""/><br />
 				<img src="<inp2:m_TemplatesBase module="In-Portal"/>img/s.gif" width="1" height="1" alt=""/><br />
 
 				<table class="fullwidth">
 					<tr>
 						<!-- SIDEBAR -->
 						<td style="width: 200px;" valign="top">
 							<inp2:m_DefineElement name="cms_sidebar">
 								<div class="movable-area">
 									<div class="movable-element">
 										<inp2:m_RenderElement name="platform/elements/side_boxes/login.elm" design="blue_box"/>
 									</div>
 									<div class="movable-element">
 										<inp2:m_RenderElement name="platform/elements/side_boxes/search.elm" design="blue_box"/>
 									</div>
 								</div>
 							</inp2:m_DefineElement>
 
-							<inp2:m_RenderElement name="sidebar" default_element="cms_sidebar" layout_view="1"/>
+							<inp2:m_RenderElement name="sidebar" default_element="cms_sidebar"/>
 						</td>
 						<!-- /SIDEBAR -->
 
 						<!-- SEPARATOR -->
 						<td width="3" class="vertical-separator" style="width: 3px;">
 							<img src="<inp2:m_TemplatesBase module="In-Portal"/>img/s.gif" width="3" height="1" alt=""/><br />
 						</td>
 						<!-- /SEPARATOR -->
 
 						<!-- CONTENT -->
 						<td style="width: auto;" valign="top">
 							<inp2:m_DefineElement name="cms_content">
 								<div class="movable-area">
 									<div class="movable-element">
 										<inp2:m_include template="platform/elements/navigation_bar.elm"/>
 									</div>
 
 									<div class="movable-element">
 										<inp2:m_RenderElement design="content_box">
 											<inp2:m_Capture to_var="header">
 												<inp2:st_PageInfo type="title"/>
 											</inp2:m_Capture>
 
 											<inp2:st_ContentBlock num="1"/>
 										</inp2:m_RenderElement>
 									</div>
 								</div>
 							</inp2:m_DefineElement>
 
-							<inp2:m_RenderElement name="content" default_element="cms_content" layout_view="1"/>
+							<inp2:m_RenderElement name="content" default_element="cms_content"/>
 							<br />
 						</td>
 						<!-- /CONTENT -->
 
 						<!--## REMOVE THIS LINE TO UNCOMMENT
 						<!-- SEPARATOR -->
 						<td width="3" class="vertical-separator">
 							<img src="<inp2:m_TemplatesBase module="In-Portal"/>img/s.gif" width="3" height="1" alt=""/><br />
 						</td>
 						<!-- /SEPARATOR -->
 
 						<!-- RIGHT-SIDEBAR WITH BANNER -->
 						<td style="width: 200px;" valign="top">
 							<div class="movable-area">
 								<div class="movable-element">
 									<inp2:m_include template="platform/elements/banners/banner_right.elm"/>
 								</div>
 							</div>
 						</td>
 						<!-- /RIGHT-SIDEBAR WITH BANNER -->
 						REMOVE THIS LINE TO UNCOMMENT ##-->
 					</tr>
 				</table>
 
 				<table class="fullwidth">
 					<tr>
 						<td >
 							<inp2:m_include template="platform/elements/footer.elm"/>
 						</td>
 					</tr>
 				</table>
 			</div>
 		</div>
 		<inp2:st_EditPage mode="end"/>
 	</body>
 </html>
\ No newline at end of file
Index: branches/5.0.x/themes/default2009/platform/elements/side_boxes/search.elm.tpl
===================================================================
--- branches/5.0.x/themes/default2009/platform/elements/side_boxes/search.elm.tpl	(revision 12297)
+++ branches/5.0.x/themes/default2009/platform/elements/side_boxes/search.elm.tpl	(revision 12298)
@@ -1,51 +1,51 @@
 <inp2:m_Capture to_var="header">
 	<inp2:m_phrase name="lu_title_SearchBox"/>
 </inp2:m_Capture>
 
 <form method="post" action="<inp2:m_Link template="platform/search/search_results" pass_category="1"/>">
 	<inp2:m_GetFormHiddens template="platform/search/search_results"/>
 	<table>
 		<tr>
 			<td colspan="2">
 				<input type="text" name="keywords" id="keywords" style="width: 155px;" class="input-text" value="" />
 			</td>
 		</tr>
 		<!--## Show only when not on home ##-->
 		<inp2:m_if check="m_GetEquals" var="m_cat_id" value="0" inverse="1">
 		<tr>
 			<td>
 				<input type="radio" name="search_scope" id="search_scope_any" value="any" checked />
 			</td>
 			<td>
 				<label for="search_scope_any"><inp2:m_Phrase name="lu_AllWebsite"/></label>
 			</td>
 		</tr>
 		<tr>
 			<td>
 				<input type="radio" name="search_scope" id="search_scope_category" value="category"/>
 			</td>
 			<td>
 				<label for="search_scope_category"><inp2:m_Phrase name="lu_ThisCategory"/></label>
 			</td>
 		</tr>
 		</inp2:m_if>
 		<!--## // Show only when not on home ##-->
 	</table>
 
 	<br />
-	<input class="button" type="submit" value="<inp2:m_Phrase label="lu_btn_FindIt"/>!" />
+	<input class="button" type="submit" value="<inp2:m_Phrase label='lu_btn_FindIt' no_editing='1'/>!" />
 
 	<!--##
 	<img src="<inp2:m_TemplatesBase module="In-Portal"/>img/s.gif" alt="" width="1" height="10" border="0" /><br />
 	<table>
 		<tr>
 			<td width="10">
 				<input class="button" type="submit" style="width: 40px;" value="<inp2:m_Phrase label="lu_comm_Go"/>!" />
 			</td>
 			<td align="left">
 				<a href="<inp2:m_Link template="platform/search/advanced_search" />" class="more-link"><inp2:m_Phrase label="lu_btn_AdvancedSearch"/></a>  <img src="<inp2:m_TemplatesBase module="In-Portal"/>img/side_link_str.gif" width="6" height="5" alt="" /><br />
 			</td>
 		</tr>
 	</table>
 	##-->
 </form>
\ No newline at end of file
Index: branches/5.0.x/themes/default2009/platform/elements/side_boxes/login.elm.tpl
===================================================================
--- branches/5.0.x/themes/default2009/platform/elements/side_boxes/login.elm.tpl	(revision 12297)
+++ branches/5.0.x/themes/default2009/platform/elements/side_boxes/login.elm.tpl	(revision 12298)
@@ -1,125 +1,125 @@
 <!-- LOGIN BOX TITLE -->
 <inp2:m_Capture to_var="header">
 	<table class="fullwidth">
 		<tr>
 			<td class="side-box-title" align="left">
 				<inp2:m_phrase name="lu_title_LoginBox"/>
 			</td>
 			<td align="right" class="login-status">
 
 				<!-- IF LOGGED IN SHOW NAME -->
 				<inp2:m_if check="m_LoggedIn">
 					<a href="<inp2:m_Link template="platform/my_account/my_profile" m_cat_id="0" m_cat_page="1"/>"><inp2:u_Field name="FirstName"/> <inp2:u_Field name="LastName"/></a><br />
 				<!-- /IF LOGGED IN SHOW NAME -->
 				<inp2:m_else/>
 
 					<table>
 						<tr>
 							<td width="11">
 								<img src="<inp2:m_TemplatesBase module="In-Portal"/>img/not_logged.gif" alt="" width="11" height="11" border="0" /><br />
 							</td>
 							<td class="login-status">
 								&nbsp;<inp2:m_Phrase label="lu_NotLoggedIn"/>
 							</td>
 						</tr>
 					</table>
 				</inp2:m_if>
 			</td>
 		</tr>
 	</table>
 </inp2:m_Capture>
 <!-- /LOGIN BOX TITLE -->
 
 <!-- IF LOGGED! -->
 <inp2:m_if check="m_LoggedIn">
 	<table width="100%" style="border-width: 0px;">
 		<tr>
 			<td colspan="2"><strong><inp2:m_phrase name="lu_section_MyAccount"/></strong></td>
 		</tr>
 
 		<!-- SHOW MY PROFILE -->
 		<inp2:m_RenderElement name="box_element" template="platform/my_account/my_profile" title="lu_MyProfile"/>
 		<!-- /SHOW MY PROFILE -->
 
 		<!-- SHOW MY FAVORITES -->
 		<inp2:m_RenderElement name="box_element" template="platform/my_account/my_favorites" title="lu_MyFavorites"/>
 		<!-- /SHOW MY FAVORITES -->
 
 		<!-- SHOW MY PREFERENCES -->
 		<inp2:m_RenderElement name="box_element" template="platform/my_account/my_preferences" title="lu_MyPreferences"/>
 		<!-- /SHOW MY PREFERENCES -->
 
 		<!-- INCLUDE "themes/default2007/[MODULE_NAME]/my_account/my_items.elm.tpl" FOR EACH INSTALLED MODULE -->
 		<inp2:m_ModuleInclude template="my_account/my_items.elm" place="sidebox" section="1"/>
 		<!-- /INCLUDE "themes/[MODULE_NAME]/my_account/my_items.elm.tpl" FOR EACH INSTALLED MODULE -->
 
 		<tr>
 			<td>
 				<img src="<inp2:m_TemplatesBase module="In-Portal"/>img/menu-li-2-level.gif" alt="" width="4" height="4" border="0" /><br />
 			</td>
 			<td>
 				<a href="<inp2:u_LogoutLink template="index" />"><inp2:m_Phrase label="lu_logout"/></a>
 			</td>
 		</tr>
 
 		<tr>
 			<td colspan="2">
 		<img src="<inp2:m_TemplatesBase module="In-Portal"/>img/s.gif" alt="" width="1" height="7" border="0" /><br />
 			</td>
 		</tr>
 
 		<tr>
 			<td colspan="2">
 				<strong><inp2:m_phrase name="lu_section_MyItems"/></strong>
 			</td>
 		</tr>
 
 		<inp2:m_ModuleInclude template="my_account/my_items.elm" place="sidebox" section="2"/>
 	</table>
 
 <!-- /IF LOGGED -->
 <inp2:m_else/>
 <!-- IF NOT LOGGED IN! -->
 
 	<form method="post" action="<inp2:m_FormAction />">
 		<inp2:m_if check="u_UseUsernames">
 			<inp2:m_phrase label="lu_username"/><br />
 			<input class="input-text" type="text" name="login" style="width:155px" /><br />
 		<inp2:m_else/>
 			<inp2:m_phrase label="lu_email"/><br />
 			<input class="input-text" type="text" name="email" style="width:155px" /><br />
 		</inp2:m_if>
 
 		<img src="<inp2:m_TemplatesBase module="In-Portal"/>img/s.gif" width="1" height="5" alt=""/><br />
 
 		<inp2:m_Phrase label="lu_Password"/><br />
 		<input type="password" class="input-text" name="password" style="width:155px" /><br />
 
 		<img src="<inp2:m_TemplatesBase module="In-Portal"/>img/s.gif" alt="" width="1" height="10" border="0" /><br />
 
 		<table>
 			<tr>
 				<td width="10">
-					<input class="button" name="events[u][OnLogin]" type="submit" value="<inp2:m_Phrase label="lu_Login"/>" /><br />
+					<input class="button" name="events[u][OnLogin]" type="submit" value="<inp2:m_Phrase label='lu_Login' no_editing='1'/>" /><br />
 				</td>
 				<td align="left">
 					<input type="checkbox" name="cb_remember_login" value="1"/> <span class="remember-login"><inp2:m_Phrase label="lu_remember_login"/></span>
 				</td>
 			</tr>
 		</table>
 
 		<img src="<inp2:m_TemplatesBase module="In-Portal"/>img/s.gif" alt="" width="5" height="5" border="0" /><br />
 		<inp2:m_if check="u_HasError" field="any">
 			<span class="field-error"><inp2:u_Error field="ValidateLogin"/></span><br />
 		</inp2:m_if>
 
 		<inp2:m_if check="u_RegistrationEnabled">
 			<a href="<inp2:m_Link template="platform/login/register" m_cat_id="0" m_cat_page="1"/>" class="more-link" ><inp2:m_Phrase label="lu_Register"/></a> <img src="<inp2:m_TemplatesBase module="In-Portal"/>img/side_link_str.gif" width="6" height="5" alt="" /><br />
 		</inp2:m_if>
 
 		<a href="<inp2:m_Link template="platform/login/forgot_password" m_cat_id="0" m_cat_page="1"/>" class="more-link" ><inp2:m_Phrase label="lu_ForgotPassword"/>?</a>  <img src="<inp2:m_TemplatesBase module="In-Portal"/>img/side_link_str.gif" width="6" height="5" alt="" />
 		<input type="hidden" name="next_template" value="<inp2:m_get var="next_template"/>" />
 		<input type="hidden" name="pending_disabled_template" value="platform/login/login_pending_disabled" />
 	</form>
 </inp2:m_if>
 <!-- /IF NOT LOGGED IN -->
Index: branches/5.0.x/themes/default2009/platform/elements/side_boxes/mailing_list.elm.tpl
===================================================================
--- branches/5.0.x/themes/default2009/platform/elements/side_boxes/mailing_list.elm.tpl	(revision 12297)
+++ branches/5.0.x/themes/default2009/platform/elements/side_boxes/mailing_list.elm.tpl	(revision 12298)
@@ -1,21 +1,21 @@
-<inp2:m_Capture to_var="header">
-	<inp2:m_phrase name="lu_title_MailingList"/>
-</inp2:m_Capture>
-
-<inp2:m_Phrase label="lu_EnterEmailToSubscribe"/><br />
-<img src="<inp2:m_TemplatesBase module="In-Portal"/>img/s.gif" alt="" width="1" height="5" border="0" /><br />
-
-<form method="POST" action="<inp2:m_FormAction />" name="mailing_list_form">	
-	<input type="text" name="subscriber_email" class="input-text" style="width: 155px;"/><br />
-	<inp2:m_if check="u_HasError" field="any">
-		<span class="field-error"><inp2:u_Error field="SubscribeEmail"/></span><br />
-	</inp2:m_if>
-
-	<br />
-	<input class="button" name="events[u][OnSubscribeQuery]" type="submit" style="width: 90px;" value="<inp2:m_Phrase label="lu_btn_Subscribe"/>" />
-	<input class="button" name="events[u][OnSubscribeQuery]" type="submit" style="width: 90px;" value="<inp2:m_Phrase label="lu_btn_Unsubscribe" />" />
-	&nbsp;
-	<input type="text" style="display: none" />
-	<input type="hidden" name="subscribe_template" value="platform/mailing_list/subscribe"/>
-	<input type="hidden" name="unsubscribe_template" value="platform/mailing_list/unsubscribe"/>
-</form>
+<inp2:m_Capture to_var="header">
+	<inp2:m_phrase name="lu_title_MailingList"/>
+</inp2:m_Capture>
+
+<inp2:m_Phrase label="lu_EnterEmailToSubscribe"/><br />
+<img src="<inp2:m_TemplatesBase module="In-Portal"/>img/s.gif" alt="" width="1" height="5" border="0" /><br />
+
+<form method="POST" action="<inp2:m_FormAction />" name="mailing_list_form">
+	<input type="text" name="subscriber_email" class="input-text" style="width: 155px;"/><br />
+	<inp2:m_if check="u_HasError" field="any">
+		<span class="field-error"><inp2:u_Error field="SubscribeEmail"/></span><br />
+	</inp2:m_if>
+
+	<br />
+	<input class="button" name="events[u][OnSubscribeQuery]" type="submit" style="width: 90px;" value="<inp2:m_Phrase label='lu_btn_Subscribe' no_editing='1'/>" />
+	<input class="button" name="events[u][OnSubscribeQuery]" type="submit" style="width: 90px;" value="<inp2:m_Phrase label='lu_btn_Unsubscribe' no_editing='1'/>" />
+	&nbsp;
+	<input type="text" style="display: none" />
+	<input type="hidden" name="subscribe_template" value="platform/mailing_list/subscribe"/>
+	<input type="hidden" name="unsubscribe_template" value="platform/mailing_list/unsubscribe"/>
+</form>
Index: branches/5.0.x/themes/default2009/platform/elements/side_boxes/recommend_site.elm.tpl
===================================================================
--- branches/5.0.x/themes/default2009/platform/elements/side_boxes/recommend_site.elm.tpl	(revision 12297)
+++ branches/5.0.x/themes/default2009/platform/elements/side_boxes/recommend_site.elm.tpl	(revision 12298)
@@ -1,16 +1,16 @@
 <inp2:m_Capture to_var="header">
 	<inp2:m_phrase name="lu_title_RecommendSite"/>
 </inp2:m_Capture>
 
 <inp2:m_Phrase label="lu_EnterEmailToRecommend"/><br />
 <img src="<inp2:m_TemplatesBase module="In-Portal"/>img/s.gif" alt="" width="1" height="5" border="0" /><br />
 
 <form method="POST" action="<inp2:m_FormAction />">
 	<input type="text" class="input-text" name="friend_email" value="" style="width: 155px;" /><br />
 	<inp2:m_if check="u_HasError" field="any">
 		<span class="field-error"><inp2:u_Error field="Email"/></span><br />
 	</inp2:m_if>
 	<br />
-	<input class="button" name="events[u][OnRecommend]" type="submit" value="<inp2:m_Phrase label="lu_btn_Recommend"/>" />
+	<input class="button" name="events[u][OnRecommend]" type="submit" value="<inp2:m_Phrase label='lu_btn_Recommend' no_editing='1'/>" />
 	<input type="hidden" name="template_success" value="platform/recommend/recommend" />
 </form>
\ No newline at end of file
Index: branches/5.0.x/themes/default2009/platform/elements/html_head.elm.tpl
===================================================================
--- branches/5.0.x/themes/default2009/platform/elements/html_head.elm.tpl	(revision 12297)
+++ branches/5.0.x/themes/default2009/platform/elements/html_head.elm.tpl	(revision 12298)
@@ -1,31 +1,31 @@
 
 <!--## Meta Info (Keywords and Description) ##-->
 <meta http-equiv="Content-Type" content="text/html; charset=<inp2:lang.current_Field name="Charset"/>" />
 
 <meta name="Description" content="<inp2:st_PageInfo type="meta_description"/>" />
 <meta name="Keywords" content="<inp2:st_PageInfo type="meta_keywords"/>" />
 <!--## /Meta Keywords and Description ##-->
 
 <inp2:theme.current_StylesheetFile/>
 <link rel="stylesheet" href="<inp2:m_TemplatesBase module='In-Portal'/>inc/jquery/thickbox/thickbox.css" type="text/css" media="screen" />
 
 <link rel="stylesheet" rev="stylesheet" href="<inp2:m_TemplatesBase module='In-Portal'/>inc/styles.css" type="text/css" />
 
 <script type="text/javascript" src="<inp2:m_TemplatesBase module='In-Portal'/>inc/script.js"></script>
 <script type="text/javascript" src="<inp2:m_TemplatesBase module='In-Portal'/>inc/ajax.js"></script>
 <script type="text/javascript" src="<inp2:m_TemplatesBase module='In-Portal'/>inc/calendar.js"></script>
 
 <script type="text/javascript">var inportalBase = '<inp2:m_TemplatesBase module="In-Portal"/>';</script>
 <script type="text/javascript" src="<inp2:m_TemplatesBase module='In-Portal'/>inc/jquery/jquery.pack.js"></script>
 <script type="text/javascript" src="<inp2:m_TemplatesBase module='In-Portal'/>inc/jquery/thickbox/thickbox.js"></script>
 
 <script type="text/javascript">
 	var aRatingManager = new RatingManager('<inp2:m_Link template="index" events[#PREFIX#]="OnMakeVote" rating="#VOTE#" id="#ID#" no_amp="1" size="#SIZE#"/>');
 
 	<inp2:m_DefineElement name="ml_selector_language_element">
 		<inp2:Field name="LanguageId"/>: {'on': '<inp2:Field name="IconURL" js_ecape="1"/>', 'off': '<inp2:Field name="IconDisabledURL" js_ecape="1"/>'}
 		<inp2:m_ifnot check="m_Param" name="is_last">,</inp2:m_ifnot>
 	</inp2:m_DefineElement>
 
-	var aMultiLanguageSelector = new MultiLanguageSelector({<inp2:lang.enabled_PrintList render_as="ml_selector_language_element" per_page="-1" strip_nl="2"/>}, <inp2:m_Get name="m_lang"/>);
+	var aMultiLanguageSelector = new MultiLanguageSelector({<inp2:lang.enabled_PrintList render_as="ml_selector_language_element" per_page="-1" no_editing="1" strip_nl="2"/>}, <inp2:m_Get name="m_lang"/>);
 </script>
Index: branches/5.0.x/themes/default2009/platform/elements/menu.elm.tpl
===================================================================
--- branches/5.0.x/themes/default2009/platform/elements/menu.elm.tpl	(revision 12297)
+++ branches/5.0.x/themes/default2009/platform/elements/menu.elm.tpl	(revision 12298)
@@ -1,104 +1,109 @@
 <table class="menu-background fullwidth">
 	<tr>
 		<td align="left">
 			<table style="width: auto;">
 				<tr>
 					<td>
 						<script type="text/javascript" src="<inp2:m_TemplatesBase module='In-Portal'/>inc/nlsmenu.js"></script>
 						<script type="text/javascript" src="<inp2:m_TemplatesBase module='In-Portal'/>inc/nlsmenueffect.js"></script>
 						<script type="text/javascript" src="<inp2:m_TemplatesBase module='In-Portal'/>inc/nlsmenuext_dyn.js"></script>
 						<script type="text/javascript" src="<inp2:m_TemplatesBase module='In-Portal'/>inc/nlsmenuext_xml.js"></script>
 
 						<link rel="StyleSheet" href="<inp2:m_TemplatesBase module='In-Portal'/>inc/dmenu.css" type="text/css" />
 						<div id="xmlMenuDiv"></div>
 
 				        <script type="text/javascript">
 				        	<inp2:m_DefineElement name="menu_xml" no_editing="1">
 										<menumgr id="mgr" flowoverformelement="false" defaulteffect="aoslide" icpath="">
 										<!--## USE droponclick="false" TO OPEN MENU ONMOUSE-OVER ##-->
 										  <menubar id="menubar" orient="H" showicon="true" showsubicon="false" stlprf="horz_" droponclick="true" >
 										    <items>
 										    	<item id="sub-elem0" url="<inp2:m_Link template="index" m_cat_id="0" m_cat_page="1"/>" ico="['<inp2:m_TemplatesBase module="In-portal"/>img/menu_home.gif']" enb="true" title=""><![CDATA[<inp2:m_RootCategoryName/>]]></item>
 										    	<inp2:m_Include template="platform/elements/menu_sections.xml" />
 										    </items>
 										  </menubar>
 										</menumgr>
 				        	</inp2:m_DefineElement>
 
 				        	<inp2:m_get name="m_cat_id" result_to_var="current_category"/>
 
-				        	addLoadEvent(
+				        	$(document).ready(
 				        		function() {
 					        	 	var menu_mgr = NlsMenuUtil.createFromXMLString('<inp2:m_RenderElement name="menu_xml" js_escape="1"/>');
 //						        	menu_mgr.renderMenus();
 						        	menu_mgr.renderMenubar('xmlMenuDiv');
+
+						        	<inp2:m_if check="m_GetConst" name="EDITING_MODE" equals_to="2">
+							        	// make all spans with phrases clickable inside menus, that were just created
+										aTemplateManager.setupEditTranslationButtons('#xmlMenuDiv');
+						        	</inp2:m_if>
 					        	}
 					        );
 				        </script>
 				        <noscript>
 							<inp2:m_DefineElement name="static_top_menu_element">
 								<inp2:m_if check="m_Param" name="external_url">
 									<inp2:m_Param name="external_url" result_to_var="link"/>
 								<inp2:m_else/>
 									<inp2:m_Link template="$template" m_cat_id="$cat_id" m_cat_page="1" result_to_var="link"/>
 								</inp2:m_if>
 
 								<inp2:m_if check="m_Param" name="menu_icon">
 									<inp2:m_TemplatesBase result_to_var="module_path"/>
 									<inp2:m_RenderElement name="menu_element" menu_href="$link" menu_title="$title" menu_icon_src="{$module_path}{$menu_icon}"/>
 								<inp2:m_else/>
 									<inp2:m_TemplatesBase module="In-Portal" result_to_var="module_path"/>
 									<inp2:m_RenderElement name="menu_element" menu_href="$link" menu_title="$title" menu_icon_src="{$module_path}img/menu_inedit.gif"/>
 								</inp2:m_if>
 							</inp2:m_DefineElement>
 
 							<table>
 								<tr>
 									<inp2:m_Link template="index" m_cat_id="0" m_cat_page="1" result_to_var="link"/>
 									<inp2:m_RootCategoryName result_to_var="title"/>
 									<inp2:m_TemplatesBase module="In-portal" result_to_var="module_path"/>
 									<inp2:m_RenderElement name="menu_element" menu_href="$link" menu_title="$title" menu_icon_src="{$module_path}img/menu_home.gif"/>
 									<inp2:st_CachedMenu level="0" category_id="0" render_as="static_top_menu_element"/>
 								</tr>
 							</table>
 				        </noscript>
 
 				        <inp2:m_Set m_cat_id="$current_category"/>
 						<inp2:c_Field requery="1" name="Name" result_to_var="category_name"/>
 					</td>
 				</tr>
 			</table>
 		</td>
 		<td align="right">
 			<table style="width: auto;">
 				<tr>
 					<!-- menu: My Account -->
 					<inp2:m_RenderElement design="menu_element">
 						<inp2:m_Capture to_var="menu_href">
 							<inp2:m_Link template="platform/my_account/my_account" m_cat_id="0" m_cat_page="1"/>
 						</inp2:m_Capture>
 
 						<inp2:m_Capture to_var="menu_icon">
 							<img src="<inp2:m_TemplatesBase module="In-Portal"/>img/menu_my_account.gif" alt="" /><br />
 						</inp2:m_Capture>
 
 						<inp2:m_Capture to_var="menu_title">
 							<inp2:m_Phrase name="lu_title_MyAccount"/>
 						</inp2:m_Capture>
 
 						<inp2:m_IsActive template=".*/my_account" result_to_var="current"/>
 					</inp2:m_RenderElement>
 					<!-- // menu: My Account -->
 
 
 					<inp2:m_if check="m_ModuleEnabled" module="In-Commerce">
 					<!-- menu: ShoppingCart -->
 						<inp2:m_Include t="in-commerce/elements/menu_element.elm"/>
 					<!-- // menu: ShoppingCart -->
 					</inp2:m_if>
 
 				</tr>
 			</table>
 		</td>
 	</tr>
 </table>
\ No newline at end of file
Index: branches/5.0.x/themes/default2009/index.tpl
===================================================================
--- branches/5.0.x/themes/default2009/index.tpl	(revision 12297)
+++ branches/5.0.x/themes/default2009/index.tpl	(revision 12298)
@@ -1,58 +1,58 @@
-<!--##
-<NAME>Home</NAME>
-<DESC>Welcome page</DESC>
-<SECTION></SECTION>
-##-->
-
-<!--## PAGE TITLE ELEMENT ##-->
-<inp2:m_DefineElement name="page_title">
-	<inp2:m_phrase name="lu_title_WelcomeTitle"/>
-</inp2:m_DefineElement>
-<!--## //PAGE TITLE ELEMENT ##-->
-
-<!--## SIDE-BAR ELEMENT ##-->
-<inp2:m_DefineElement name="sidebar">
-	<div class="movable-area">
-		<div class="movable-element">
-			<inp2:m_RenderElement name="platform/elements/side_boxes/login.elm" design="blue_box"/>
-		</div>
-		<div class="movable-element">
-			<inp2:m_RenderElement name="platform/elements/side_boxes/search.elm" design="blue_box"/>
-		</div>
-		<div class="movable-element">
-			<inp2:m_RenderElement name="platform/elements/side_boxes/recommend_site.elm" design="blue_box"/>
-		</div>
-		<div class="movable-element">
-			<inp2:m_RenderElement name="platform/elements/side_boxes/mailing_list.elm" design="blue_box"/>
-		</div>
-	</div>
-</inp2:m_DefineElement>
-<!--## /SIDE-BAR ELEMENT ##-->
-
-<!--## MAIN CONTENT ##-->
-<inp2:m_DefineElement name="content">
-	<div class="movable-area">
-		<div class="movable-element">
-			<inp2:m_include template="platform/elements/navigation_bar.elm"/>
-		</div>
-		<div class="movable-element">
-			<inp2:m_RenderElement design="content_box">
-				<inp2:m_Capture to_var="header">
-					<inp2:m_phrase name="lu_title_WelcomeTitle"/>
-				</inp2:m_Capture>
-
-				<inp2:st_ContentBlock num="1"/>
-			</inp2:m_RenderElement>
-		</div>
-		<div class="movable-element">
-			<!--## INCLUDE HOME PAGE ELEMENTS FOR EACH MODULE ##-->
-			<inp2:m_ModuleInclude template="elements/content_boxes/home_page_items.elm" data_exists="1"/>
-			<!--## /HOME PAGE ELEMENTS ##-->
-		</div>
-	</div>
-</inp2:m_DefineElement>
-<!--## /MAIN CONTENT ##-->
-
-<!--## DESIGN TEMPLATE ##-->
-<inp2:m_include template="platform/designs/default_design.des" pass_params="1"/>
+<!--##
+<NAME>Home</NAME>
+<DESC>Welcome page</DESC>
+<SECTION></SECTION>
+##-->
+
+<!--## PAGE TITLE ELEMENT ##-->
+<inp2:m_DefineElement name="page_title">
+	<inp2:m_phrase name="lu_title_WelcomeTitle" no_editing="1"/>
+</inp2:m_DefineElement>
+<!--## //PAGE TITLE ELEMENT ##-->
+
+<!--## SIDE-BAR ELEMENT ##-->
+<inp2:m_DefineElement name="sidebar">
+	<div class="movable-area">
+		<div class="movable-element">
+			<inp2:m_RenderElement name="platform/elements/side_boxes/login.elm" design="blue_box"/>
+		</div>
+		<div class="movable-element">
+			<inp2:m_RenderElement name="platform/elements/side_boxes/search.elm" design="blue_box"/>
+		</div>
+		<div class="movable-element">
+			<inp2:m_RenderElement name="platform/elements/side_boxes/recommend_site.elm" design="blue_box"/>
+		</div>
+		<div class="movable-element">
+			<inp2:m_RenderElement name="platform/elements/side_boxes/mailing_list.elm" design="blue_box"/>
+		</div>
+	</div>
+</inp2:m_DefineElement>
+<!--## /SIDE-BAR ELEMENT ##-->
+
+<!--## MAIN CONTENT ##-->
+<inp2:m_DefineElement name="content">
+	<div class="movable-area">
+		<div class="movable-element">
+			<inp2:m_include template="platform/elements/navigation_bar.elm"/>
+		</div>
+		<div class="movable-element">
+			<inp2:m_RenderElement design="content_box">
+				<inp2:m_Capture to_var="header">
+					<inp2:m_phrase name="lu_title_WelcomeTitle"/>
+				</inp2:m_Capture>
+
+				<inp2:st_ContentBlock num="1"/>
+			</inp2:m_RenderElement>
+		</div>
+		<div class="movable-element">
+			<!--## INCLUDE HOME PAGE ELEMENTS FOR EACH MODULE ##-->
+			<inp2:m_ModuleInclude template="elements/content_boxes/home_page_items.elm" data_exists="1"/>
+			<!--## /HOME PAGE ELEMENTS ##-->
+		</div>
+	</div>
+</inp2:m_DefineElement>
+<!--## /MAIN CONTENT ##-->
+
+<!--## DESIGN TEMPLATE ##-->
+<inp2:m_include template="platform/designs/default_design.des" pass_params="1"/>
 <!--## /DESIGN TEMPLATE ##-->
\ No newline at end of file
Index: branches/5.0.x/admin/system_presets/simple/settings.php
===================================================================
--- branches/5.0.x/admin/system_presets/simple/settings.php	(revision 12297)
+++ branches/5.0.x/admin/system_presets/simple/settings.php	(revision 12298)
@@ -1,8 +1,7 @@
 <?php
 
 	$visible_editing_modes = Array (
-		1, // Browse Mode
-		4, // Content Mode
-		2, // Layout Mode
-		3, // Design Mode
+		EDITING_MODE_BROWSE,
+		EDITING_MODE_CONTENT,
+		EDITING_MODE_DESIGN,
 	);
\ No newline at end of file
Index: branches/5.0.x/core/kernel/db/db_tag_processor.php
===================================================================
--- branches/5.0.x/core/kernel/db/db_tag_processor.php	(revision 12297)
+++ branches/5.0.x/core/kernel/db/db_tag_processor.php	(revision 12298)
@@ -1,2512 +1,2512 @@
 <?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.net/license/ for copyright notices and details.
 */
 
 class kDBTagProcessor extends TagProcessor {
 
 	/**
 	* Description
 	*
 	* @var kDBConnection
 	* @access public
 	*/
 	var $Conn;
 
 	function kDBTagProcessor()
 	{
 		parent::kBase();
 		$this->Conn =& $this->Application->GetADODBConnection();
 	}
 
 
 	/**
 	 * 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_WARNING);
 			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'] = addslashes( $this->Application->Phrase($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 filters defined</span> for prefix <strong>'.$this->Prefix.'</strong>, but <strong>DrawAutoRefreshMenu</strong> tag used', E_USER_WARNING);
 			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 $intervalmMinutes
 	 * @param string $hour_text Text for hours
 	 * @param string $min_text Text for minutes
 	 * @return unknown
 	 */
 	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 =& $this->Application->RecallObject('ColumnPickerHelper');
 		/* @var $picker_helper kColumnPickerHelper */
 		$picker_helper->ApplyPicker($this->getPrefixSpecial(), $grid_config, $params['grid']);
 
 		if ($mode == 'fields') {
 			return "'".join("','", array_keys($grid_config))."'";
 		}
 
 		$std_params['pass_params'] = 'true';
 		$std_params['PrefixSpecial'] = $this->getPrefixSpecial();
 
 		$object =& $this->GetList($params);
 
 		$o = '';
 		$i = 0;
 		foreach ($grid_config as $field => $options) {
 			$i++;
 			$block_params = Array();
 			$block_params['name'] = $force_block ? $force_block : (isset($options[$mode.'_block']) ? $options[$mode.'_block'] : $def_block);
 			$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) $options['width'] = $w;
 
 			/*if (isset($options['filter_width'])) {
 				$block_params['filter_width'] = $options['filter_width'];
 			}
 			elseif (isset($options['width'])) {
 				if (isset($options['filter_block']) && preg_match('/range/', $options['filter_block'])) {
 					if ($options['width'] < 60) {
 						$options['width'] = 60;
 						$block_params['filter_width'] = 20;
 					}
 					else {
 						$block_params['filter_width'] = $options['width'] - 40;
 					}
 				}
 				else {
 					$block_params['filter_width'] = max($options['width']-10, 20);
 				}
 			}*/
 			/*if (isset($block_params['filter_width'])) $block_params['filter_width'] .= 'px';
 
 
 			if (isset($options['filter_block']) && preg_match('/range/', $options['filter_block'])) {
 					$block_params['filter_width'] = '20px';
 			}
 			else {
 				$block_params['filter_width'] = '97%';
 //				$block_params['filter_width'] = max($options['width']-10, 20);
 			}*/
 
 
 			$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));
 			$block_params = array_merge($std_params, $options, $block_params);
 			$o.= $this->Application->ParseBlock($block_params, 1);
 		}
 		return $o;
 	}
 
 	function PickerCRC($params)
 	{
 		/* @var $picker_helper kColumnPickerHelper */
 		$picker_helper =& $this->Application->RecallObject('ColumnPickerHelper');
 		$picker_helper->SetGridName($params['grid']);
 		$data = $picker_helper->LoadColumns($this->getPrefixSpecial());
 		return $data['crc'];
 	}
 
 	function FreezerPosition($params)
 	{
 		/* @var $picker_helper kColumnPickerHelper */
 		$picker_helper =& $this->Application->RecallObject('ColumnPickerHelper');
 		$picker_helper->SetGridName($params['grid']);
 		$data = $picker_helper->LoadColumns($this->getPrefixSpecial());
 		$freezer_pos = array_search('__FREEZER__', $data['order']);
 		return $freezer_pos === false || in_array('__FREEZER__', $data['hidden_fields']) ? 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'] : '';
 
 		$names_mapping = $this->Application->GetVar('NamesToSpecialMapping');
 
 		if( !getArrayValue($names_mapping, $this->Prefix, $list_name) )
 		{
 			$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 = $this->SelectParam($params, 'types');
 		$except = $this->SelectParam($params, 'except');
 		$list_name = $this->SelectParam($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');
 		if (!$list_name) {
 			$list_name = $this->Application->Parser->GetParam('list_name');
 		}
 
 		$requery = isset($params['requery']) && $params['requery'];
 		if ($list_name && !$requery) {
 			$names_mapping = $this->Application->GetVar('NamesToSpecialMapping');
 
 			$special = is_array($names_mapping) && isset($names_mapping[$this->Prefix]) && isset($names_mapping[$this->Prefix][$list_name]) ? $names_mapping[$this->Prefix][$list_name] : false;
 //			$special = getArrayValue($names_mapping, $this->Prefix, $list_name);
 			if (!$special) {
 				$special = $this->BuildListSpecial($params);
 			}
 		}
 		else {
 			$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($an_event, $prefix_special.':OnListBuild', $params);
 			}
 
 			if (array_key_exists('offset', $params)) {
 				$list->Offset += $params['offset']; // apply custom offset
 			}
 
 			$list->Query($requery);
 
 			if (array_key_exists('offset', $params)) {
 				$list->Offset -= $params['offset']; // remove custom offset
 			}
 		}
 
 		$this->Special = $special;
 
 		if ($list_name) {
 			$names_mapping[$this->Prefix][$list_name] = $special;
 			$this->Application->SetVar('NamesToSpecialMapping', $names_mapping);
 		}
 
 		return $list;
 	}
 
 	function ListMarker($params)
 	{
 		$list =& $this->GetList($params);
 		$ret = $list->getPrefixSpecial();
 		if( getArrayValue($params, 'as_preg') ) $ret = preg_quote($ret, '/');
 		return $ret;
 	}
 
 	/**
 	 * 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->SelectedCount); // 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();
 		$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->SelectedCount - 1);
 			$block_params['last_row'] = ($i + (($i+1) % $columns) >= $list->SelectedCount - 1);
 			$block_params['not_last'] = !$block_params['is_last']; // for front-end
 
 			if ($cache_mod_rw) {
 				if ($this->Prefix == 'c') {
 					// for listing subcategories in category
 					$this->Application->setCache('filenames', $this->Prefix.'_'.$list->GetDBField($id_field), $list->GetDBField('NamedParentPath'));
 					$this->Application->setCache('category_tree', $list->GetDBField($id_field), $list->GetDBField('TreeLeft') . ';' . $list->GetDBField('TreeRight'));
 				} else {
 					// for listing items in category
 					$this->Application->setCache('filenames', 'c_'.$list->GetDBField('CategoryId'), $list->GetDBField('CategoryFilename'));
 					$this->Application->setCache('filenames', $this->Prefix.'_'.$list->GetDBField($id_field), $list->GetDBField('Filename'));
 				}
 			}
 
 			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, 1) :
 						(!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, 1);
 			array_push($displayed, $list->GetDBField($id_field));
 
 			if($direction == 'V' && $list->SelectedCount % $columns > 0 && $column_number == ($columns - 1) && ceil(($i + 1) / $columns) > $list->SelectedCount % ceil($list->SelectedCount / $columns)) {
 				// if vertical output, then draw empty cells vertically, not horizontally
 				$o .= $block_empty_cell_params['name'] ? $this->Application->ParseBlock($block_empty_cell_params, 1) : '<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, 1) :
 						(!isset($params['no_table']) ? '</tr>' : '');
 			}
 
 			$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, 1) : '<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, 1) : '</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;
 	}
 
 	/**
 	 * Allows to modify block params & current list record before PrintList parses record
 	 *
 	 * @param kDBList $object
 	 * @param Array $block_params
 	 */
 	function PrepareListElementParams(&$object, &$block_params)
 	{
 //		$fields_hash =& $object->getCurrentRecord();
 
 	}
 
 	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->PerPage < $list->RecordsCount) {
 			$block_params = $this->prepareTagParams($params);
 			$block_params['name'] = $this->SelectParam($params, 'render_as,block');
 
 			return $this->Application->ParseBlock($block_params);
 		}
 	}
 
 	function NotLastItem($params)
 	{
 		$object =& $this->getList($params); // maybe we should use $this->GetList($params) instead
 		return ($object->CurrentIndex < min($object->PerPage == -1 ? $object->RecordsCount : $object->PerPage, $object->RecordsCount) - 1);
 	}
 
 	function PageLink($params)
 	{
 		$t = isset($params['template']) ? $params['template'] : '';
 		unset($params['template']);
 
 		if (!$t) $t = $this->Application->GetVar('t');
 
 		if (isset($params['page'])) {
 			$this->Application->SetVar($this->getPrefixSpecial().'_Page', $params['page']);
 			unset($params['page']);
 		}
 
 		if (!isset($params['pass'])) {
 			$params['pass'] = 'm,'.$this->getPrefixSpecial();
 		}
 
 		return $this->Application->HREF($t, '', $params);
 	}
 
 	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())
 	{
 		/*if (isset($tag_params['list_name'])) {
 			$list =& $this->GetList($tag_params);
 			$this->Init($list->Prefix, $list->Special);
 		}*/
 
 		$ret = $tag_params;
 		$ret['Prefix'] = $this->Prefix;
 		$ret['Special'] = $this->Special;
 		$ret['PrefixSpecial'] = $this->getPrefixSpecial();
 		return $ret;
 	}
 
 	function GetISO($currency)
 	{
 		if ($currency == 'selected') {
 			$iso = $this->Application->RecallVar('curr_iso');
 		}
 		elseif ($currency == 'primary' || $currency == '') {
 			$iso = $this->Application->GetPrimaryCurrency();
 		}
 		else { //explicit currency
 			$iso = $currency;
 		}
 		return $iso;
 	}
 
 	function ConvertCurrency($value, $iso)
 	{
 		$converter =& $this->Application->recallObject('kCurrencyRates');
 		// convery primary currency to selected (if they are the same, converter will just return)
 		$value = $converter->Convert($value, 'PRIMARY', $iso);
 		return $value;
 	}
 
 	function AddCurrencySymbol($value, $iso)
 	{
 		$currency =& $this->Application->recallObject('curr.-'.$iso, null, Array('skip_autoload' => true));
 		if( !$currency->isLoaded() ) $currency->Load($iso, 'ISO');
 
 		$symbol = $currency->GetDBField('Symbol');
 		if (!$symbol) $symbol = $currency->GetDBField('ISO').'&nbsp;';
 		if ($currency->GetDBField('SymbolPosition') == 0) {
 			$value = $symbol.$value;
 		}
 		if ($currency->GetDBField('SymbolPosition') == 1) {
 			$value = $value.$symbol;
 		}
 		return $value;
 	}
 
 	/**
 	 * 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() ) $params['no_special'] = 'no_special';
 
 		$object =& $this->getObject($params);
 
 		if ( $this->HasParam($params, 'db')  )
 		{
 			$value = $object->GetDBField($field);
 		}
 		else
 		{
 			if( $this->HasParam($params, 'currency') )
 			{
 				$iso = $this->GetISO($params['currency']);
 				$original = $object->GetDBField($field);
 				$value = $this->ConvertCurrency($original, $iso);
 				$object->SetDBField($field, $value);
 				$object->Fields[$field]['converted'] = true;
 			}
 
 			$format = getArrayValue($params, 'format');
 			if (!$format || $format == '$format') {
 				$format = null;
 			}
 
 			$value = $object->GetField($field, $format);
 
 			if( $this->SelectParam($params, 'negative') )
 			{
 				if(strpos($value, '-') === 0)
 				{
 					$value = substr($value, 1);
 				}
 				else
 				{
 					$value = '-'.$value;
 				}
 			}
 
 			if( $this->HasParam($params, 'currency') )
 			{
 				$value = $this->AddCurrencySymbol($value, $iso);
 				$params['no_special'] = 1;
 			}
 		}
 
 		if( !$this->HasParam($params, 'no_special') ) $value = htmlspecialchars($value);
 		if( getArrayValue($params,'checked'	) ) $value = ($value == ( isset($params['value']) ? $params['value'] : 1)) ? 'checked' : '';
 		if( isset($params['plus_or_as_label']) ) {
 			$value = substr($value, 0,1) == '+' ? substr($value, 1) : $this->Application->Phrase($value);
 		}
 		elseif( isset($params['as_label']) && $params['as_label']  ) $value = $this->Application->Phrase($value);
 
 		$first_chars = $this->SelectParam($params,'first_chars,cut_first');
 		if($first_chars)
 		{
 			$needs_cut = mb_strlen($value) > $first_chars;
 			$value = mb_substr($value, 0, $first_chars);
 			if ($needs_cut) $value .= ' ...';
 		}
 		if( getArrayValue($params,'nl2br'	) ) $value = nl2br($value);
 
 		if ($value != '') $this->Application->Parser->DataExists = true;
 
 		if( $this->HasParam($params, 'currency') )
 		{
 			//restoring value in original currency, for other Field tags to work properly
 			$object->SetDBField($field, $original);
 		}
 
 		return $value;
 	}
 
 	function SetField($params)
 	{
 		// <inp2:SetField field="Value" src=p:cust_{$custom_name}"/>
 
 		$object =& $this->getObject($params);
 		$dst_field = $this->SelectParam($params, 'name,field');
 
 		list($prefix_special, $src_field) = explode(':', $params['src']);
 		$src_object =& $this->Application->recallObject($prefix_special);
 		$object->SetDBField($dst_field, $src_object->GetDBField($src_field));
 	}
 
 	/**
 	 * Checks if parameter is passed
 	 * Note: works like Tag and line simple method too
 	 *
 	 * @param Array $params
 	 * @param string $param_name
 	 * @return bool
 	 */
 	function HasParam($params, $param_name = null)
 	{
 		if( !isset($param_name) )
 		{
 			$param_name = $this->SelectParam($params, 'name');
 			$params = $this->Application->Parser->Params;
 		}
 		$value = isset($params[$param_name]) ? $params[$param_name] : false;
 		return $value && ($value != '$'.$param_name);
 	}
 
 	function PhraseField($params)
 	{
 		$field_label = $this->Field($params);
 		$translation = $this->Application->Phrase( $field_label );
 		return $translation;
 	}
 
 	function Error($params)
 	{
 		$field = $this->SelectParam($params, 'name,field');
 		$object =& $this->getObject($params);
 		$msg = $object->GetErrorMsg($field, false);
 		return $msg;
 	}
 
 	function HasError($params)
 	{
 		if ($params['field'] == 'any')
 		{
 			$object =& $this->getObject($params);
 
 			$skip_fields = getArrayValue($params, 'except');
 			$skip_fields = $skip_fields ? explode(',', $skip_fields) : Array();
 
 			return $object->HasErrors($skip_fields);
 		}
 		else
 		{
 			$fields = $this->SelectParam($params, 'field,fields');
 			$fields = explode(',', $fields);
 			$res = false;
 			foreach($fields as $field)
 			{
 				$params['field'] = $field;
 				$res = $res || ($this->Error($params) != '');
 			}
 			return $res;
 		}
 	}
 
 	function ErrorWarning($params)
 	{
 		if (!isset($params['field'])) {
 			$params['field'] = 'any';
 		}
 		if ($this->HasError($params)) {
 			$params['prefix'] = $this->getPrefixSpecial();
 			return $this->Application->ParseBlock($params);
 		}
 	}
 
 	function IsRequired($params)
 	{
 		$field = $params['field'];
 		$object =& $this->getObject($params);;
 
 		$formatter_class = getArrayValue($object->Fields, $field, 'formatter');
 		if ($formatter_class == 'kMultiLanguage')
 		{
 			$formatter =& $this->Application->recallObject($formatter_class);
 			$field = $formatter->LangFieldName($field);
 		}
 
 		$options = $object->GetFieldOptions($field);
 		return getArrayValue($options,'required');
 	}
 
 	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;
 	}
 
 	function PredefinedOptions($params)
 	{
 		$object =& $this->getObject($params);
 
 		$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 ($this->HasParam($params, 'has_empty')) {
 			$empty_value = array_key_exists('empty_value', $params) ? $params['empty_value'] : '';
 			$options = array_merge_recursive2(Array ($empty_value => ''), $options); // don't use other array merge function, because they will reset keys !!!
 		}
 
 		$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 = getArrayValue($params, 'selected_param');
 		if (!$selected_param_name) {
 			$selected_param_name = $params['selected'];
 		}
 		$selected = $params['selected'];
 
 		$o = '';
 		if ($this->HasParam($params, 'no_empty') && !getArrayValue($options, '')) {
 			// removes empty option, when present (needed?)
 			array_shift($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 : '');
 				$o .= $this->Application->ParseBlock($block_params, 1);
 			}
 		}
 		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 : '');
 				$o .= $this->Application->ParseBlock($block_params, 1);
 			}
 		}
 		return $o;
 	}
 
 	function PredefinedSearchOptions($params)
 	{
 		$object =& $this->GetList($params);
 		/* @var $object kDBList */
 
 		$params['value'] = $this->SearchField($params);
 
 		return $this->PredefinedOptions($params);
 	}
 
 	function Format($params)
 	{
 		$field = $this->SelectParam($params, 'name,field');
 		$object =& $this->getObject($params);
 
 		$options = $object->GetFieldOptions($field);
 
 		$format = $options[ $this->SelectParam($params, 'input_format') ? 'input_format' : 'format' ];
 
 		$formatter_class = getArrayValue($options,'formatter');
 		if ($formatter_class) {
 			$formatter =& $this->Application->recallObject($formatter_class);
 			$human_format = getArrayValue($params,'human');
 			$edit_size = getArrayValue($params,'edit_size');
 			$sample = getArrayValue($params,'sample');
 			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->Page;
 				break;
 
 			case 'total':
 				$ret = $object->GetTotalPages();
 				break;
 
 			case 'prev':
 				$ret = $object->Page > 1 ? $object->Page - 1 : false;
 				break;
 
 			case 'next':
 				$ret = $object->Page < $object->GetTotalPages() ? $object->Page + 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->Page; // 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) $total_pages = 1; // display 1st page as selected in case if we have no pages at all
 		$o = '';
 
 		// what are these 2 lines for?
 		$this->Application->SetVar($prefix_special.'_event','');
 		$this->Application->SetVar($prefix_special.'_id','');
 
 		$current_page = $list->Page; //  $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();
 
 			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']){
 					$o .= $this->Application->ParseBlock($prev_block_params, 1);
 				}
 			}
 
 			$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', $current_page-1);
 				$o .= $this->Application->ParseBlock($prev_block_params, 1);
 			}
 		}
 		else {
 			if ( $no_prev_page_block = $this->SelectParam($params, 'no_prev_page_render_as,block_no_prev_page') ) {
 				$block_params['name'] = $no_prev_page_block;
 				$o .= $this->Application->ParseBlock($block_params, 1);
 			}
 		}
 
 		$separator_params['name'] = $this->SelectParam($params, 'separator_render_as,block_separator');
 		for ($i = $split_start; $i <= $split_end; $i++)
 		{
 			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', $i);
 			$o .= $this->Application->ParseBlock($block_params, 1);
 
 			if ($this->SelectParam($params, 'separator_render_as,block_separator')
 				&& $i < $split_end)
 			{
 				$o .= $this->Application->ParseBlock($separator_params, 1);
 			}
 		}
 
 		if ($current_page < $total_pages){
 			$next_block_params = $this->prepareTagParams();
 			$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', $current_page+1);
 				$o .= $this->Application->ParseBlock($next_block_params, 1);
 			}
 			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']){
 					$o .= $this->Application->ParseBlock($next_block_params, 1);
 				}
 			}
 		}
 		else {
 			if ( $no_next_page_block = $this->SelectParam($params, 'no_next_page_render_as,block_no_next_page') ) {
 				$block_params['name'] = $no_next_page_block;
 				$o .= $this->Application->ParseBlock($block_params, 1);
 			}
 		}
 
 		$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);
 	}
 
 
 	/**
 	 * 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)
 	{
 		$field = $this->SelectParam($params, 'name,field');
 		$object =& $this->getObject($params);
 
 		$formatter_class = getArrayValue($object->Fields, $field, 'formatter');
 		if ($formatter_class == 'kMultiLanguage') {
 			$formatter =& $this->Application->recallObject($formatter_class);
 			/* @var $formatter kMultiLanguage */
 
 			$force_primary = isset($object->Fields[$field]['force_primary']) && $object->Fields[$field]['force_primary'];
 			$field = $formatter->LangFieldName($field, $force_primary);
 		}
 
 		if (array_key_exists('force_id', $params)) {
 			$id = $params['force_id'];
 		}
 		else {
 			$id_field = getArrayValue($params, 'IdField');
 			$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( getArrayValue($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( getArrayValue($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');
 		$sorting_prefix = getArrayValue($list_sortings, $this->Special) ? $this->Special : '';
 
 		$user_sorting_start = 0;
 		if ( $forced_sorting = getArrayValue($list_sortings, $sorting_prefix, 'ForcedSorting') ) {
 			$user_sorting_start = count($forced_sorting);
 		}
 		return $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);
 		$user_sorting_start = $this->getUserSortIndex();
 
 		$sorting_configs = $this->Application->getUnitOption($this->Prefix, 'ConfigMapping', Array ());
 		$list_sortings = $this->Application->getUnitOption($this->Prefix, 'ListSortings', Array ());
 		$sorting_prefix = getArrayValue($list_sortings, $this->Special) ? $this->Special : '';
 
 		if (array_key_exists('DefaultSorting1Field', $sorting_configs)) {
 			$list_sortings[$sorting_prefix]['Sorting'] = Array (
 				$this->Application->ConfigValue($sorting_configs['DefaultSorting1Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting1Dir']),
 				$this->Application->ConfigValue($sorting_configs['DefaultSorting2Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting2Dir']),
 			);
 		}
 
 		$sorting = getArrayValue($list_sortings, $sorting_prefix, 'Sorting');
 		$sort_fields = is_array($sorting) ? array_keys($sorting) : Array ();
 
 		for ($order_number = 0; $order_number < 2; $order_number++) {
 			// currect sorting in list
 			$sorting_pos = $user_sorting_start + $order_number;
 			$current_order_field = $list->GetOrderField($sorting_pos, true);
 			$current_order_direction = $list->GetOrderDirection($sorting_pos, true);
 
 			if (!$current_order_field || !$current_order_direction) {
 				// no sorting defined for this sorting position
 				continue;
 			}
 
 			// user sorting found
 			if (array_key_exists($order_number, $sort_fields)) {
 				// default sorting found
 				$default_order_field = $sort_fields[$order_number];
 				$default_order_direction = $sorting[$default_order_field];
 
 				if ($current_order_field != $default_order_field || $current_order_direction != $default_order_direction) {
 					// #1. user sorting differs from default sorting -> changed
 					return true;
 				}
 			}
 			else {
 				// #2. user sorting + no default sorting -> changed
 				return true;
 			}
 		}
 
 		// #3. user sorting match default or not defined -> not changed
 		return false;
 	}
 
 	/**
 	 * Get's information of sorting field at "pos" position,
 	 * like sorting field name (type="field") or sorting direction (type="direction")
 	 *
 	 * @param Array $params
 	 * @return mixed
 	 */
 	function OrderInfo($params)
 	{
 		$user_sorting_start = $this->getUserSortIndex() + --$params['pos'];
 		$list =& $this->GetList($params);
 //		$object =& $this->Application->recallObject( $this->getPrefixSpecial() );
 
 		if($params['type'] == 'field') return $list->GetOrderField($user_sorting_start);
 		if($params['type'] == 'direction') return $list->GetOrderDirection($user_sorting_start);
 	}
 
 	/**
 	 * Checks if sorting field/direction matches passed field/direction parameter
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function IsOrder($params)
 	{
 		$params['type'] = isset($params['field']) ? 'field' : 'direction';
 		$value = $this->OrderInfo($params);
 
 		if( isset($params['field']) ) return $params['field'] == $value;
 		if( isset($params['direction']) ) return $params['direction'] == $value;
 	}
 
 	/**
 	 * Returns list perpage
 	 *
 	 * @param Array $params
 	 * @return int
 	 */
 	function PerPage($params)
 	{
 		$object =& $this->getObject($params);
 		return $object->PerPage;
 	}
 
 	/**
 	 * Checks if list perpage matches value specified
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function PerPageEquals($params)
 	{
 		$object =& $this->getObject($params);
 		return $object->PerPage == $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
 	 */
 	function FieldEquals($params)
 	{
 		$object =& $this->getObject($params);
 		$ret = $object->GetDBField($this->SelectParam($params, 'name,field')) == $params['value'];
 //		if( getArrayValue($params,'inverse') ) $ret = !$ret;
 		return $ret;
 	}
 
 	/**
 	 * 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)
 	{
 		$object =& $this->getObject($params);
 
 		$grids = $this->Application->getUnitOption($this->Prefix,'Grids');
 		$icons =& $grids[ $params['grid'] ]['Icons'];
 
 		$key = '';
 		$status_fields = $this->Application->getUnitOption($this->Prefix,'StatusField');
 		if(!$status_fields) return $icons['default'];
 
 		foreach($status_fields as $status_field)
 		{
 			$key .= $object->GetDBField($status_field).'_';
 		}
 		$key = rtrim($key,'_');
 		$value = ($key !== false) ? $key : 'default';
 
 		return isset($icons[$value]) ? $icons[$value] : $icons['default'];
 	}
 
 	/**
 	 * Generates bluebar title + initializes prefixes used on page
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function SectionTitle($params)
 	{
 		$preset_name = replaceModuleSection($params['title_preset']);
 		$title_presets = $this->Application->getUnitOption($this->Prefix,'TitlePresets');
 		$title_info = getArrayValue($title_presets, $preset_name);
 		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 (getArrayValue($title_presets,'default')) {
 			// use default labels + custom labels specified in preset used
 			$title_info = array_merge_recursive2($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 = getArrayValue($title_info,'prefixes');
 		$all_tag_params = getArrayValue($title_info,'tag_params');
 		if ($prefixes) {
 			// extract tag_perams 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_recursive2($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'];
 		}
 
 		$cut_first = getArrayValue($params, 'cut_first');
 		if ($cut_first && mb_strlen($title) > $cut_first) {
 			if (!preg_match('/<a href="(.*)">(.*)<\/a>/',$title)) {
 				$title = mb_substr($title, 0, $cut_first).' ...';
 			}
 		}
 
 		return $title;
 	}
 
 	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':
 				$of_phrase = $this->Application->Phrase('la_of');
 				return $object->NoFilterCount != $object->RecordsCount ? $object->RecordsCount.' '.$of_phrase.' '.$object->NoFilterCount : $object->RecordsCount;
 				break;
 
 			default:
 				return $object->GetField($info_type);
 				break;
 		}
 	}
 
 	function GridInfo($params)
 	{
 		$object =& $this->GetList($params);
 		/* @var $object kDBList */
 
 		switch ($params['type']) {
 			case 'filtered':
 				return $object->GetRecordsCount();
 			case 'total':
 				return $object->GetNoFilterCount();
 			case 'from':
 				return $object->RecordsCount ? $object->Offset+1 : 0; //0-based
 			case 'to':
 				return $object->PerPage > 0 ? min($object->Offset + $object->PerPage, $object->RecordsCount) : $object->RecordsCount;
 			case 'total_pages':
 				return $object->GetTotalPages();
 			case 'needs_pagination':
 				return ($object->PerPage != -1) && (($object->RecordsCount > $object->PerPage) || ($object->Page > 1));
 		}
 	}
 
 	/**
 	 * 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);
 		$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';
 		$params['name'] = $params['blocks_prefix'].$element_type;
 
 		switch ($element_type) {
 			case 'select':
 			case 'multiselect':
 			case 'radio':
 				$field_options = $object->GetFieldOptions($field, 'options');
 
 				if ($object->GetDBField('DirectOptions')) {
 					// used for custom fields
 					$field_options['options'] = $object->GetDBField('DirectOptions');
 				}
 				else {
 					// used for configuration
 					$field_options['options'] = $helper->GetValuesHash($object->GetDBField($params['value_list_field']), ',');
 				}
 
 				$object->SetFieldOptions($field, $field_options);
 				break;
 
 			case 'text':
 			case 'textarea':
 				$params['field_params'] = $helper->ParseConfigSQL($object->GetDBField($params['value_list_field']));
 				break;
 
 			case 'password':
 			case 'checkbox':
 			default:
 				break;
 		}
 		return $this->Application->ParseBlock($params, 1);
 	}
 
 	/**
 	 * 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 modfied & is in TempTables mode, then parse block with name passed;
 	 * remove modification mark if not in TempTables mode
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 * @author Alexey
 	 */
 	function SaveWarning($params)
 	{
 		$main_prefix = getArrayValue($params, 'main_prefix');
 		if ($main_prefix && $main_prefix != '$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);
 		if (!$list->Counted) $list->CountRecs();
 		return $list->RecordsCount;
 	}
 
 	/**
 	 * 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'].']';
 		}
 
 		return $ret;
 	}
 
 	/**
 	 * Return range filter field value
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	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( !$this->HasParam($params, 'no_special') ) $ret = htmlspecialchars($ret);
 			return $ret;
 		}
 
 		return '';
 	}
 
 	function SearchFormat($params)
 	{
 		$field = $params['field'];
 		$object =& $this->GetList($params);
 
 		$options = $object->GetFieldOptions($field);
 
 		$format = $options[ $this->SelectParam($params, 'input_format') ? 'input_format' : 'format' ];
 
 		$formatter_class = getArrayValue($options,'formatter');
 		if($formatter_class)
 		{
 			$formatter =& $this->Application->recallObject($formatter_class);
 			$human_format = getArrayValue($params,'human');
 			$edit_size = getArrayValue($params,'edit_size');
 			$sample = getArrayValue($params,'sample');
 			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 error of range field
 	 *
 	 * @param unknown_type $params
 	 * @return unknown
 	 */
 	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
 	 *
 	 * @access public
 	 * @return kDBBase
 	 */
 	function &getObject($params = Array())
 	{
 		$object =& $this->Application->recallObject($this->getPrefixSpecial(), $this->Prefix, $params);
 		if (isset($params['requery']) && $params['requery']) {
 			$this->Application->HandleEvent($q_event, $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'];
 	}
 
 	/**
 	 * Group list records by header, saves internal order in group
 	 *
 	 * @param Array $records
 	 * @param string $heading_field
 	 */
 	function groupRecords(&$records, $heading_field)
 	{
 		$sorted = Array();
 		$i = 0; $record_count = count($records);
 		while ($i < $record_count) {
 			$sorted[ $records[$i][$heading_field] ][] = $records[$i];
 			$i++;
 		}
 
 		$records = Array();
 		foreach ($sorted as $heading => $heading_records) {
 			$records = array_merge_recursive($records, $heading_records);
 		}
 	}
 
 	function DisplayOriginal($params)
 	{
 		return false;
 	}
 
-	function MultipleEditing($params)
+	/*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( array_merge_recursive2($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');
 
 		$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, 'no_amp' => 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
 	 */
 	function ExportPath($params)
 	{
 		$ret = EXPORT_PATH.'/';
 
 		if( getArrayValue($params, 'as_url') )
 		{
 			$ret = str_replace( FULL_PATH.'/', $this->Application->BaseURL(), $ret);
 		}
 
 		$export_options = unserialize($this->Application->RecallVar($this->getPrefixSpecial().'_options'));
 		$ret .= $export_options['ExportFilename'].'.'.($export_options['ExportFormat'] == 1 ? 'csv' : 'xml');
 
 		return $ret;
 	}
 
 	function FieldTotal($params)
 	{
 		$list =& $this->GetList($params);
 
 		return $list->GetFormattedTotal($this->SelectParam($params, 'field,name'), $params['function']);
 	}
 
 	/**
 	 * Returns FCKEditor locale, that matches default site language
 	 *
 	 * @return string
 	 */
 	function _getFCKLanguage()
 	{
 		static $language_code = null;
 
 		if (!isset($language_code)) {
 			$language_code = 'en'; // defaut value
 
 			$sql = 'SELECT Locale
 					FROM '. $this->Application->getUnitOption('lang', 'TableName') . '
 					WHERE LanguageId = ' . $this->Application->GetDefaultLanguageId(); // $this->Application->GetVar('m_lang');
 			$locale = strtolower( $this->Conn->GetOne($sql) );
 
 			if (file_exists(FULL_PATH . EDITOR_PATH . 'editor/lang/' . $locale . '.js')) {
 				// found language file, that exactly matches locale name (e.g. "en")
 				$language_code = $locale;
 			}
 			else {
 				$locale = explode('-', $locale);
 				if (file_exists(FULL_PATH . EDITOR_PATH . 'editor/lang/' . $locale[0] . '.js')) {
 					// language file matches first part of locale (e.g. "ru-RU")
 					$language_code = $locale[0];
 				}
 			}
 		}
 
 		return $language_code;
 	}
 
 
 	function FCKEditor($params)
 	{
 		$params['no_special'] = 1;
 		$params['format'] = array_key_exists('format', $params) ? $params['format'] . ';fck_ready' : 'fck_ready';
 		$value = $this->Field($params);
 		$name = array_key_exists('name', $params) ? $params['name'] : $this->InputName($params);
 
 		$theme_path = substr($this->Application->GetFrontThemePath(), 1) . '/inc/';
 		if (!file_exists(FULL_PATH . '/' . $theme_path . 'style.css')) {
 			$theme_path = EDITOR_PATH;
 		}
 
 		$styles_xml = $this->Application->BaseURL() . $theme_path . 'styles.xml';
 		$styles_css = $this->Application->BaseURL() . $theme_path . 'style.css';
 
 		$bgcolor = array_key_exists('bgcolor', $params) ? $params['bgcolor'] : $this->Application->GetVar('bgcolor');
 		if (!$bgcolor) {
 			$bgcolor = '#ffffff';
 		}
 
 		$preview_url = '';
 		$page_id = $this->Application->GetVar('c_id');
 		$content_id = $this->Application->GetVar('content_id');
 		if ($page_id && $content_id) {
 			// editing content block from Front-End, not category in admin
 			$sql = 'SELECT NamedParentPath
 					FROM ' . $this->Application->getUnitOption('c', 'TableName') . '
 					WHERE ' . $this->Application->getUnitOption('c', 'IDField') . ' = ' . $page_id;
 			$template = strtolower( $this->Conn->GetOne($sql) );
 
-			$url_params = Array ('m_cat_id' => $page_id, 'no_amp' => 1, 'editing_mode' => EDITING_MODE_CMS, 'pass' => 'm');
+			$url_params = Array ('m_cat_id' => $page_id, 'no_amp' => 1, 'editing_mode' => EDITING_MODE_CONTENT, 'pass' => 'm');
 			$preview_url = $this->Application->HREF($template, '_FRONT_END_', $url_params, 'index.php');
 			$preview_url = preg_replace('/&(admin|editing_mode)=[\d]/', '', $preview_url);
 		}
 
 		include_once(FULL_PATH . EDITOR_PATH . 'fckeditor.php');
 
 		$oFCKeditor = new FCKeditor($name);
 		$oFCKeditor->FullUrl    = $this->Application->BaseURL();
 		$oFCKeditor->BaseUrl    = BASE_PATH . '/';
 		$oFCKeditor->BasePath	= BASE_PATH . EDITOR_PATH;
 		$oFCKeditor->Width		= $params['width'] ;
 		$oFCKeditor->Height		= $params['height'] ;
 		$oFCKeditor->ToolbarSet	= $page_id && $content_id ? 'Advanced' : 'Default';
 		$oFCKeditor->Value		= $value;
 		$oFCKeditor->PreviewUrl	= $preview_url;
 		$oFCKeditor->DefaultLanguage = $this->_getFCKLanguage();
 		$oFCKeditor->LateLoad = array_key_exists('late_load', $params) && $params['late_load'];
 		$oFCKeditor->Config = Array (
 			//'UserFilesPath' => $pathtoroot.'kernel/user_files',
 			'ProjectPath' => BASE_PATH . '/',
 			'CustomConfigurationsPath' => $this->Application->BaseURL() . 'core/admin_templates/js/inp_fckconfig.js',
 			'StylesXmlPath' => $styles_xml,
 			'EditorAreaCSS' => $styles_css,
 			'DefaultStyleLabel' => $this->Application->Phrase('la_editor_default_style'),
 //				'Debug' => 1,
 			'Admin' => 1,
 			'K4' => 1,
 			'newBgColor' => $bgcolor,
 			'PreviewUrl' => $preview_url,
 			'BaseUrl' => BASE_PATH . '/',
 			'DefaultLanguage' => $this->_getFCKLanguage(),
 			'EditorAreaStyles' => 'body { background-color: '.$bgcolor.' }',
 		);
 
 		return $oFCKeditor->CreateHtml();
 	}
 
 	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
 	 */
 	function ItemLink($params)
 	{
 		$object =& $this->getObject($params);
 
 		if (!isset($params['pass'])) {
 			$params['pass'] = 'm';
 		}
 
 		$params[$object->getPrefixSpecial().'_id'] = $object->GetID();
 
 		$m =& $this->Application->recallObject('m_TagProcessor');
 		return $m->t($params);
 	}
 
 	/**
 	 * 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();
 		$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->PerPage == $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
 	 */
 	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 = 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_WARNING);
 			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_map('addslashes', $preset_info['toolbar_buttons']);
 
 		return $toolbar_buttons ? "'" . implode("', '", $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');
 		}
 
 		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;
 	}
 }
 
 ?>
\ No newline at end of file
Index: branches/5.0.x/core/kernel/db/dbitem.php
===================================================================
--- branches/5.0.x/core/kernel/db/dbitem.php	(revision 12297)
+++ branches/5.0.x/core/kernel/db/dbitem.php	(revision 12298)
@@ -1,1297 +1,1301 @@
 <?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.net/license/ for copyright notices and details.
 */
 
 /**
 * DBItem
 *
 * Desciption
 * @package kernel4
 */
 class kDBItem extends kDBBase {
 
 	/**
 	* Description
 	*
 	* @var array Associative array of current item' field values
 	* @access public
 	*/
 	var $FieldValues;
 
 	/**
 	 * Unformatted field values, before parse
 	 *
 	 * @var Array
 	 * @access private
 	 */
 	var $DirtyFieldValues = Array();
 
 	/**
 	 * Holds item values after loading (not affected by submit)
 	 *
 	 * @var Array
 	 * @access private
 	 */
 	var $OriginalFieldValues = Array ();
 
 	var $FieldErrors;
 
 	var $ErrorMsgs = Array();
 
 	/**
 	* If set to true, Update will skip Validation before running
 	*
 	* @var array Associative array of current item' field values
 	* @access public
 	*/
 	var $IgnoreValidation = false;
 
 	var $Loaded = false;
 
 	/**
 	* Holds item' primary key value
 	*
 	* @var int Value of primary key field for current item
 	* @access public
 	*/
 	var $ID;
 
 	function kDBItem()
 	{
 		parent::kDBBase();
 		$this->ErrorMsgs['required'] = '!la_err_required!'; //'Field is required';
 		$this->ErrorMsgs['unique'] = '!la_err_unique!'; //'Field value must be unique';
 		$this->ErrorMsgs['value_out_of_range'] = '!la_err_value_out_of_range!'; //'Field is out of range, possible values from %s to %s';
 		$this->ErrorMsgs['length_out_of_range'] = '!la_err_length_out_of_range!'; //'Field is out of range';
 		$this->ErrorMsgs['bad_type'] = '!la_err_bad_type!'; //'Incorrect data format, please use %s';
 		$this->ErrorMsgs['invalid_format'] = '!la_err_invalid_format!'; //'Incorrect data format, please use %s';
 		$this->ErrorMsgs['bad_date_format'] = '!la_err_bad_date_format!'; //'Incorrect date format, please use (%s) ex. (%s)';
 		$this->ErrorMsgs['primary_lang_required'] = '!la_err_primary_lang_required!';
 	}
 
 	function SetDirtyField($field_name, $field_value)
 	{
 		$this->DirtyFieldValues[$field_name] = $field_value;
 	}
 
 	function GetDirtyField($field_name)
 	{
 		return $this->DirtyFieldValues[$field_name];
 	}
 
 	function GetOriginalField($field_name, $formatted = false, $format=null)
 	{
 		if (array_key_exists($field_name, $this->OriginalFieldValues)) {
 			// item was loaded before
 			$value = $this->OriginalFieldValues[$field_name];
 		}
 		else {
 			// no original fields -> use default field value
 			$value = $this->Fields[$field_name]['default'];
 		}
 
 		if (!$formatted) {
 			return $value;
 		}
 
 		$options = $this->GetFieldOptions($field_name);
 		$res = $value;
 		if (array_key_exists('formatter', $options)) {
 			$formatter =& $this->Application->recallObject($options['formatter']);
 			/* @var $formatter kFormatter */
 
 			$res = $formatter->Format($value, $field_name, $this, $format);
 		}
 		return $res;
 	}
 
 	/**
 	 * Sets original field value (useful for custom virtual fields)
 	 *
 	 * @param string $field_name
 	 */
 	function SetOriginalField($field_name, $field_value)
 	{
 		$this->OriginalFieldValues[$field_name] = $field_value;
 	}
 
 	/**
 	 * Set's default values for all fields
 	 *
 	 * @param bool $populate_ml_fields create all ml fields from db in config or not
 	 *
 	 * @access public
 	 */
 	function SetDefaultValues($populate_ml_fields = false)
 	{
 		parent::SetDefaultValues($populate_ml_fields);
 		if ($populate_ml_fields) {
 			$this->PopulateMultiLangFields();
 		}
 
 		foreach ($this->Fields as $field => $params) {
 			if ( isset($params['default']) ) {
 				$this->SetDBField($field, $params['default']);
 			}
 			else {
 				$this->SetDBField($field, NULL);
 			}
 		}
 	}
 
 	/**
 	* Sets current item field value
 	* (applies formatting)
 	*
 	* @access public
 	* @param string $name Name of the field
 	* @param mixed $value Value to set the field to
 	* @return void
 	*/
 	function SetField($name,$value)
 	{
 		$options = $this->GetFieldOptions($name);
 		$parsed = $value;
 		if ($value == '') {
 			$parsed = NULL;
 		}
 
 		// kFormatter is always used, to make sure, that numeric value is converted to normal representation
 		// according to regional format, even when formatter is not set (try seting format to 1.234,56 to understand why)
 		$formatter =& $this->Application->recallObject(isset($options['formatter']) ? $options['formatter'] : 'kFormatter');
 		$parsed = $formatter->Parse($value, $name, $this);
 
 		$this->SetDBField($name,$parsed);
 	}
 
 	/**
 	* Sets current item field value
 	* (doesn't apply formatting)
 	*
 	* @access public
 	* @param string $name Name of the field
 	* @param mixed $value Value to set the field to
 	* @return void
 	*/
 	function SetDBField($name,$value)
 	{
 		$this->FieldValues[$name] = $value;
 		/*if (isset($this->Fields[$name]['formatter'])) {
 			$formatter =& $this->Application->recallObject($this->Fields[$name]['formatter']);
 			$formatter->UpdateSubFields($name, $value, $this->Fields[$name], $this);
 		}*/
 	}
 
 	/**
 	 * Set's field error, if pseudo passed not found then create it with message text supplied.
 	 * Don't owerrite existing pseudo translation.
 	 *
 	 * @param string $field
 	 * @param string $pseudo
 	 * @param string $error_label
 	 *
 	 * @return bool
 	 */
 	function SetError($field, $pseudo, $error_label = null, $error_params = null)
 	{
 		$error_field = isset($this->Fields[$field]['error_field']) ? $this->Fields[$field]['error_field'] : $field;
 		if (isset($this->FieldErrors[$error_field]['pseudo'])) {
 			// don't set more then one error on field
 			return false;
 		}
 
 		$this->FieldErrors[$error_field]['pseudo'] = $pseudo;
 
 		if (isset($error_params)) {
 			// additional params, that helps to determine error sources
 			$this->FieldErrors[$error_field]['params'] = $error_params;
 		}
 
 		if (isset($error_label) && !isset($this->ErrorMsgs[$pseudo])) {
 			// label for error (only when not already set)
 			$this->ErrorMsgs[$pseudo] = (substr($error_label, 0, 1) == '+') ? substr($error_label, 1) : '!'.$error_label.'!';
 		}
 
 		return true;
 	}
 
 	/**
 	* Return current item' field value by field name
 	* (doesn't apply formatter)
 	*
 	* @access public
 	* @param string $name field name to return
 	* @return mixed
 	*/
 	function GetDBField($name)
 	{
+		/*if (!array_key_exists($name, $this->FieldValues) && defined('DEBUG_MODE') && DEBUG_MODE) {
+			$this->Application->Debugger->appendTrace();
+		}*/
+
 		return $this->FieldValues[$name];
 	}
 
 	function HasField($name)
 	{
 		return isset($this->FieldValues[$name]);
 	}
 
 	function GetFieldValues()
 	{
 		return $this->FieldValues;
 	}
 
 	/**
 	* Sets item' fields corresponding to elements in passed $hash values.
 	*
 	* The function sets current item fields to values passed in $hash, by matching $hash keys with field names
 	* of current item. If current item' fields are unknown {@link kDBItem::PrepareFields()} is called before acutally setting the fields
 	*
 	* @access public
 	* @param Array $hash
 	* @param Array $set_fields Optional param, field names in target object to set, other fields will be skipped
 	* @return void
 	*/
 	function SetFieldsFromHash($hash, $set_fields = null)
 	{
 		// used in formatter which work with multiple fields together
 		foreach($hash as $field_name => $field_value) {
 			if (is_numeric($field_name) || !array_key_exists($field_name, $this->Fields)) {
 				continue;
 			}
 
 			if (is_array($set_fields) && !in_array($field_name, $set_fields)) {
 				continue;
 			}
 
 			$this->SetDirtyField($field_name, $field_value);
 		}
 
 		// formats all fields using associated formatters
 		foreach ($hash as $field_name => $field_value)
 		{
 			if (is_numeric($field_name) || !array_key_exists($field_name, $this->Fields)) {
 				continue;
 			}
 
 			if (is_array($set_fields) && !in_array($field_name, $set_fields)) {
 				continue;
 			}
 
 			$this->SetField($field_name,$field_value);
 		}
 	}
 
 	function SetDBFieldsFromHash($hash, $set_fields = null)
 	{
 		foreach ($hash as $field_name => $field_value) {
 			if (is_numeric($field_name) || !array_key_exists($field_name, $this->Fields)) {
 				continue;
 			}
 
 			if (is_array($set_fields) && !in_array($field_name, $set_fields)) {
 				continue;
 			}
 
 			$this->SetDBField($field_name, $field_value);
 		}
 	}
 
 	/**
 	* Returns part of SQL WHERE clause identifing the record, ex. id = 25
 	*
 	* @access public
 	* @param string $method Child class may want to know who called GetKeyClause, Load(), Update(), Delete() send its names as method
 	* @param Array $keys_hash alternative, then item id, keys hash to load item by
 	* @return void
 	* @see kDBItem::Load()
 	* @see kDBItem::Update()
 	* @see kDBItem::Delete()
 	*/
 	function GetKeyClause($method=null, $keys_hash = null)
 	{
 		if( !isset($keys_hash) ) $keys_hash = Array($this->IDField => $this->ID);
 
 		$ret = '';
 		foreach($keys_hash as $field => $value)
 		{
 			if (!preg_match('/\./', $field)) {
 				$ret .= '(`'.$this->TableName.'`.'.$field.' = '.$this->Conn->qstr($value).') AND ';
 			}
 			else {
 				$ret .= '('.$field.' = '.$this->Conn->qstr($value).') AND ';
 			}
 		}
 
 		return preg_replace('/(.*) AND $/', '\\1', $ret);
 	}
 
 	/**
 	* Loads item from the database by given id
 	*
 	* @access public
 	* @param mixed $id item id of keys->values hash to load item by
 	* @param string $id_field_name Optional parameter to load item by given Id field
 	* @return bool True if item has been loaded, false otherwise
 	*/
 	function Load($id, $id_field_name = null)
 	{
 		if ( isset($id_field_name) ) {
 			$this->SetIDField($id_field_name); // set new IDField
 		}
 
 		$keys_sql = '';
 		if (is_array($id)) {
 			$keys_sql = $this->GetKeyClause('load', $id);
 		}
 		else {
 			$this->setID($id);
 			$keys_sql = $this->GetKeyClause('load');
 		}
 
 		if ( isset($id_field_name) ) {
 			// restore original IDField from unit config
 			$this->setIDField( $this->Application->getUnitOption($this->Prefix, 'IDField') );
 		}
 
 		if (($id === false) || !$keys_sql) {
 			return $this->Clear();
 		}
 
 		if (!$this->raiseEvent('OnBeforeItemLoad', $id)) {
 			return false;
 		}
 
 		$q = $this->GetSelectSQL() . ' WHERE ' . $keys_sql;
 		$field_values = $this->Conn->GetRow($q);
 
 		if ($field_values) {
 			$this->FieldValues = array_merge_recursive2($this->FieldValues, $field_values);
 			$this->OriginalFieldValues = $this->FieldValues;
 		}
 		else {
 			return $this->Clear();
 		}
 
 		if (is_array($id) || isset($id_field_name)) {
 			$this->setID($this->FieldValues[$this->IDField]);
 		}
 
 		$this->UpdateFormattersSubFields(); // used for updating separate virtual date/time fields from DB timestamp (for example)
 
 		$this->raiseEvent('OnAfterItemLoad', $this->GetID());
 		$this->Loaded = true;
 
 		return true;
 	}
 
 	/**
 	* Builds select sql, SELECT ... FROM parts only
 	*
 	* @access public
 	* @return string
 	*/
 	function GetSelectSQL()
 	{
 		$sql = $this->addCalculatedFields($this->SelectClause);
 		return parent::GetSelectSQL($sql);
 	}
 
 	function UpdateFormattersMasterFields()
 	{
 		foreach ($this->Fields as $field => $options) {
 			if (isset($options['formatter'])) {
 				$formatter =& $this->Application->recallObject($options['formatter']);
 				$formatter->UpdateMasterFields($field, $this->GetDBField($field), $options, $this);
 			}
 		}
 	}
 
 	/**
 	 * Allows to skip certain fields from getting into sql queries
 	 *
 	 * @param string $field_name
 	 * @param mixed $force_id
 	 * @return bool
 	 */
 	function skipField($field_name, $force_id = false)
 	{
 		$skip = false;
 
 		// 1. skipping 'virtual' field
 		$skip = $skip || array_key_exists($field_name, $this->VirtualFields);
 
 		// 2. don't write empty field value to db, when "skip_empty" option is set
 		$field_value = array_key_exists($field_name, $this->FieldValues) ? $this->FieldValues[$field_name] : false;
 		$skip_empty = array_key_exists('skip_empty', $this->Fields[$field_name]) ? $this->Fields[$field_name]['skip_empty'] : false;
 		$skip = $skip || (!$field_value && $skip_empty);
 
 		// 3. skipping field not in Fields (nor virtual, nor real)
 		$skip = $skip || !array_key_exists($field_name, $this->Fields);
 
 		return $skip;
 	}
 
 	/**
 	* Updates previously loaded record with current item' values
 	*
 	* @access public
 	* @param int Primery Key Id to update
 	* @return bool
 	*/
 	function Update($id = null, $system_update = false)
 	{
 		if (isset($id)) {
 			$this->setID($id);
 		}
 
 		if (!$this->raiseEvent('OnBeforeItemUpdate')) {
 			return false;
 		}
 
 		if (!isset($this->ID)) {
 			// ID could be set inside OnBeforeItemUpdate event, so don't combine this check with previous one
 			return false;
 		}
 
 		// validate before updating
 		if (!$this->Validate()) {
 			return false;
 		}
 
 	    if (!$this->raiseEvent('OnAfterItemValidate')) {
 	    	return false;
 	    }
 
 	    if (!$this->FieldValues) {
 	    	// nothing to update
 	    	return true;
 	    }
 
 	    $sql = '';
 
 	    foreach ($this->FieldValues as $field_name => $field_value) {
 	    	if ($this->skipField($field_name)) {
 	    		continue;
 	    	}
 
 	    	if ( is_null($field_value) ) {
 	    		if (array_key_exists('not_null', $this->Fields[$field_name]) && $this->Fields[$field_name]['not_null']) {
 	    			// "kFormatter::Parse" methods converts empty values to NULL and for
 	    			// not-null fields they are replaced with default value here
 	    			$field_value = $this->Fields[$field_name]['default'];
 	    		}
 	    	}
 
 	    	$sql .= '`' . $field_name . '` = ' . $this->Conn->qstr($field_value) . ', ';
 	   	}
 
 	   	$sql = 'UPDATE ' . $this->TableName . '
 	   			SET ' . substr($sql, 0, -2) . '
 	   			WHERE ' . $this->GetKeyClause('update');
 
 	    if ($this->Conn->ChangeQuery($sql) === false) {
 	    	// there was and sql error
 	    	return false;
 	    }
 
 		$affected = $this->Conn->getAffectedRows();
 		if (!$system_update && $affected == 1) {
 			$this->setModifiedFlag(clUPDATE);
 		}
 
 		$this->saveCustomFields();
 	    $this->raiseEvent('OnAfterItemUpdate');
 	    $this->Loaded = true;
 
 	    if ($this->mode != 't') {
 			$this->Application->resetCounters($this->TableName);
 		}
 
 		return true;
 	}
 
 	function ValidateField($field)
 	{
 		$options = $this->Fields[$field];
 
 		/*if (isset($options['formatter'])) {
 			$formatter =& $this->Application->recallObject($options['formatter']);
 			$formatter->UpdateMasterFields($field, $this->GetDBField($field), $options, $this);
 		}*/
 
 		$error_field = isset($options['error_field']) ? $options['error_field'] : $field;
 		$res = !isset($this->FieldErrors[$error_field]['pseudo']) || !$this->FieldErrors[$error_field]['pseudo'];
 
 		$res = $res && $this->ValidateRequired($field, $options);
 		$res = $res && $this->ValidateType($field, $options);
 		$res = $res && $this->ValidateRange($field, $options);
 		$res = $res && $this->ValidateUnique($field, $options);
 		$res = $res && $this->CustomValidation($field, $options);
 
 		return $res;
 	}
 
 	/**
 	 * Validate all item fields based on
 	 * constraints set in each field options
 	 * in config
 	 *
 	 * @return bool
 	 * @access private
 	 */
 	function Validate()
 	{
 		$this->UpdateFormattersMasterFields(); //order is critical - should be called BEFORE checking errors
 
 		if ($this->IgnoreValidation) {
 			return true;
 		}
 
 		$global_res = true;
 		foreach ($this->Fields as $field => $params) {
 			$res = $this->ValidateField($field);
 
 
 			$global_res = $global_res && $res;
 		}
 
 		if (!$global_res && $this->Application->isDebugMode()) {
 			$error_msg = '	Validation failed in prefix <strong>'.$this->Prefix.'</strong>,
 							FieldErrors follow (look at items with <strong>"pseudo"</strong> key set)<br />
 							You may ignore this notice if submitted data really has a validation error';
 			trigger_error(trim($error_msg), E_USER_NOTICE);
 			$this->Application->Debugger->dumpVars($this->FieldErrors);
 		}
 
 		return $global_res;
 	}
 
 	/**
 	 * Check field value by user-defined alghoritm
 	 *
 	 * @param string $field field name
 	 * @param Array $params field options from config
 	 * @return bool
 	 */
 	function CustomValidation($field, $params)
 	{
 		return true;
 	}
 
 	/**
 	 * Check if item has errors
 	 *
 	 * @param Array $skip_fields fields to skip during error checking
 	 * @return bool
 	 */
 	function HasErrors($skip_fields)
 	{
 		$global_res = false;
 
 		foreach ($this->Fields as $field => $field_params) {
 			// If Formatter has set some error messages during values parsing
 			if ( !( in_array($field, $skip_fields) ) &&
 				isset($this->FieldErrors[$field]['pseudo']) && $this->FieldErrors[$field] != '') {
 				$global_res = true;
 			}
 		}
 		return $global_res;
 	}
 
 	/**
 	 * Check if value in field matches field type specified in config
 	 *
 	 * @param string $field field name
 	 * @param Array $params field options from config
 	 * @return bool
 	 */
 	function ValidateType($field, $params)
 	{
 		$res = true;
 		$val = $this->FieldValues[$field];
 		if ( 	$val != '' &&
 					isset($params['type']) &&
 					preg_match("#int|integer|double|float|real|numeric|string#", $params['type'])
 				) {
 			if ($params['type'] == 'numeric') {
 				trigger_error('Invalid field type <strong>'.$params['type'].'</strong> (in ValidateType method), please use <strong>float</strong> instead', E_USER_NOTICE);
 				$params['type'] = 'float';
 			}
 			$res = is_numeric($val);
 			if ($params['type']=='string' || $res) {
 				$f = 'is_'.$params['type'];
 				settype($val, $params['type']);
 				$res = $f($val) && ($val == $this->FieldValues[$field]);
 			}
 			if (!$res) {
 				$this->SetError($field, 'bad_type', null, $params['type']);
 			}
 		}
 		return $res;
 	}
 
 	/**
 	 * Check if value is set for required field
 	 *
 	 * @param string $field field name
 	 * @param Array $params field options from config
 	 * @return bool
 	 * @access private
 	 */
 	function ValidateRequired($field, $params)
 	{
 		$res = true;
 		if (isset($params['required']) && $params['required']) {
 			$check_value = $this->FieldValues[$field];
 			if ($this->Application->ConfigValue('TrimRequiredFields')) {
 				$check_value = trim($check_value);
 			}
 			$res = ((string)$check_value != '');
 		}
 
 		if (!$res) {
 			$this->SetError($field, 'required');
 		}
 
 		return $res;
 	}
 
 	/**
 	 * Validates that current record has unique field combination among other table records
 	 *
 	 * @param string $field field name
 	 * @param Array $params field options from config
 	 * @return bool
 	 * @access private
 	 */
 	function ValidateUnique($field, $params)
 	{
 		$res = true;
 		$unique_fields = getArrayValue($params,'unique');
 		if($unique_fields !== false)
 		{
 			$where = Array();
 			array_push($unique_fields,$field);
 			foreach($unique_fields as $unique_field)
 			{
 				// if field is not empty or if it is required - we add where condition
 				if ((string)$this->GetDBField($unique_field) != '' || (isset($this->Fields[$unique_field]['required']) && $this->Fields[$unique_field]['required'])) {
 					$where[] = '`'.$unique_field.'` = '.$this->Conn->qstr( $this->GetDBField($unique_field) );
 				}
 				else {
 					// not good if we check by less fields than indicated
 					return true;
 				}
 			}
 			// This can ONLY happen if all unique fields are empty and not required.
 			// In such case we return true, because if unique field is not required there may be numerous empty values
 //			if (!$where) return true;
 
 			$sql = 'SELECT COUNT(*) FROM %s WHERE ('.implode(') AND (',$where).') AND ('.$this->IDField.' <> '.(int)$this->ID.')';
 
 			$res_temp = $this->Conn->GetOne( str_replace('%s', $this->TableName, $sql) );
 
 			$current_table_only = getArrayValue($params, 'current_table_only'); // check unique record only in current table
 			$res_live = $current_table_only ? 0 : $this->Conn->GetOne( str_replace('%s', $this->Application->GetLiveName($this->TableName), $sql) );
 
 			$res = ($res_temp == 0) && ($res_live == 0);
 
 			if (!$res) {
 				$this->SetError($field, 'unique');
 			}
 		}
 		return $res;
 	}
 
 	/**
 	 * Check if field value is in range specified in config
 	 *
 	 * @param string $field field name
 	 * @param Array $params field options from config
 	 * @return bool
 	 * @access private
 	 */
 	function ValidateRange($field, $params)
 	{
 		$res = true;
 		$val = $this->FieldValues[$field];
 
 		if ( isset($params['type']) && preg_match("#int|integer|double|float|real#", $params['type']) && strlen($val) > 0 ) {
 			if ( isset($params['max_value_inc'])) {
 				$res = $res && $val <= $params['max_value_inc'];
 				$max_val = $params['max_value_inc'].' (inclusive)';
 			}
 			if ( isset($params['min_value_inc'])) {
 				$res = $res && $val >= $params['min_value_inc'];
 				$min_val = $params['min_value_inc'].' (inclusive)';
 			}
 			if ( isset($params['max_value_exc'])) {
 				$res = $res && $val < $params['max_value_exc'];
 				$max_val = $params['max_value_exc'].' (exclusive)';
 			}
 			if ( isset($params['min_value_exc'])) {
 				$res = $res && $val > $params['min_value_exc'];
 				$min_val = $params['min_value_exc'].' (exclusive)';
 			}
 		}
 		if (!$res) {
 			if ( !isset($min_val) ) $min_val = '-&infin;';
 			if ( !isset($max_val) ) $max_val = '&infin;';
 
 			$this->SetError($field, 'value_out_of_range', null, Array ($min_val, $max_val));
 			return $res;
 		}
 		if ( isset($params['max_len'])) {
 			$res = $res && mb_strlen($val) <= $params['max_len'];
 		}
 		if ( isset($params['min_len'])) {
 			$res = $res && mb_strlen($val) >= $params['min_len'];
 		}
 		if (!$res) {
 			$error_params = Array (getArrayValue($params, 'min_len'), getArrayValue($params, 'max_len'));
 			$this->SetError($field, 'length_out_of_range', null, $error_params);
 			return $res;
 		}
 		return $res;
 	}
 
 	/**
 	 * Return error message for field
 	 *
 	 * @param string $field
 	 * @return string
 	 * @access public
 	 */
 	function GetErrorMsg($field, $force_escape = null)
 	{
 		if( !isset($this->FieldErrors[$field]) ) return '';
 
 		$err = getArrayValue($this->FieldErrors[$field], 'pseudo');
 		if (!$err) return '';
 		// if special error msg defined in config
 		if( isset($this->Fields[$field]['error_msgs'][$err]) )
 		{
 			$msg = $this->Fields[$field]['error_msgs'][$err];
 		}
 		else //fall back to defaults
 		{
 			if( !isset($this->ErrorMsgs[$err]) ) {
 				trigger_error('No user message is defined for pseudo error <b>'.$err.'</b><br>', E_USER_WARNING);
 				return $err; //return the pseudo itself
 			}
 			$msg = $this->ErrorMsgs[$err];
 		}
 		$msg = $this->Application->ReplaceLanguageTags($msg, $force_escape);
 
 		if ( isset($this->FieldErrors[$field]['params']) )
 		{
 			return vsprintf($msg, $this->FieldErrors[$field]['params']);
 		}
 		return $msg;
 	}
 
 	/**
 	* Creates a record in the database table with current item' values
 	*
 	* @param mixed $force_id Set to TRUE to force creating of item's own ID or to value to force creating of passed id. Do not pass 1 for true, pass exactly TRUE!
 	* @access public
 	* @return bool
 	*/
 	function Create($force_id = false, $system_create = false)
 	{
 		if (!$this->raiseEvent('OnBeforeItemCreate')) {
 			return false;
 		}
 
 		// Validating fields before attempting to create record
 		if (!$this->Validate()) {
 			return false;
 		}
 
 		if (!$this->raiseEvent('OnAfterItemValidate')) {
 			return false;
 		}
 
 		if (is_int($force_id)) {
 			$this->FieldValues[$this->IDField] = $force_id;
 		}
 		elseif (!$force_id || !is_bool($force_id)) {
 			$this->FieldValues[$this->IDField] = $this->generateID();
 		}
 
 		$fields_sql = '';
 		$values_sql = '';
 		foreach ($this->FieldValues as $field_name => $field_value) {
 			if ($this->skipField($field_name, $force_id)) {
 				continue;
 			}
 
 			if (is_null($field_value)) {
 				if (array_key_exists('not_null', $this->Fields[$field_name]) && $this->Fields[$field_name]['not_null']) {
 					// "kFormatter::Parse" methods converts empty values to NULL and for
 	    			// not-null fields they are replaced with default value here
 					$values_sql .= $this->Conn->qstr($this->Fields[$field_name]['default']);
 				}
 				else {
 					$values_sql .= $this->Conn->qstr($field_value);
 				}
 			}
 			else {
 				if (($field_name == $this->IDField) && ($field_value == 0)) {
 					// don't skip IDField in INSERT statement, just use DEFAULT keyword as it's value
 					$values_sql .= 'DEFAULT';
 				}
 				else {
 					$values_sql .= $this->Conn->qstr($field_value);
 				}
 			}
 
 			$fields_sql .= '`' . $field_name . '`, '; //Adding field name to fields block of Insert statement
 			$values_sql .= ', ';
 		}
 
 		$sql = 'INSERT INTO ' . $this->TableName . ' (' . substr($fields_sql, 0, -2) . ')
 				VALUES (' . substr($values_sql, 0, -2) . ')';
 
 		//Executing the query and checking the result
 		if ($this->Conn->ChangeQuery($sql) === false) {
 			return false;
 		}
 
 		$insert_id = $this->Conn->getInsertID();
 		if ($insert_id == 0) {
 			// insert into temp table (id is not auto-increment field)
 			$insert_id = $this->FieldValues[$this->IDField];
 		}
 		$this->setID($insert_id);
 
 		if (!$system_create){
 			$this->setModifiedFlag(clCREATE);
 		}
 
 		$this->saveCustomFields();
 		if ($this->mode != 't') {
 			$this->Application->resetCounters($this->TableName);
 		}
 		$this->raiseEvent('OnAfterItemCreate');
 		$this->Loaded = true;
 
 		return true;
 	}
 
 	/**
 	* Deletes the record from databse
 	*
 	* @access public
 	* @return bool
 	*/
 	function Delete($id = null)
 	{
 		if (isset($id)) {
 			$this->setID($id);
 		}
 
 		if (!$this->raiseEvent('OnBeforeItemDelete')) {
 			return false;
 		}
 
 		$sql = 'DELETE FROM ' . $this->TableName . '
 				WHERE ' . $this->GetKeyClause('Delete');
 
 		$ret = $this->Conn->ChangeQuery($sql);
 		$affected_rows = $this->Conn->getAffectedRows();
 
 		$this->setModifiedFlag(clDELETE); // will change affected rows, so get it before this line
 
 		if ($affected_rows > 0) {
 			// something was actually deleted
 			$this->raiseEvent('OnAfterItemDelete');
 		}
 
 		if ($this->mode != 't') {
 			$this->Application->resetCounters($this->TableName);
 		}
 
 		return $ret;
 	}
 
 	function PopulateMultiLangFields()
 	{
 		$ml_helper =& $this->Application->recallObject('kMultiLanguageHelper');
 		/* @var $ml_helper kMultiLanguageHelper */
 
 		$lang_count = $ml_helper->getLanguageCount();
 		foreach ($this->Fields as $field => $options)
 		{
 			// master field is set only for CURRENT language
 			if (isset($options['formatter']) && $options['formatter'] == 'kMultiLanguage' && isset($options['master_field'])) {
 				if (preg_match('/^l([0-9]+)_(.*)/', $field, $regs)) {
 					$l = $regs[1];
 					$name = $regs[2];
 					// MuliLanguage formatter sets error_field to master_field, but in PopulateMlFields mode, we display ML fields directly
 					// so we set it back to itself, otherwise error will not be displayed
 					$this->Fields['l' . $l . '_' . $name]['error_field'] = 'l' . $l . '_' . $name;
 					for ($i = 1; $i <= $lang_count; $i++) {
 						if ($i == $l || !$ml_helper->LanguageFound($i)) continue;
 						$f_options = $options;
 						$f_options['error_field'] = 'l' . $i . '_' . $name;  // set error field back to itself - see comment above
 						if ($i != $this->Application->GetDefaultLanguageId()) {
 							unset($f_options['required']); // all non-primary language field set to non-required
 						}
 						$this->Fields['l' . $i . '_' . $name] = $f_options;
 					}
 				}
 			}
 		}
 	}
 
 	/**
 	 * Sets new name for item in case if it is beeing copied
 	 * in same table
 	 *
 	 * @param array $master Table data from TempHandler
 	 * @param int $foreign_key ForeignKey value to filter name check query by
 	 * @param string $title_field FieldName to alter, by default - TitleField of the prefix
 	 * @param string $format sprintf-style format of renaming pattern, by default Copy %1$s of %2$s which makes it Copy [Number] of Original Name
 	 * @access private
 	 */
 	function NameCopy($master=null, $foreign_key=null, $title_field=null, $format='Copy %1$s of %2$s')
 	{
 		if (!isset($title_field)) {
 		$title_field = $this->Application->getUnitOption($this->Prefix, 'TitleField');
 		if (!$title_field || isset($this->CalculatedFields[$title_field]) ) return;
 		}
 
 		$new_name = $this->GetDBField($title_field);
 		$original_checked = false;
 		do {
 			if ( preg_match('/'.sprintf($format, '([0-9]*) *', '(.*)').'/', $new_name, $regs) ) {
 				$new_name = sprintf($format, ($regs[1]+1), $regs[2]);
 			}
 			elseif ($original_checked) {
 				$new_name = sprintf($format, '', $new_name);
 			}
 
 			// if we are cloning in temp table this will look for names in temp table,
 			// since object' TableName contains correct TableName (for temp also!)
 			// if we are cloning live - look in live
 			$query = 'SELECT '.$title_field.' FROM '.$this->TableName.'
 								WHERE '.$title_field.' = '.$this->Conn->qstr($new_name);
 
 			$foreign_key_field = getArrayValue($master, 'ForeignKey');
 			$foreign_key_field = is_array($foreign_key_field) ? $foreign_key_field[ $master['ParentPrefix'] ] : $foreign_key_field;
 
 			if ($foreign_key_field && isset($foreign_key)) {
 				$query .= ' AND '.$foreign_key_field.' = '.$foreign_key;
 			}
 
 			$res = $this->Conn->GetOne($query);
 
 			/*// if not found in live table, check in temp table if applicable
 			if ($res === false && $object->Special == 'temp') {
 				$query = 'SELECT '.$name_field.' FROM '.$this->GetTempName($master['TableName']).'
 									WHERE '.$name_field.' = '.$this->Conn->qstr($new_name);
 				$res = $this->Conn->GetOne($query);
 			}*/
 
 			$original_checked = true;
 		} while ($res !== false);
 		$this->SetDBField($title_field, $new_name);
 	}
 
 	function raiseEvent($name, $id = null, $additional_params = Array())
 	{
 		if( !isset($id) ) $id = $this->GetID();
 		$event = new kEvent( Array('name'=>$name,'prefix'=>$this->Prefix,'special'=>$this->Special) );
 		$event->setEventParam('id', $id);
 
 		if ($additional_params) {
 			foreach ($additional_params as $ap_name => $ap_value) {
 				$event->setEventParam($ap_name, $ap_value);
 			}
 		}
 
 		$this->Application->HandleEvent($event);
 		return $event->status == erSUCCESS ? true : false;
 	}
 
 	/**
 	 * Set's new ID for item
 	 *
 	 * @param int $new_id
 	 * @access public
 	 */
 	function setID($new_id)
 	{
 		$this->ID = $new_id;
 		$this->SetDBField($this->IDField, $new_id);
 	}
 
 	/**
 	 * Generate and set new temporary id
 	 *
 	 * @access private
 	 */
 	function setTempID()
 	{
 		$new_id = (int)$this->Conn->GetOne('SELECT MIN('.$this->IDField.') FROM '.$this->TableName);
 		if($new_id > 0) $new_id = 0;
 		--$new_id;
 
 		$this->Conn->Query('UPDATE '.$this->TableName.' SET `'.$this->IDField.'` = '.$new_id.' WHERE `'.$this->IDField.'` = '.$this->GetID());
 
 		if ($this->ShouldLogChanges()) {
 			// Updating TempId in ChangesLog, if changes are disabled
 			$ses_var_name = $this->Application->GetTopmostPrefix($this->Prefix).'_changes_'.$this->Application->GetTopmostWid($this->Prefix);
 			$changes = $this->Application->RecallVar($ses_var_name);
 			$changes = $changes ? unserialize($changes) : Array ();
 			if ($changes) {
 				foreach ($changes as $key => $rec) {
 					if ($rec['Prefix'] == $this->Prefix && $rec['ItemId'] == $this->GetID()) {
 						$changes[$key]['ItemId'] = $new_id;
 					}
 				}
 			}
 			$this->Application->StoreVar($ses_var_name, serialize($changes));
 		}
 
 		$this->SetID($new_id);
 	}
 
 	/**
 	 * Set's modification flag for main prefix of current prefix to true
 	 *
 	 * @access private
 	 * @author Alexey
 	 */
 	function setModifiedFlag($mode = null)
 	{
 		$main_prefix = $this->Application->GetTopmostPrefix($this->Prefix);
 		$this->Application->StoreVar($main_prefix.'_modified', '1');
 
 		if ($this->ShouldLogChanges()) {
 			$this->LogChanges($main_prefix, $mode);
 			if (!$this->IsTempTable()) {
 				$handler =& $this->Application->recallObject($this->Prefix.'_EventHandler');
 				$ses_var_name = $main_prefix.'_changes_'.$this->Application->GetTopmostWid($this->Prefix);
 				$handler->SaveLoggedChanges($ses_var_name);
 			}
 		}
 	}
 
 	/**
 	 * Determines, that changes made to this item should be written to change log
 	 *
 	 * @return bool
 	 */
 	function ShouldLogChanges()
 	{
 		$log_changes = $this->Application->getUnitOption($this->Prefix, 'LogChanges') || $this->Application->ConfigValue('UseChangeLog');
 
 		return $log_changes && !$this->Application->getUnitOption($this->Prefix, 'ForceDontLogChanges');
 	}
 
 	function LogChanges($main_prefix, $mode)
 	{
 		if (!$mode) {
 			return ;
 		}
 
 		$ses_var_name = $main_prefix.'_changes_'.$this->Application->GetTopmostWid($this->Prefix);
 		$changes = $this->Application->RecallVar($ses_var_name);
 		$changes = $changes ? unserialize($changes) : array();
 
 		$general = array(
 			'Prefix' => $this->Prefix,
 			'ItemId' => $this->GetID(),
 			'OccuredOn' => adodb_mktime(),
 			'MasterPrefix' => $main_prefix,
 			'MasterId' => $this->Prefix == $main_prefix ? $this->GetID() : $this->Application->GetVar($main_prefix.'_id'), // is that correct (Kostja)??
 			'Action' => $mode,
 		);
 		switch ($mode) {
 			case clUPDATE:
 				$changes[] = array_merge($general, Array(
 					'Changes' => serialize(array_merge($this->GetTitleField(), $this->GetChangedFields())),
 				));
 				break;
 			case clCREATE:
 				$changes[] = array_merge($general, Array(
 					'Changes' => serialize($this->GetTitleField()),
 				));
 				break;
 			case clDELETE:
 				$changes[] = array_merge($general, Array(
 					'Changes' => serialize(array_merge($this->GetTitleField(), $this->GetRealFields())),
 				));
 		}
 
 		$this->Application->StoreVar($ses_var_name, serialize($changes));
 	}
 
 	function GetTitleField()
 	{
 		$title_field = $this->Application->getUnitOption($this->Prefix, 'TitleField');
 		if ($title_field && $this->GetField($title_field)) {
 			return Array($title_field => $this->GetField($title_field));
 		}
 	}
 
 	function GetRealFields()
 	{
 		if (function_exists('array_diff_key')) {
 			$db_fields = array_diff_key($this->FieldValues, $this->VirtualFields, $this->CalculatedFields);
 		}
 		else {
 			$db_fields = array();
 			foreach ($this->FieldValues as $key => $value) {
 				if (array_key_exists($key, $this->VirtualFields) || array_key_exists($key, $this->CalculatedFields)) continue;
 				$db_fields[$key] = $value;
 			}
 		}
 		return $db_fields;
 	}
 
 	function GetChangedFields()
 	{
 		$changes = array();
 
 		$diff = array_diff_assoc($this->GetRealFields(), $this->OriginalFieldValues);
 		foreach ($diff as $field => $new_value) {
 			$changes[$field] = array('old' => $this->GetOriginalField($field, true), 'new' => $this->GetField($field));
 		}
 		return $changes;
 	}
 
 	/**
 	 * Returns ID of currently processed record
 	 *
 	 * @return int
 	 * @access public
 	 */
 	function GetID()
 	{
 		return $this->ID;
 	}
 
 	/**
 	 * Generates ID for new items before inserting into database
 	 *
 	 * @return int
 	 * @access private
 	 */
 	function generateID()
 	{
 		return 0;
 	}
 
 	/**
 	 * Returns true if item was loaded successfully by Load method
 	 *
 	 * @return bool
 	 */
 	function isLoaded()
 	{
 		return $this->Loaded;
 	}
 
 	/**
 	 * Checks if field is required
 	 *
 	 * @param string $field
 	 * @return bool
 	 */
 	function isRequired($field)
 	{
 		return getArrayValue( $this->Fields[$field], 'required' );
 	}
 
 	/**
 	 * Sets new required flag to field
 	 *
 	 * @param string $field
 	 * @param bool $is_required
 	 */
 	function setRequired($field, $is_required = true)
 	{
 		$this->Fields[$field]['required'] = $is_required;
 	}
 
 	function Clear($new_id = null)
 	{
 		$this->Loaded = false;
 		$this->FieldValues = Array();
 		$this->OriginalFieldValues = Array ();
 		$this->SetDefaultValues(); // will wear off kDBItem::setID effect, so set it later
 		$this->FieldErrors = Array();
 
 		$this->setID($new_id);
 
 		return $this->Loaded;
 	}
 
 	function Query($force = false)
 	{
 		if( $this->Application->isDebugMode() )
 		{
 			$this->Application->Debugger->appendTrace();
 		}
 		trigger_error('<b>Query</b> method is called in class <b>'.get_class($this).'</b> for prefix <b>'.$this->getPrefixSpecial().'</b>', E_USER_ERROR);
 	}
 
 	function saveCustomFields()
 	{
 		if (!$this->customFields) {
 			return true;
 		}
 
 		$cdata_key = rtrim($this->Prefix.'-cdata.'.$this->Special, '.');
 		$cdata =& $this->Application->recallObject($cdata_key, null, Array('skip_autoload' => true, 'populate_ml_fields' => true));
 
 		$resource_id = $this->GetDBField('ResourceId');
 		$cdata->Load($resource_id, 'ResourceId');
 		$cdata->SetDBField('ResourceId', $resource_id);
 
 		$ml_formatter =& $this->Application->recallObject('kMultiLanguage');
 		/* @var $ml_formatter kMultiLanguage */
 
 		foreach ($this->customFields as $custom_id => $custom_name) {
 			$force_primary = isset($cdata->Fields['cust_'.$custom_id]['force_primary']) && $cdata->Fields['cust_'.$custom_id]['force_primary'];
 			$cdata->SetDBField($ml_formatter->LangFieldName('cust_'.$custom_id, $force_primary), $this->GetDBField('cust_'.$custom_name));
 		}
 
 		if ($cdata->isLoaded()) {
 			$ret = $cdata->Update();
 		}
 		else {
 			 $ret = $cdata->Create();
 			 if ($cdata->mode == 't') $cdata->setTempID();
 		}
 
 		return $ret;
 	}
 
 	/**
 	 * Returns specified field value from all selected rows.
 	 * Don't affect current record index
 	 *
 	 * @param string $field
 	 * @return Array
 	 */
 	function GetCol($field)
 	{
 		return Array (0 => $this->GetDBField($field));
 	}
 }
 
 
 
 ?>
\ No newline at end of file
Index: branches/5.0.x/core/kernel/application.php
===================================================================
--- branches/5.0.x/core/kernel/application.php	(revision 12297)
+++ branches/5.0.x/core/kernel/application.php	(revision 12298)
@@ -1,2955 +1,2956 @@
 <?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.net/license/ for copyright notices and details.
 */
 
 /**
 * Basic class for Kernel4-based Application
 *
 * This class is a Facade for any other class which needs to deal with Kernel4 framework.<br>
 * The class incapsulates the main run-cycle of the script, provide access to all other objects in the framework.<br>
 * <br>
 * The class is a singleton, which means that there could be only one instance of kApplication in the script.<br>
 * This could be guranteed by NOT calling the class constuctor directly, but rather calling kApplication::Instance() method,
 * which returns an instance of the application. The method gurantees that it will return exactly the same instance for any call.<br>
 * See singleton pattern by GOF.
 * @package kernel4
 */
 
 class kApplication {
 
 	/**
 	 * Is true, when Init method was called already, prevents double initialization
 	 *
 	 * @var bool
 	 */
 	var $InitDone = false;
 
 	/**
 	* Holds internal NParser object
 	* @access private
 	* @var NParser
 	*/
 	var $Parser;
 
 
 	/**
 	 * New Parser (Experimental)
 	 *
 	 * @var NParser
 	 */
 	var $NParser;
 
 	/**
 	* Holds parser output buffer
 	* @access private
 	* @var string
 	*/
 	var $HTML;
 
 	/**
 	 * Prevents request from beeing proceeded twice in case if application init is called mere then one time
 	 *
 	 * @var bool
 	 * @todo This is not good anyway (by Alex)
 	 */
 	var $RequestProcessed = false;
 
 	/**
 	* The main Factory used to create
 	* almost any class of kernel and
 	* modules
 	*
 	* @access private
 	* @var kFactory
 	*/
 	var $Factory;
 
 	/**
 	 * All ConfigurationValues table content (hash) here
 	 *
 	 * @var Array
 	 * @access private
 	 */
 	var $ConfigHash = Array();
 
 	/**
 	 * Ids of config variables used in current run (for caching)
 	 *
 	 * @var Array
 	 * @access private
 	 */
 	var $ConfigCacheIds = array();
 
 	/**
 	 * Template names, that will be used instead of regular templates
 	 *
 	 * @var Array
 	 */
 	var $ReplacementTemplates = Array ();
 
 	/**
 	 * Mod-Rewrite listeners used during url building and parsing
 	 *
 	 * @var Array
 	 */
 	var $RewriteListeners = Array ();
 
 	/**
 	 * Reference to debugger
 	 *
 	 * @var Debugger
 	 */
 	var $Debugger = null;
 
 	/**
 	 * Holds all phrases used
 	 * in code and template
 	 *
 	 * @var PhrasesCache
 	 */
 	var $Phrases;
 
 	/**
 	 * Modules table content, key - module name
 	 *
 	 * @var Array
 	 */
 	var $ModuleInfo = Array();
 
 	/**
 	 * Holds DBConnection
 	 *
 	 * @var kDBConnection
 	 */
 	var $Conn = null;
 
 	/**
 	 * Maintains list of user-defined error handlers
 	 *
 	 * @var Array
 	 */
 	var $errorHandlers = Array();
 
 
 	// performance needs:
 	/**
 	 * Holds a refererence to httpquery
 	 *
 	 * @var kHttpQuery
 	 */
 	var $HttpQuery = null;
 
 	/**
 	 * Holds a reference to UnitConfigReader
 	 *
 	 * @var kUnitConfigReader
 	 */
 	var $UnitConfigReader = null;
 
 	/**
 	 * Holds a reference to Session
 	 *
 	 * @var Session
 	 */
 	var $Session = null;
 
 	/**
 	 * Holds a ref to kEventManager
 	 *
 	 * @var kEventManager
 	 */
 	var $EventManager = null;
 
 	/**
 	 * Ref to itself, needed because everybody used to write $this->Application, even inside kApplication
 	 *
 	 * @var kApplication
 	 */
 	var $Application = null;
 
 	/**
 	 * Ref for TemplatesChache
 	 *
 	 * @var TemplatesCache
 	 */
 	var $TemplatesCache = null;
 
 	var $CompilationCache = array(); //used when compiling templates
 	var $CachedProcessors = array(); //used when running compiled templates
 
 	var $LambdaElements = 1; // for autonumbering unnamed RenderElements [any better place for this prop? KT]
 
 	/**
 	 * Holds current NParser tag while parsing, can be used in error messages to display template file and line
 	 *
 	 * @var unknown_type
 	 */
 	var $CurrentNTag = null;
 
 	/**
 	 * Memcache object pointer
 	 *
 	 * @var Memcache
 	 */
 	var $Memcached = null;
 
 	/**
 	* Returns kApplication instance anywhere in the script.
  	*
  	* This method should be used to get single kApplication object instance anywhere in the
  	* Kernel-based application. The method is guranteed to return the SAME instance of kApplication.
  	* Anywhere in the script you could write:
  	* <code>
  	*		$application =& kApplication::Instance();
  	* </code>
  	* or in an object:
  	* <code>
  	*		$this->Application =& kApplication::Instance();
  	* </code>
  	* to get the instance of kApplication. Note that we call the Instance method as STATIC - directly from the class.
  	* To use descendand of standard kApplication class in your project you would need to define APPLICATION_CLASS constant
  	* BEFORE calling kApplication::Instance() for the first time. If APPLICATION_CLASS is not defined the method would
  	* create and return default KernelApplication instance.
  	* @static
  	* @access public
 	* @return kApplication
 	*/
 	function &Instance()
 	{
 		static $instance = false;
 
 		if(!$instance)
 		{
 			safeDefine('APPLICATION_CLASS', 'kApplication');
 			$class = APPLICATION_CLASS;
 			$instance = new $class();
 			$instance->Application =& $instance;
 		}
 		return $instance;
 	}
 
 	function InitMemcached()
 	{
 		return ;
 
 		$memcached_servers = 'localhost:11211'; // $this->Application->ConfigValue('MemcachedServers');
 
 		if ($memcached_servers && class_exists('Memcache')) {
 			$this->Memcached = new Memcache();
 			$servers = explode(';', $memcached_servers);
 			foreach ($servers as $server) {
 				list ($server, $port) = strpos($server, ':') !== false ? explode(':', $server, 2) : Array ($server, 11211);
 				$this->Memcached->addServer($server, $port);
 			}
 		}
 
 		//try to set something to cache, if not working - set $this->Memcached to null
 	}
 
 	function CacheSet($name, $value, $expiration)
 	{
 		if (isset($this->Memcached)) {
 			return $this->Memcached->set($name, $value, 0, $expiration);
 		}
 		return false;
 	}
 
 	function CacheGet($name)
 	{
 		if (isset($this->Memcached)) {
 			return $this->Memcached->get($name);
 		}
 		return false;
 	}
 
 	/**
 	* Initializes the Application
  	*
  	* @access public
 	* @see kHTTPQuery
 	* @see Session
 	* @see TemplatesCache
 	* @return bool Was Init actually made now or before
 	*/
 	function Init()
 	{
 		if($this->InitDone) return false;
 
 		$this->InitMemcached();
 
 		if (!constOn('SKIP_OUT_COMPRESSION')) {
 			ob_start(); // collect any output from method (other then tags) into buffer
 		}
 
 		if(defined('DEBUG_MODE') && $this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) {
 			$this->Debugger->appendMemoryUsage('Application before Init:');
 		}
 		if (!$this->isDebugMode() && !constOn('DBG_ZEND_PRESENT')) {
 			error_reporting(0);
 			ini_set('display_errors', 0);
 		}
 		if (!constOn('DBG_ZEND_PRESENT')) {
 			$error_handler = set_error_handler( Array (&$this, 'handleError') );
 			if ($error_handler) {
 				// wrap around previous error handler, if any was set
 				$this->errorHandlers[] = $error_handler;
 			}
 		}
 
 		$this->Conn = new kDBConnection(SQL_TYPE, Array(&$this, 'handleSQLError') );
 		$this->Conn->debugMode = $this->isDebugMode();
 		$this->Conn->Connect(SQL_SERVER, SQL_USER, SQL_PASS, SQL_DB);
 
 		$this->Factory = new kFactory();
 		$this->registerDefaultClasses();
 		$this->Phrases = new PhrasesCache();
 		$this->EventManager =& $this->Factory->makeClass('EventManager');
 		$this->Factory->Storage['EventManager'] =& $this->EventManager;
 		$this->RegisterDefaultBuildEvents();
 		$this->SetDefaultConstants();
 
 		if( defined('DEBUG_MODE') && $this->isDebugMode() ) {
 			$this->Debugger->appendTimestamp('Before UnitConfigReader');
 		}
 
 		$this->UnitConfigReader =& $this->recallObject('kUnitConfigReader');
 		$this->UnitConfigReader->scanModules(MODULES_PATH);
 		$this->registerModuleConstants();
 
 		if( defined('DEBUG_MODE') && $this->isDebugMode() ) {
 			$this->Debugger->appendTimestamp('After UnitConfigReader');
 		}
 
 		$rewrite_on = $this->ConfigValue('UseModRewrite');
 		// admin=1 - when front is browsed using admin session
 		$admin_on = getArrayValue($_REQUEST, 'admin') || $this->IsAdmin();
 		define('MOD_REWRITE', $rewrite_on && !$admin_on ? 1 : 0);
 
 		$this->HttpQuery =& $this->recallObject('HTTPQuery');
 
 		if( defined('DEBUG_MODE') && $this->isDebugMode() ) {
 			$this->Debugger->appendTimestamp('Processed HTTPQuery initial');
 		}
 
 		$this->Session =& $this->recallObject('Session');
 
 		if( defined('DEBUG_MODE') && $this->isDebugMode() ) {
 			$this->Debugger->appendTimestamp('Processed Session');
 		}
 
 		if (!$this->RecallVar('UserGroups')) {
 			$user_groups = trim($this->Session->GetField('GroupList'), ',');
 			if (!$user_groups) {
 				$user_groups = $this->ConfigValue('User_GuestGroup');
 			}
 
 			$this->Session->SetField('GroupList', $user_groups);
 			$this->StoreVar('UserGroups', $user_groups);
 		}
 
 		$this->HttpQuery->AfterInit();
 
 		$this->Session->ValidateExpired();
 
 		if( defined('DEBUG_MODE') && $this->isDebugMode() ) {
 			$this->Debugger->appendTimestamp('Processed HTTPQuery AfterInit');
 		}
 
 		$this->LoadCache();
 		$this->InitConfig();
 
 		$this->Phrases->Init('phrases');
 
 		if( defined('DEBUG_MODE') && $this->isDebugMode() ) {
 			$this->Debugger->appendTimestamp('Loaded cache and phrases');
 		}
 
 		$this->UnitConfigReader->AfterConfigRead();
 
 		if( defined('DEBUG_MODE') && $this->isDebugMode() ) {
 			$this->Debugger->appendTimestamp('Processed AfterConfigRead');
 		}
 
 
 		/*// Module items are recalled during url parsing & PhrasesCache is needed already there,
 		// because it's used in their build events. That's why phrases cache initialization is
 		// called from kHTTPQuery in case when mod_rewrite is used
 		if (!$this->RewriteURLs()) {
 			$this->Phrases = new PhrasesCache();
 		}*/
 
 		if ($this->GetVar('m_cat_id') === false) $this->SetVar('m_cat_id', 0);
 		if( !$this->RecallVar('curr_iso') ) $this->StoreVar('curr_iso', $this->GetPrimaryCurrency() );
 
 		$this->SetVar('visits_id', $this->RecallVar('visit_id') );
 
 		$language =& $this->recallObject( 'lang.current', null, Array('live_table' => true) );
 		if (preg_match('/utf-8/', $language->GetDBField('Charset'))) {
 			setlocale(LC_ALL, 'en_US.UTF-8');
 			mb_internal_encoding('UTF-8');
 		}
 
 		$this->ValidateLogin();
 
 		if( defined('DEBUG_MODE') && $this->isDebugMode() ) {
 			$this->Debugger->profileFinish('kernel4_startup');
 		}
 
 		$this->InitDone = true;
 
 		$this->HandleEvent( new kEvent('adm:OnStartup') );
 
 		return true;
 	}
 
 	/**
 	 * Returns module information. Searches module by requested field
 	 *
 	 * @param string $field
 	 * @param mixed $value
 	 * @param string field value to returns, if not specified, then return all fields
 	 * @param string field to return
 	 * @return Array
 	 */
 	function findModule($field, $value, $return_field = null)
 	{
 		$found = false;
 		foreach ($this->ModuleInfo as $module_name => $module_info) {
 			if (strtolower($module_info[$field]) == strtolower($value)) {
 				$found = true;
 				break;
 			}
 		}
 
 		if ($found) {
 			return isset($return_field) ? $module_info[$return_field] : $module_info;
 		}
 
 		return false;
 	}
 
 	function refreshModuleInfo()
 	{
 		if (defined('IS_INSTALL') && IS_INSTALL && !$this->TableFound('Modules')) {
 			$this->registerModuleConstants();
 			return false;
 		}
 
 		$modules_helper =& $this->recallObject('ModulesHelper');
 		/* @var $modules_helper kModulesHelper */
 
 		$sql = 'SELECT *
 				FROM ' . TABLE_PREFIX . 'Modules
 				WHERE Loaded = 1
 				ORDER BY LoadOrder';
 		$this->ModuleInfo = $this->Conn->Query($sql, 'Name');
 
 		$sql = 'SELECT *
 				FROM '.TABLE_PREFIX.'Modules
 				WHERE '.$modules_helper->getWhereClause().'
 				ORDER BY LoadOrder';
 		$this->ModuleInfo = $this->Conn->Query($sql, 'Name');
 
 		$this->registerModuleConstants();
 	}
 
 	/**
 	 * Checks if passed language id if valid and sets it to primary otherwise
 	 *
 	 */
 	function VerifyLanguageId()
 	{
 		$language_id = $this->GetVar('m_lang');
 		if (!$language_id) {
 			$language_id = 'default';
 		}
 		$this->SetVar('lang.current_id', $language_id );
 		$this->SetVar('m_lang', $language_id );
 
 		$lang_mode = $this->GetVar('lang_mode');
 		$this->SetVar('lang_mode', '');
 		$lang =& $this->recallObject('lang.current');
 		if ( !$lang->IsLoaded() || (!$this->Application->IsAdmin() && !$lang->GetDBField('Enabled')) ) {
 			if (!defined('IS_INSTALL')) $this->ApplicationDie('Unknown or disabled language');
 		}
 		$this->SetVar('lang_mode',$lang_mode);
 	}
 
 	/**
 	 * Checks if passed theme id if valid and sets it to primary otherwise
 	 *
 	 */
 	function VerifyThemeId()
 	{
 		if ($this->Application->IsAdmin()) {
 			safeDefine('THEMES_PATH', '/core/admin_templates');
 			return;
 		}
 
 		$path = $this->GetFrontThemePath();
 		if ($path === false) {
 			$this->ApplicationDie('No Primary Theme Selected or Current Theme is Unknown or Disabled');
 		}
 		safeDefine('THEMES_PATH', $path);
 
 		/*$theme_id = $this->GetVar('m_theme');
 		if (!$theme_id) {
 			$theme_id =  $this->GetDefaultThemeId();
 			if (!$theme_id) {
 				if (!defined('IS_INSTALL')) $this->ApplicationDie('No Primary Theme Selected');
 			}
 		}
 		$this->SetVar('m_theme', $theme_id);
 		$this->SetVar('theme.current_id', $theme_id ); // KOSTJA: this is to fool theme' getPassedId
 		$theme =& $this->recallObject('theme.current');
 		if (!$theme->IsLoaded() || !$theme->GetDBField('Enabled')) {
 		if (!defined('IS_INSTALL')) $this->ApplicationDie('Unknown or disabled theme');
 		}
 		safeDefine('THEMES_PATH', '/themes/'.$theme->GetDBField('Name'));*/
 	}
 
 	function GetFrontThemePath($force=0)
 	{
 		static $path=null;
 		if (!$force && isset($path)) return $path;
 
 		$theme_id = $this->GetVar('m_theme');
 		if (!$theme_id) {
 //			$theme_id =  $this->GetDefaultThemeId(1); //1 to force front-end mode!
 			$theme_id = 'default';
 		}
 		$this->SetVar('m_theme', $theme_id);
 		$this->SetVar('theme.current_id', $theme_id ); // KOSTJA: this is to fool theme' getPassedId
 		$theme =& $this->recallObject('theme.current');
 		if (!$theme->IsLoaded() || !$theme->GetDBField('Enabled')) {
 			return false;
 		}
 		$path = '/themes/'.$theme->GetDBField('Name');
 		return $path;
 	}
 
 	function GetDefaultLanguageId()
 	{
 		static $language_id = 0;
 
 		if ($language_id > 0) {
 			return $language_id;
 		}
 
 		$table = $this->getUnitOption('lang', 'TableName');
 		$id_field = $this->getUnitOption('lang', 'IDField');
 
 		$sql = 'SELECT '.$id_field.'
 				FROM '.$table.'
 				WHERE (PrimaryLang = 1) AND (Enabled = 1)';
 		$language_id = $this->Conn->GetOne($sql);
 
 		if (!$language_id && defined('IS_INSTALL') && IS_INSTALL) {
 			$language_id = 1;
 		}
 
 		return $language_id;
 	}
 
 	function GetDefaultThemeId($force_front=0)
 	{
 		static $theme_id = 0;
 
 		if ($theme_id > 0) {
 			return $theme_id;
 		}
 
 		if (constOn('DBG_FORCE_THEME')) {
 			$theme_id = DBG_FORCE_THEME;
 		}
 		elseif (!$force_front && $this->IsAdmin()) {
 			$theme_id = 999;
 		}
 		else {
 			$table = $this->getUnitOption('theme','TableName');
 			$id_field = $this->getUnitOption('theme','IDField');
 			$sql = 'SELECT '.$id_field.'
 					FROM '.$table.'
 					WHERE (PrimaryTheme = 1) AND (Enabled = 1)';
 			$theme_id = $this->Conn->GetOne($sql);
 		}
 
 		return $theme_id;
 	}
 
 	function GetPrimaryCurrency()
 	{
 		if ($this->isModuleEnabled('In-Commerce')) {
 			$table = $this->getUnitOption('curr', 'TableName');
 			return $this->Conn->GetOne('SELECT ISO FROM '.$table.' WHERE IsPrimary = 1');
 		}
 		else {
 			return 'USD';
 		}
 	}
 
 	/**
 	* Registers default classes such as ItemController, GridController and LoginController
 	*
 	* Called automatically while initializing Application
 	* @access private
 	* @return void
 	*/
 	function RegisterDefaultClasses()
 	{
 		$this->registerClass('kTempTablesHandler', KERNEL_PATH.'/utility/temp_handler.php');
 		$this->registerClass('kEventManager', KERNEL_PATH.'/event_manager.php', 'EventManager');
 		$this->registerClass('kUnitConfigReader', KERNEL_PATH.'/utility/unit_config_reader.php');
 
 		$this->registerClass('kArray', KERNEL_PATH.'/utility/params.php');
 		$this->registerClass('Params', KERNEL_PATH.'/utility/params.php');
 		$this->registerClass('kHelper', KERNEL_PATH.'/kbase.php');
 
 		$this->registerClass('kCache', KERNEL_PATH.'/utility/cache.php', 'Cache', Array('Params'));
 		$this->registerClass('kHTTPQuery', KERNEL_PATH.'/utility/http_query.php', 'HTTPQuery', Array('Params') );
 
 		$this->registerClass('Session', KERNEL_PATH.'/session/session.php');
 		$this->registerClass('SessionStorage', KERNEL_PATH.'/session/session.php');
 
 
 
 		$this->registerClass('Params', KERNEL_PATH.'/utility/params.php', 'kActions');
 
 		$this->registerClass('kMultipleFilter', KERNEL_PATH.'/utility/filters.php');
 		$this->registerClass('kDBList', KERNEL_PATH.'/db/dblist.php');
 		$this->registerClass('kDBItem', KERNEL_PATH.'/db/dbitem.php');
 		$this->registerClass('kDBEventHandler', KERNEL_PATH.'/db/db_event_handler.php');
 
 		$this->registerClass('kTagProcessor', KERNEL_PATH.'/processors/tag_processor.php');
 		$this->registerClass('kMainTagProcessor', KERNEL_PATH.'/processors/main_processor.php','m_TagProcessor', 'kTagProcessor');
 		$this->registerClass('kDBTagProcessor', KERNEL_PATH.'/db/db_tag_processor.php', null, 'kTagProcessor');
 
 		$this->registerClass('TemplatesCache', KERNEL_PATH.'/parser/template.php',null, 'kDBTagProcessor');
 		$this->registerClass('Template', KERNEL_PATH.'/parser/template.php');
 		$this->registerClass('TemplateParser', KERNEL_PATH.'/parser/template_parser.php',null, 'kDBTagProcessor');
 		$this->registerClass('NParser', KERNEL_PATH.'/nparser/nparser.php');
 
 		$this->registerClass('kEmailSendingHelper', KERNEL_PATH.'/utility/email_send.php', 'EmailSender', Array('kHelper'));
 		$this->registerClass('kSocket', KERNEL_PATH.'/utility/socket.php', 'Socket');
 
 		if (file_exists(MODULES_PATH.'/in-commerce/units/currencies/currency_rates.php')) {
 			$this->registerClass('kCurrencyRates', MODULES_PATH.'/in-commerce/units/currencies/currency_rates.php');
 		}
 
 		$this->registerClass('FCKeditor', FULL_PATH.'/admin/editor/cmseditor/fckeditor.php'); // need this?
 
 		/* Moved from MyApplication */
 
 		$this->registerClass('Inp1Parser',KERNEL_PATH.'/../units/general/inp1_parser.php','Inp1Parser');
 
 		$this->registerClass('InpSession',KERNEL_PATH.'/../units/general/inp_ses_storage.php','Session');
 		$this->registerClass('InpSessionStorage',KERNEL_PATH.'/../units/general/inp_ses_storage.php','SessionStorage');
 
 		$this->registerClass('kCatDBItem',KERNEL_PATH.'/../units/general/cat_dbitem.php');
 		$this->registerClass('kCatDBItemExportHelper',KERNEL_PATH.'/../units/general/cat_dbitem_export.php', 'CatItemExportHelper');
 		$this->registerClass('kCatDBList',KERNEL_PATH.'/../units/general/cat_dblist.php');
 		$this->registerClass('kCatDBEventHandler',KERNEL_PATH.'/../units/general/cat_event_handler.php');
 		$this->registerClass('kCatDBTagProcessor',KERNEL_PATH.'/../units/general/cat_tag_processor.php');
 
 		// Do not move to config - this helper is used before configs are read
 		$this->registerClass('kModulesHelper', KERNEL_PATH.'/../units/general/helpers/modules.php', 'ModulesHelper');
 
 		/* End moved */
 
 	}
 
 	function RegisterDefaultBuildEvents()
 	{
 		$event_manager =& $this->recallObject('EventManager');
 		$event_manager->registerBuildEvent('kTempTablesHandler', 'OnTempHandlerBuild');
 	}
 
 	/**
 	 * Returns item's filename that corresponds id passed. If possible, then get it from cache
 	 *
 	 * @param string $prefix
 	 * @param int $id
 	 * @return string
 	 */
 	function getFilename($prefix, $id, $category_id=null)
 	{
 		$filename = $this->getCache('filenames',  $prefix.'_'.$id);
 		if ($filename === false) {
 			$table = $this->getUnitOption($prefix, 'TableName');
 			$id_field = $this->getUnitOption($prefix, 'IDField');
 
 			if ($prefix == 'c') {
 				if(!$id) {
 					$this->setCache('filenames', $prefix.'_'.$id, '');
 					return '';
 				}
 
 				// this allows to save 2 sql queries for each category
 				$sql = 'SELECT NamedParentPath, CachedTemplate, TreeLeft, TreeRight
 						FROM '.$table.'
 						WHERE '.$id_field.' = '.$this->Conn->qstr($id);
 				$category_data = $this->Conn->GetRow($sql);
 
 				// only direct links to category pages work (symlinks, container pages and so on won't work)
 				$filename = $category_data['NamedParentPath'];
 				$this->setCache('category_templates', $id, $filename);
 				$this->setCache('category_designs', $id, ltrim($category_data['CachedTemplate'], '/'));
 				$this->setCache('category_tree', $id, $category_data['TreeLeft'] . ';' . $category_data['TreeRight']);
 			}
 			else {
 				$resource_id = $this->Conn->GetOne('SELECT ResourceId FROM '.$table.' WHERE '.$id_field.' = '.$this->Conn->qstr($id));
 				if (is_null($category_id)) $category_id = $this->GetVar('m_cat_id');
 				$sql = 'SELECT Filename FROM '.TABLE_PREFIX.'CategoryItems WHERE ItemResourceId = '.$resource_id.' AND CategoryId = '.$category_id;
 				$filename = $this->Conn->GetOne($sql);
 
 				/*if (!$filename) {
 					$sql = 'SELECT Filename FROM '.TABLE_PREFIX.'CategoryItems WHERE ItemResourceId = '.$resource_id.' AND PrimaryCat = 1';
 					$filename = $this->Conn->GetOne($sql);
 				}*/
 
 				/*$sql = 'SELECT Filename
 						FROM '.$table.'
 						WHERE '.$id_field.' = '.$this->Conn->qstr($id);
 				$filename = $this->Conn->GetOne($sql);*/
 			}
 			$this->setCache('filenames', $prefix.'_'.$id, $filename);
 		}
 		return $filename;
 	}
 
 
 	/**
 	 * Adds new value to cache $cache_name and identified by key $key
 	 *
 	 * @param string $cache_name cache name
 	 * @param int $key key name to add to cache
 	 * @param mixed $value value of chached record
 	 */
 	function setCache($cache_name, $key, $value, $expiration=3600)
 	{
 		$cache =& $this->recallObject('Cache');
 		/* @var $cache kCache */
 
 		return $cache->setCache($cache_name, $key, $value, $expiration);
 	}
 
 	/**
 	 * Returns cached $key value from cache named $cache_name
 	 *
 	 * @param string $cache_name cache name
 	 * @param int $key key name from cache
 	 * @return mixed
 	 */
 	function getCache($cache_name, $key)
 	{
 		$cache =& $this->recallObject('Cache');
 		return $cache->getCache($cache_name, $key);
 	}
 
 	/**
 	* Defines default constants if it's not defined before - in config.php
 	*
 	* @access private
 	*/
 	function SetDefaultConstants() // it's defined in startup.php - can be removed??
 	{
 		safeDefine('SERVER_NAME', $_SERVER['HTTP_HOST']);
 	}
 
 	/**
 	 * Registers each module specific constants if any found
 	 *
 	 */
 	function registerModuleConstants()
 	{
 		if (file_exists(KERNEL_PATH.'/constants.php')) {
 			k4_include_once(KERNEL_PATH.'/constants.php');
 		}
 
 		if (!$this->ModuleInfo) return false;
 		foreach($this->ModuleInfo as $module_name => $module_info)
 		{
 			$module_path = '/'.$module_info['Path'];
 			$contants_file = FULL_PATH.$module_path.'constants.php';
 			if( file_exists($contants_file) ) k4_include_once($contants_file);
 		}
 		return true;
 	}
 
 	function ProcessRequest()
 	{
 		$event_manager =& $this->recallObject('EventManager');
 		/* @var $event_manager kEventManager */
 
 		if($this->isDebugMode() && constOn('DBG_SHOW_HTTPQUERY')) {
 			$this->Debugger->appendHTML('HTTPQuery:');
 			$this->Debugger->dumpVars($this->HttpQuery->_Params);
 		}
 
 		$event_manager->ProcessRequest();
 		$event_manager->RunRegularEvents(reBEFORE);
 		$this->RequestProcessed =  true;
 	}
 
 	/**
 	* Actually runs the parser against current template and stores parsing result
 	*
 	* This method gets t variable passed to the script, loads the template given in t variable and
 	* parses it. The result is store in {@link $this->HTML} property.
 	* @access public
 	* @return void
 	*/
 	function Run()
 	{
 		if($this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) {
 			$this->Debugger->appendMemoryUsage('Application before Run:');
 		}
 
 		if ($this->IsAdmin()) {
 			// for permission checking in events & templates
 			$this->LinkVar('module');				// for common configuration templates
 			$this->LinkVar('module_key');			// for common search templates
 			$this->LinkVar('section');				// for common configuration templates
 
 			if ($this->GetVar('m_opener') == 'p') {
 				$this->LinkVar('main_prefix');		// window prefix, that opened selector
 				$this->LinkVar('dst_field');		// field to set value choosed in selector
 //				$this->LinkVar('return_template');	// template to go, when something was coosen from popup (from finalizePopup)
 //				$this->LinkVar('return_m');			// main env part to restore after popup will be closed (from finalizePopup)
 			}
 
 			if ($this->GetVar('ajax') == 'yes' && !$this->GetVar('debug_ajax')) {
 				// hide debug output from ajax requests automatically
 				define('DBG_SKIP_REPORTING', 1);
 			}
 		}
 		elseif ($this->GetVar('admin')) {
 			// viewing front-end through admin's frame
 			$admin_session =& $this->Application->recallObject('Session.admin');
 			$user = (int)$admin_session->RecallVar('user_id'); // in case, when no valid admin session found
 			$perm_helper =& $this->recallObject('PermissionsHelper');
 			/* @var $perm_helper kPermissionsHelper */
 
 			if ($perm_helper->CheckUserPermission($user, 'CATEGORY.MODIFY', 0, 0)) {
 				// user can edit cms blocks
 				$editing_mode = $this->GetVar('editing_mode');
-				define('EDITING_MODE', $editing_mode ? $editing_mode : EDITING_MODE_CMS);
+				define('EDITING_MODE', $editing_mode ? $editing_mode : EDITING_MODE_BROWSE);
+				$this->Phrases->setPhraseEditing();
 			}
 		}
 
 		safeDefine('EDITING_MODE', ''); // user can't edit anything
 
 		if (!$this->RequestProcessed) $this->ProcessRequest();
 
 		$this->InitParser();
 		$t = $this->GetVar('t');
 
 		if (!$this->TemplatesCache->TemplateExists($t) && !$this->IsAdmin()) {
 			$cms_handler =& $this->recallObject('st_EventHandler');
 			/* @var $cms_handler CategoriesEventHandler */
 
 			$t = ltrim($cms_handler->GetDesignTemplate(), '/');
 
 			if ($this->isDebugMode()) {
 				$this->Debugger->appendHTML('<strong>Design Template</strong>: ' . $t . '; <strong>CategoryID</strong>: ' . $this->GetVar('m_cat_id'));
 			}
 		}
 		/*else {
 			$cms_handler->SetCatByTemplate();
 		}*/
 
 		if($this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) {
 			$this->Debugger->appendMemoryUsage('Application before Parsing:');
 		}
 
 		if (defined('NPARSER') && 'NPARSER') {
 			$this->HTML = $this->NParser->Run( $t );
 		}
 		else {
 			$this->HTML = $this->Parser->ParseTemplate( $t );
 		}
 
 		if ($this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) {
 			$this->Debugger->appendMemoryUsage('Application after Parsing:');
 		}
 	}
 
 	function InitParser($theme_name = false)
 	{
 		if (defined('NPARSER') && 'NPARSER') {
 			if( !is_object($this->NParser) ) {
 				$this->NParser =& $this->recallObject('NParser');
 				$this->TemplatesCache =& $this->recallObject('TemplatesCache');
 
 				// can be removed in future
 //				$this->Parser =& $this->recallObject('TemplateParser');
 				$this->Parser =& $this->NParser;
 			}
 		}
 		else {
 			if( !is_object($this->Parser) ) {
 				$this->Parser =& $this->recallObject('TemplateParser');
 				$this->TemplatesCache =& $this->recallObject('TemplatesCache');
 			}
 		}
 
 		$this->TemplatesCache->forceThemeName = $theme_name;
 	}
 
 	/**
 	* Send the parser results to browser
 	*
 	* Actually send everything stored in {@link $this->HTML}, to the browser by echoing it.
 	* @access public
 	* @return void
 	*/
 	function Done()
 	{
 		$this->HandleEvent( new kEvent('adm:OnBeforeShutdown') );
 		if ($this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) {
 			$this->Debugger->appendMemoryUsage('Application before Done:');
 		}
 
 		if ($this->isDebugMode()) {
 			$this->EventManager->RunRegularEvents(reAFTER);
 			$this->Session->SaveData();
 
 			if (constOn('DBG_CACHE')) {
 				$cache =& $this->recallObject('Cache');
 				$cache->printStatistics();
 			}
 
 			$this->HTML = ob_get_clean() . $this->HTML . $this->Debugger->printReport(true);
 		}
 		else {
 			$this->HTML = ob_get_clean().$this->HTML;
 		}
 
 		if ($this->UseOutputCompression()) {
 			header('Content-Encoding: gzip');
 			$compression_level = $this->ConfigValue('OutputCompressionLevel');
 			if ($compression_level < 0 || $compression_level > 9) $compression_level = 7;
 			echo gzencode($this->HTML, $compression_level);
 		}
 		else {
 			echo $this->HTML;
 		}
 
 		$this->UpdateCache();
 
 		flush();
 		if (!$this->isDebugMode()) {
 			$this->EventManager->RunRegularEvents(reAFTER);
 			$this->Session->SaveData();
 		}
 
 		if (defined('DBG_CAPTURE_STATISTICS') && DBG_CAPTURE_STATISTICS && !$this->IsAdmin()) {
 			$this->_storeStatistics();
 		}
 	}
 
 	/**
 	 * Stores script execution statistics to database
 	 *
 	 */
 	function _storeStatistics()
 	{
 		global $start;
 
 		$script_time = getmicrotime() - $start;
 		$query_statistics = $this->Conn->getQueryStatistics(); // time & count
 
 		$sql = 'SELECT *
 				FROM ' . TABLE_PREFIX . 'StatisticsCapture
 				WHERE TemplateName = "' . $this->GetVar('t') . '"';
 		$data = $this->Conn->GetRow($sql);
 
 		if ($data) {
 			$this->_updateAverageStatistics($data, 'ScriptTime', $script_time);
 			$this->_updateAverageStatistics($data, 'SqlTime', $query_statistics['time']);
 			$this->_updateAverageStatistics($data, 'SqlCount', $query_statistics['count']);
 
 			$data['Hits']++;
 			$data['LastHit'] = adodb_mktime();
 
 			$this->Conn->doUpdate($data, TABLE_PREFIX . 'StatisticsCapture', 'StatisticsId = ' . $data['StatisticsId']);
 		}
 		else {
 			$data['ScriptTimeMin'] = $data['ScriptTimeAvg'] = $data['ScriptTimeMax'] = $script_time;
 			$data['SqlTimeMin'] = $data['SqlTimeAvg'] = $data['SqlTimeMax'] = $query_statistics['time'];
 			$data['SqlCountMin'] = $data['SqlCountAvg'] = $data['SqlCountMax'] = $query_statistics['count'];
 			$data['TemplateName'] = $this->GetVar('t');
 			$data['Hits'] = 1;
 			$data['LastHit'] = adodb_mktime();
 			$this->Conn->doInsert($data, TABLE_PREFIX . 'StatisticsCapture');
 		}
 	}
 
 	/**
 	 * Calculates average time for statistics
 	 *
 	 * @param Array $data
 	 * @param string $field_prefix
 	 * @param float $current_value
 	 */
 	function _updateAverageStatistics(&$data, $field_prefix, $current_value)
 	{
 		$data[$field_prefix . 'Avg'] = (($data['Hits'] * $data[$field_prefix . 'Avg']) + $current_value) / ($data['Hits'] + 1);
 
 		if ($current_value < $data[$field_prefix . 'Min']) {
 			$data[$field_prefix . 'Min'] = $current_value;
 		}
 
 		if ($current_value > $data[$field_prefix . 'Max']) {
 			$data[$field_prefix . 'Max'] = $current_value;
 		}
 	}
 
 	function logSlowQuery($slow_sql, $time)
 	{
 		$query_crc = crc32($slow_sql);
 
 		$sql = 'SELECT *
 				FROM ' . TABLE_PREFIX . 'SlowSqlCapture
 				WHERE QueryCrc = ' . $query_crc;
 		$data = $this->Conn->Query($sql, null, true);
 
 		if ($data) {
 			$this->_updateAverageStatistics($data, 'Time', $time);
 
 			$template_names = explode(',', $data['TemplateNames']);
 			array_push($template_names, $this->GetVar('t'));
 			$data['TemplateNames'] = implode(',', array_unique($template_names));
 
 			$data['Hits']++;
 			$data['LastHit'] = adodb_mktime();
 
 			$this->Conn->doUpdate($data, TABLE_PREFIX . 'SlowSqlCapture', 'CaptureId = ' . $data['CaptureId']);
 		}
 		else {
 			$data['TimeMin'] = $data['TimeAvg'] = $data['TimeMax'] = $time;
 			$data['SqlQuery'] = $slow_sql;
 			$data['QueryCrc'] = $query_crc;
 			$data['TemplateNames'] = $this->GetVar('t');
 			$data['Hits'] = 1;
 			$data['LastHit'] = adodb_mktime();
 
 			$this->Conn->doInsert($data, TABLE_PREFIX . 'SlowSqlCapture');
 		}
 	}
 
 	/**
 	 * Checks if output compression options is available
 	 *
 	 * @return string
 	 */
 	function UseOutputCompression()
 	{
 		if (constOn('IS_INSTALL') || constOn('DBG_ZEND_PRESENT') || constOn('SKIP_OUT_COMPRESSION')) return false;
 		return $this->ConfigValue('UseOutputCompression') && function_exists('gzencode') && strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip');
 	}
 
 	//	Facade
 
 	/**
 	* Returns current session id (SID)
 	* @access public
 	* @return longint
 	*/
 	function GetSID()
 	{
 		$session =& $this->recallObject('Session');
 		return $session->GetID();
 	}
 
 	function DestroySession()
 	{
 		$session =& $this->recallObject('Session');
 		$session->Destroy();
 	}
 
 	/**
 	* Returns variable passed to the script as GET/POST/COOKIE
 	*
 	* @access public
 	* @param string $name Name of variable to retrieve
 	* @param int $default default value returned in case if varible not present
 	* @return mixed
 	*/
 	function GetVar($name, $default = false)
 	{
 		return isset($this->HttpQuery->_Params[$name]) ? $this->HttpQuery->_Params[$name] : $default;
 	}
 
 	/**
 	* Returns ALL variables passed to the script as GET/POST/COOKIE
 	*
 	* @access public
 	* @return array
 	*/
 	function GetVars()
 	{
 		return $this->HttpQuery->GetParams();
 	}
 
 	/**
 	* Set the variable 'as it was passed to the script through GET/POST/COOKIE'
 	*
 	* This could be useful to set the variable when you know that
 	* other objects would relay on variable passed from GET/POST/COOKIE
 	* or you could use SetVar() / GetVar() pairs to pass the values between different objects.<br>
 	*
 	* This method is formerly known as $this->Session->SetProperty.
 	* @param string $var Variable name to set
 	* @param mixed $val Variable value
 	* @access public
 	* @return void
 	*/
 	function SetVar($var,$val)
 	{
 		return $this->HttpQuery->Set($var, $val);
 	}
 
 	/**
 	 * Deletes kHTTPQuery variable
 	 *
 	 * @param string $var
 	 * @todo think about method name
 	 */
 	function DeleteVar($var)
 	{
 		return $this->HttpQuery->Remove($var);
 	}
 
 	/**
 	 * Deletes Session variable
 	 *
 	 * @param string $var
 	 */
 	function RemoveVar($var)
 	{
 		return $this->Session->RemoveVar($var);
 	}
 
 	function RemovePersistentVar($var)
 	{
 		return $this->Session->RemovePersistentVar($var);
 	}
 
 	/**
 	 * Restores Session variable to it's db version
 	 *
 	 * @param string $var
 	 */
 	function RestoreVar($var)
 	{
 		return $this->Session->RestoreVar($var);
 	}
 
 	/**
 	* Returns session variable value
 	*
 	* Return value of $var variable stored in Session. An optional default value could be passed as second parameter.
 	*
 	* @see SimpleSession
 	* @access public
 	* @param string $var Variable name
 	* @param mixed $default Default value to return if no $var variable found in session
 	* @return mixed
 	*/
 	function RecallVar($var,$default=false)
 	{
 		return $this->Session->RecallVar($var,$default);
 	}
 
 	function RecallPersistentVar($var, $default = false)
 	{
 		return $this->Session->RecallPersistentVar($var, $default);
 	}
 
 	/**
 	* Stores variable $val in session under name $var
 	*
 	* Use this method to store variable in session. Later this variable could be recalled.
 	* @see RecallVar
 	* @access public
 	* @param string $var Variable name
 	* @param mixed $val Variable value
 	*/
 	function StoreVar($var, $val, $optional = false)
 	{
 		$session =& $this->recallObject('Session');
 		$this->Session->StoreVar($var, $val, $optional);
 	}
 
 	function StorePersistentVar($var, $val)
 	{
 		$this->Session->StorePersistentVar($var, $val);
 	}
 
 	function StoreVarDefault($var, $val, $optional=false)
 	{
 		$session =& $this->recallObject('Session');
 		$this->Session->StoreVarDefault($var, $val, $optional);
 	}
 
 	/**
 	* Links HTTP Query variable with session variable
 	*
 	* If variable $var is passed in HTTP Query it is stored in session for later use. If it's not passed it's recalled from session.
 	* This method could be used for making sure that GetVar will return query or session value for given
 	* variable, when query variable should overwrite session (and be stored there for later use).<br>
 	* This could be used for passing item's ID into popup with multiple tab -
 	* in popup script you just need to call LinkVar('id', 'current_id') before first use of GetVar('id').
 	* After that you can be sure that GetVar('id') will return passed id or id passed earlier and stored in session
 	* @access public
 	* @param string $var HTTP Query (GPC) variable name
 	* @param mixed $ses_var Session variable name
 	* @param mixed $default Default variable value
 	*/
 	function LinkVar($var, $ses_var = null, $default = '', $optional = false)
 	{
 		if (!isset($ses_var)) $ses_var = $var;
 		if ($this->GetVar($var) !== false) {
 			$this->StoreVar($ses_var, $this->GetVar($var), $optional);
 		}
 		else {
 			$this->SetVar($var, $this->RecallVar($ses_var, $default));
 		}
 	}
 
 	/**
 	* Returns variable from HTTP Query, or from session if not passed in HTTP Query
 	*
 	* The same as LinkVar, but also returns the variable value taken from HTTP Query if passed, or from session if not passed.
 	* Returns the default value if variable does not exist in session and was not passed in HTTP Query
 	*
 	* @see LinkVar
 	* @access public
 	* @param string $var HTTP Query (GPC) variable name
 	* @param mixed $ses_var Session variable name
 	* @param mixed $default Default variable value
 	* @return mixed
 	*/
 	function GetLinkedVar($var, $ses_var = null, $default = '')
 	{
 		$this->LinkVar($var, $ses_var, $default);
 		return $this->GetVar($var);
 	}
 
 	function AddBlock($name, $tpl)
 	{
 		$this->cache[$name] = $tpl;
 	}
 
 	/* Seems to be not used anywhere... /Kostja
 
 	function SetTemplateBody($title,$body)
 	{
 		$templates_cache =& $this->recallObject('TemplatesCache');
 		$templates_cache->SetTemplateBody($title,$body);
 	}*/
 
 	function ProcessTag($tag_data)
 	{
 		$a_tag = new Tag($tag_data,$this->Parser);
 		return $a_tag->DoProcessTag();
 	}
 
 	function ProcessParsedTag($prefix, $tag, $params)
 	{
 		if (defined('NPARSER') && NPARSER) {
 			$p = $this->Parser->GetProcessor($prefix);
 			return $p->ProcessParsedTag($tag, $params, $prefix);
 		}
 
 		$a_tag = new Tag('',$this->Parser);
 		$a_tag->Tag = $tag;
 		$tmp=$this->Application->processPrefix($prefix);
 		$a_tag->Processor = $tmp['prefix'];
 		$a_tag->Special = $tmp['special'];
 		$a_tag->NamedParams = $params;
 		return $a_tag->DoProcessTag();
 	}
 
 	/**
 	* Return ADODB Connection object
 	*
 	* Returns ADODB Connection object already connected to the project database, configurable in config.php
 	* @access public
 	* @return kDBConnection
 	*/
 	function &GetADODBConnection()
 	{
 		return $this->Conn;
 	}
 
 	/**
 	 * Allows to parse given block name or include template
 	 *
 	 * @param Array $params Parameters to pass to block/template. Reserved parameter "name" used to specify block/template name.
 	 * @param Array $pass_params Forces to pass current parser params to this block/template. Use with cauntion, because you can accidently pass "block_no_data" parameter.
 	 * @param bool $as_template
 	 * @return string
 	 */
 	function ParseBlock($params, $pass_params = 0, $as_template = false)
 	{
 		if (substr($params['name'], 0, 5) == 'html:') return substr($params['name'], 6);
 		return $this->Parser->ParseBlock($params, $pass_params, $as_template);
 	}
 
 	/**
 	 * Returns index file, that could be passed as parameter to method, as parameter to tag and as constant or not passed at all
 	 *
 	 * @param string $prefix
 	 * @param string $index_file
 	 * @param Array $params
 	 * @return string
 	 */
 	function getIndexFile($prefix, $index_file, &$params)
 	{
 		if (isset($params['index_file'])) {
 			$index_file = $params['index_file'];
 			unset($params['index_file']);
 			return $index_file;
 		}
 
 		if (isset($index_file)) {
 			return $index_file;
 		}
 
 		if (defined('INDEX_FILE')) {
 			return INDEX_FILE;
 		}
 
 		$cut_prefix = trim(BASE_PATH, '/').'/'.trim($prefix, '/');
 		return trim(preg_replace('/'.preg_quote($cut_prefix, '/').'(.*)/', '\\1', $_SERVER['PHP_SELF']), '/');
 	}
 
 	/**
 	* Return href for template
 	*
 	* @access public
 	* @param string $t Template path
 	* @var string $prefix index.php prefix - could be blank, 'admin'
 	*/
 	function HREF($t, $prefix='', $params=null, $index_file=null)
 	{
 		if(!$t) $t = $this->GetVar('t'); // moved from kMainTagProcessor->T()
 
 		$t = preg_replace('/^Content\//i', '', $t);
 
 
 		/*if ($this->GetVar('skip_last_template')) {
 			$params['opener'] = 'p';
 			$this->SetVar('m_opener', 'p');
 		}
 
 		if ($t == 'incs/close_popup') {
 			// because this template closes the popup and we don't need popup mark here anymore
 			$params['m_opener'] = 's';
 		}*/
 
 		if( substr($t, -4) == '.tpl' ) $t = substr($t, 0, strlen($t) - 4 );
 
 		if ( $this->IsAdmin() && $prefix == '') $prefix = ADMIN_DIRECTORY;
 		if ( $this->IsAdmin() && $prefix == '_FRONT_END_') $prefix = '';
 
 		$index_file = $this->getIndexFile($prefix, $index_file, $params);
 
 		if (isset($params['_auto_prefix_'])) {
 			unset($params['_auto_prefix_']); // this is parser-related param, do not need to pass it here
 		}
 
 		$ssl = isset($params['__SSL__']) ? $params['__SSL__'] : null;
 		if ($ssl !== null) {
 			$session =& $this->recallObject('Session');
 			$cookie_url = trim($session->CookieDomain.$session->CookiePath, '/.');
 			if ($ssl) {
 				$target_url = defined('ADMIN') && ADMIN ? $this->ConfigValue('AdminSSL_URL') : false;
 				if (!$target_url) {
 					$target_url = $this->ConfigValue('SSL_URL');
 				}
 			}
 			else {
 				$target_url = 'http://'.DOMAIN.$this->ConfigValue('Site_Path');
 			}
 
 			if (!preg_match('#'.preg_quote($cookie_url).'#', $target_url)) {
 				$session->SetMode(smGET_ONLY);
 			}
 		}
 
 		if (isset($params['opener']) && $params['opener'] == 'u') {
 			$wid = $this->Application->GetVar('m_wid');
 			$stack_name = rtrim('opener_stack_'.$wid, '_');
 			$opener_stack = $this->RecallVar($stack_name);
 
 			if ($opener_stack && $opener_stack != serialize(Array())) {
 				$opener_stack = unserialize($opener_stack);
 				list($index_file, $env) = explode('|', $opener_stack[count($opener_stack) - 1]);
 				$ret = $this->BaseURL($prefix, $ssl).$index_file.'?'.ENV_VAR_NAME.'='.$env;
 				if ( getArrayValue($params,'escape') ) $ret = addslashes($ret);
 
 				if (isset($params['m_opener']) && $params['m_opener'] == 'u') {
 					array_pop($opener_stack);
 					if (!$opener_stack) {
 						$this->RemoveVar($stack_name);
 						// remove popups last templates, because popup is closing now
 						$this->RemoveVar('last_template_'.$wid);
 						$this->RemoveVar('last_template_popup_'.$wid);
 
 						// don't save popups last templates again :)
 						$this->SetVar('skip_last_template', 1);
 					}
 					else {
 						$this->StoreVar($stack_name, serialize($opener_stack));
 					}
 
 					/*// store window relations
 					$window_relations = $this->Application->RecallVar('window_relations');
 					$window_relations = $window_relations ? unserialize($window_relations) : Array ();
 					if (array_key_exists($wid, $window_relations)) {
 						unset($window_relations[$wid]);
 						$this->Application->StoreVar('window_relations', serialize($window_relations));
 					}*/
 				}
 				return $ret;
 			}
 			else {
 				//define('DBG_REDIRECT', 1);
 				$t = $this->GetVar('t');
 			}
 		}
 
 		$pass = isset($params['pass']) ? $params['pass'] : '';
 		$pass_events = isset($params['pass_events']) ? $params['pass_events'] : false; // pass events with url
 
 		$map_link = '';
 		if( isset($params['anchor']) )
 		{
 			$map_link = '#'.$params['anchor'];
 			unset($params['anchor']);
 		}
 
 		if ( isset($params['no_amp']) )
 		{
 			$params['__URLENCODE__'] = $params['no_amp'];
 			unset($params['no_amp']);
 		}
 
 		$no_rewrite = false;
 		if( isset($params['__NO_REWRITE__']) )
 		{
 			$no_rewrite = true;
 			unset($params['__NO_REWRITE__']);
 		}
 
 		$force_rewrite = false;
 		if( isset($params['__MOD_REWRITE__']) )
 		{
 			$force_rewrite = true;
 			unset($params['__MOD_REWRITE__']);
 		}
 
 		$force_no_sid = false;
 		if( isset($params['__NO_SID__']) )
 		{
 			$force_no_sid = true;
 			unset($params['__NO_SID__']);
 		}
 
 		// append pass through variables to each link to be build
 		// $params = array_merge_recursive2($this->getPassThroughVariables($params), $params);
 		$params = array_merge($this->getPassThroughVariables($params), $params);
 
 		if ($force_rewrite || ($this->RewriteURLs($ssl) && !$no_rewrite)) {
 			static $rewrite_listeners_done = false;
 
 			if (!$rewrite_listeners_done) {
 				$mod_rewrite_helper =& $this->recallObject('ModRewriteHelper');
 				/* @var $mod_rewrite_helper kModRewriteHelper */
 
 				$mod_rewrite_helper->initRewriteListeners();
 
 				$rewrite_listeners_done = true;
 			}
 
 			$session =& $this->recallObject('Session');
 
 			if ($session->NeedQueryString() && !$force_no_sid) {
 				$params['sid'] = $this->GetSID();
 			}
 
 			$url = $this->BuildEnv_NEW($t, $params, $pass, $pass_events);
 			$ret = $this->BaseURL($prefix, $ssl).$url.$map_link;
 		}
 		else {
 			unset($params['pass_category']); // we don't need to pass it when mod_rewrite is off
 			$env = $this->BuildEnv($t, $params, $pass, $pass_events);
 			$ret = $this->BaseURL($prefix, $ssl).$index_file.'?'.$env.$map_link;
 		}
 
 		return $ret;
 	}
 
 	/**
 	 * Returns variables with values that should be passed throught with this link + variable list
 	 *
 	 * @param Array $params
 	 * @return Array
 	 */
 	function getPassThroughVariables(&$params)
 	{
 		static $cached_pass_through = null;
 
 		if (isset($params['no_pass_through']) && $params['no_pass_through']) {
 			unset($params['no_pass_through']);
 			return Array();
 		}
 
 		// because pass through is not changed during script run, then we can cache it
 		if (is_null($cached_pass_through)) {
 
 			$cached_pass_through = Array();
 			$pass_through = $this->Application->GetVar('pass_through');
 
 			if ($pass_through) {
 				// names of variables to pass to each link
 				$cached_pass_through['pass_through'] = $pass_through;
 				$pass_through = explode(',', $pass_through);
 				foreach ($pass_through as $pass_through_var) {
 					$cached_pass_through[$pass_through_var] = $this->Application->GetVar($pass_through_var);
 				}
 			}
 
 		}
 
 		return $cached_pass_through;
 	}
 
 
 	/**
 	 * Returns sorted array of passed prefixes (to build url from)
 	 *
 	 * @param string $pass
 	 * @return Array
 	 */
 	function getPassInfo($pass = 'all')
 	{
 		if (!$pass) $pass = 'all';
 		$pass = trim(
 				preg_replace(
 					'/(?<=,|\\A)all(?=,|\\z)/',
 					trim($this->GetVar('passed'), ','),
 					trim($pass, ',')
 				),
 		 ',');
 
 		if (!$pass) {
 			return Array();
 		}
 
 		$pass_info = array_unique( explode(',', $pass) ); // array( prefix[.special], prefix[.special] ...
 
 		// we need to keep that sorting despite the sorting below, because this sorts prefixes with same priority by name
 		sort($pass_info, SORT_STRING); // to be prefix1,prefix1.special1,prefix1.special2,prefix3.specialX
 
 		foreach ($pass_info as $prefix) {
 			list($prefix_only) = explode('.', $prefix, 1);
 			$sorted[$prefix] = $this->getUnitOption($prefix_only, 'RewritePriority', 0);
 		}
 
 		arsort($sorted);
 		$pass_info = array_keys($sorted);
 
 		// ensure that "m" prefix is at the beginning
 		$main_index = array_search('m', $pass_info);
 		if ($main_index !== false) {
 			unset($pass_info[$main_index]);
 			array_unshift($pass_info, 'm');
 		}
 		return $pass_info;
 	}
 
 	function BuildEnv_NEW($t, $params, $pass='all', $pass_events = false)
 	{
 //		$session =& $this->recallObject('Session');
 		$force_admin = getArrayValue($params,'admin') || $this->GetVar('admin');
 
 //		if($force_admin) $sid = $this->GetSID();
 
 		$ret = '';
 		$env = '';
 
 		$encode = false;
 
 		if (isset($params['__URLENCODE__'])) {
 			$encode = $params['__URLENCODE__'];
 			unset($params['__URLENCODE__']);
 		}
 
 		if (isset($params['__SSL__'])) {
 			unset($params['__SSL__']);
 		}
 
 		$catalog_item_found = false;
 		$pass_info = $this->getPassInfo($pass);
 
 		if ($pass_info) {
 			if ($pass_info[0] == 'm') {
 				array_shift($pass_info);
 			}
 
 			$inject_parts = Array (); // url parts for beginning of url
 			$params['t'] = $t; // make template available for rewrite listeners
 			$params['pass_template'] = true; // by default we keep given template in resulting url
 
 			if (!array_key_exists('pass_category', $params)) {
 				$params['pass_category'] = false; // by default we don't keep categories in url
 			}
 
 			foreach ($pass_info as $pass_index => $pass_element) {
 				list ($prefix) = explode('.', $pass_element);
 				$catalog_item = $this->findModule('Var', $prefix) && $this->getUnitOption($prefix, 'CatalogItem');
 
 				if (array_key_exists($prefix, $this->RewriteListeners)) {
 					// if next prefix is same as current, but with special => exclude current prefix from url
 					$next_prefix = array_key_exists($pass_index + 1, $pass_info) ? $pass_info[$pass_index + 1] : false;
 					if ($next_prefix) {
 						$next_prefix = substr($next_prefix, 0, strlen($prefix) + 1);
 						if ($prefix . '.' == $next_prefix) {
 							continue;
 						}
 					}
 
 					// rewrited url part
 					$url_part = $this->BuildModuleEnv_NEW($pass_element, $params, $pass_events);
 
 					if (is_string($url_part) && $url_part) {
 						$ret .= $url_part . '/';
 
 						if ($catalog_item) {
 							// pass category later only for catalog items
 							$catalog_item_found = true;
 						}
 					}
 					elseif (is_array($url_part)) {
 						// rewrite listener want to insert something at the beginning of url too
 						if ($url_part[0]) {
 							$inject_parts[] = $url_part[0];
 						}
 
 						if ($url_part[1]) {
 							$ret .= $url_part[1] . '/';
 						}
 
 						if ($catalog_item) {
 							// pass category later only for catalog items
 							$catalog_item_found = true;
 						}
 					} elseif ($url_part === false) {
 						// rewrite listener decided not to rewrite given $pass_element
 						$env .= ':' . $this->BuildModuleEnv($pass_element, $params, $pass_events);
 					}
 				}
 				else {
 					$env .= ':' . $this->BuildModuleEnv($pass_element, $params, $pass_events);
 				}
 			}
 
 			if ($catalog_item_found || preg_match('/c\.[-\d]*/', implode(',', $pass_info))) {
 				// "c" prefix is present -> keep category
 				$params['pass_category'] = true;
 			}
 
 			$params['inject_parts'] = $inject_parts;
 
 			$ret = $this->BuildModuleEnv_NEW('m', $params, $pass_events) . '/' . $ret;
 			$cat_processed = array_key_exists('category_processed', $params) && $params['category_processed'];
 
 			// remove tempporary parameters used by listeners
 			unset($params['t'], $params['inject_parts'], $params['pass_template'], $params['pass_category'], $params['category_processed']);
 
 			if ($catalog_item_found || !$cat_processed || !defined('EXP_DIR_URLS')) {
 				// this catalog item detail page OR there is no category given
 				$ret = trim($ret, '/') . '.html';
 			}
 			else {
 				// url ends with "/" and not with ".html"
 				$ret = trim($ret, '/') .  '/';
 			}
 
 			if ($env) {
 				$params[ENV_VAR_NAME] = ltrim($env, ':');
 			}
 		}
 
 		unset($params['pass'], $params['opener'], $params['m_event']);
 		if ($force_admin) {
 			$params['admin'] = 1;
 		}
 
 		if (array_key_exists('escape', $params) && $params['escape']) {
 			$ret = addslashes($ret);
 			unset($params['escape']);
 		}
 
 		$ret = str_replace('%2F', '/', urlencode($ret));
 
 		$params_str = '';
 		$join_string = $encode ? '&' : '&amp;';
 
 		foreach ($params as $param => $value) {
 			$params_str .= $join_string . $param . '=' . $value;
 		}
 
 		if ($params_str) {
 			$ret .= '?' . substr($params_str, strlen($join_string));
 		}
 
 		if ($encode) {
 			$ret = str_replace('\\', '%5C', $ret);
 		}
 
 		return $ret;
 	}
 
 	function BuildModuleEnv_NEW($prefix_special, &$params, $keep_events = false)
 	{
 		list ($prefix) = explode('.', $prefix_special);
 
 		$url_parts = Array ();
 		$listener = $this->RewriteListeners[$prefix];
 
 		$ret = $listener[0]->$listener[1](REWRITE_MODE_BUILD, $prefix_special, $params, $url_parts, $keep_events);
 
 		return $ret;
 	}
 
 	/**
 	 * Builds env part that corresponds prefix passed
 	 *
 	 * @param string $prefix_special item's prefix & [special]
 	 * @param Array $params url params
 	 * @param bool $pass_events
 	 */
 	function BuildModuleEnv($prefix_special, &$params, $pass_events = false)
 	{
 		list($prefix) = explode('.', $prefix_special);
 		$query_vars = $this->getUnitOption($prefix, 'QueryString');
 
 		//if pass events is off and event is not implicity passed
 		if( !$pass_events && !isset($params[$prefix_special.'_event']) ) {
 			$params[$prefix_special.'_event'] = ''; // remove event from url if requested
 			//otherwise it will use value from get_var
 		}
 
 		if(!$query_vars) return '';
 
 		$tmp_string = Array(0 => $prefix_special);
 		foreach($query_vars as $index => $var_name)
 		{
 			//if value passed in params use it, otherwise use current from application
 			$var_name = $prefix_special.'_'.$var_name;
 			$tmp_string[$index] =  isset( $params[$var_name] ) ? $params[$var_name] : $this->GetVar($var_name);
 			if ( isset($params[$var_name]) ) unset( $params[$var_name] );
 		}
 
 		$escaped = array();
 		foreach ($tmp_string as $tmp_val) {
 			$escaped[] = str_replace(Array('-',':'), Array('\-','\:'), $tmp_val);
 		}
 
 		$ret = implode('-', $escaped);
 		if ($this->getUnitOption($prefix, 'PortalStyleEnv') == true)
 		{
 			$ret = preg_replace('/^([a-zA-Z]+)-([0-9]+)-(.*)/','\\1\\2-\\3', $ret);
 		}
 		return $ret;
 	}
 
 	function BuildEnv($t, $params, $pass='all', $pass_events = false, $env_var = true)
 	{
 		$session =& $this->recallObject('Session');
 		$ssl = isset($params['__SSL__']) ? $params['__SSL__'] : 0;
 		$sid = $session->NeedQueryString() && !$this->RewriteURLs($ssl) ? $this->GetSID() : '';
 //		if (getArrayValue($params,'admin') == 1) $sid = $this->GetSID();
 
 		$ret = '';
 		if ($env_var) {
 			$ret = ENV_VAR_NAME.'=';
 		}
 
 		$ret .=	$sid.(constOn('INPORTAL_ENV') ? '-' : ':');
 
 		$encode = false;
 		if (isset($params['__URLENCODE__'])) {
 			$encode = $params['__URLENCODE__'];
 			unset($params['__URLENCODE__']);
 		}
 
 		if (isset($params['__SSL__'])) {
 			unset($params['__SSL__']);
 		}
 
 		$env_string = '';
 		$category_id = isset($params['m_cat_id']) ? $params['m_cat_id'] : $this->GetVar('m_cat_id');
 
 		$item_id = false;
 		$pass_info = $this->getPassInfo($pass);
 		if ($pass_info) {
 			if ($pass_info[0] == 'm') array_shift($pass_info);
 			foreach ($pass_info as $pass_element) {
 				list($prefix) = explode('.', $pass_element);
 				$require_rewrite = $this->findModule('Var', $prefix);
 				if ($require_rewrite) {
 					$item_id = isset($params[$pass_element.'_id']) ? $params[$pass_element.'_id'] : $this->GetVar($pass_element.'_id');
 				}
 				$env_string .= ':'.$this->BuildModuleEnv($pass_element, $params, $pass_events);
 			}
 		}
 
 		if (strtolower($t) == '__default__') {
 			// to put category & item templates into cache
 			$filename = $this->getFilename('c', $category_id);
 			if (is_numeric($item_id)) {
 				$mod_rw_helper =& $this->Application->recallObject('ModRewriteHelper');
 				/* @var $mod_rw_helper kModRewriteHelper */
 
 				$t = $mod_rw_helper->GetItemTemplate($category_id, $pass_element); // $pass_element should be the last processed element
 //				$t =  $this->getCache('item_templates', $category_id);
 			}
 			elseif ($category_id) {
 				$t = strtolower( preg_replace('/^Content\//i', '', $this->getCache('category_templates', $category_id)) );
 			}
 			else {
 				$t = 'index';
 			}
 		}
 
 		$ret .= $t.':'.$this->BuildModuleEnv('m', $params, $pass_events).$env_string;
 
 		unset($params['pass'], $params['opener'], $params['m_event']);
 
 		if ($this->GetVar('admin') && !isset($params['admin'])) {
 			$params['admin'] = 1;
 
 			if (!array_key_exists('editing_mode', $params)) {
 				$params['editing_mode'] = EDITING_MODE;
 			}
 		}
 
 		if (array_key_exists('escape', $params) && $params['escape']) {
 			$ret = addslashes($ret);
 			unset($params['escape']);
 		}
 
 		$join_string = $encode ? '&' : '&amp;';
 		$params_str = '';
 		foreach ($params as $param => $value)
 		{
 			$params_str .= $join_string.$param.'='.$value;
 		}
 		$ret .= $params_str;
 
 		if ($encode) {
 			$ret = str_replace('\\', '%5C', $ret);
 		}
 		return $ret;
 	}
 
 	function BaseURL($prefix='', $ssl=null)
 	{
 		if ($ssl === null) {
 			return PROTOCOL.SERVER_NAME.(defined('PORT')?':'.PORT : '').rtrim(BASE_PATH, '/').$prefix.'/';
 		}
 		else {
 			if ($ssl) {
 				$base_url = defined('ADMIN') && ADMIN ? $this->ConfigValue('AdminSSL_URL') : false;
 				if (!$base_url) {
 					$base_url = $this->ConfigValue('SSL_URL');
 				}
 
 				return rtrim($base_url, '/').$prefix.'/';
 			}
 			else {
 				return 'http://'.DOMAIN.(defined('PORT')?':'.PORT : '').rtrim( $this->ConfigValue('Site_Path'), '/').$prefix.'/';
 			}
 		}
 	}
 
 	function Redirect($t='', $params=null, $prefix='', $index_file=null)
 	{
 		$js_redirect = getArrayValue($params, 'js_redirect');
 		if (preg_match("/external:(.*)/", $t, $rets)) {
 			$location = $rets[1];
 		}
 		else {
 			if ($t == '' || $t === true) $t = $this->GetVar('t');
 
 			// pass prefixes and special from previous url
 			if( isset($params['js_redirect']) ) unset($params['js_redirect']);
 
 			if (!isset($params['pass'])) $params['pass'] = 'all';
 			if ($this->GetVar('ajax') == 'yes' && $t == $this->GetVar('t')) {
 				// redirects to the same template as current
 				$params['ajax'] = 'yes';
 			}
 			$params['__URLENCODE__'] = 1;
 			$location = $this->HREF($t, $prefix, $params, $index_file);
 			//echo " location : $location <br>";
 		}
 
 		$a_location = $location;
 		$location = "Location: $location";
 
 
 		if ($this->isDebugMode() && constOn('DBG_REDIRECT')) {
 			$this->Debugger->appendTrace();
 			echo "<b>Debug output above!!!</b> Proceed to redirect: <a href=\"$a_location\">$a_location</a><br>";
 		}
 		else {
 			if ($js_redirect) {
 				$this->SetVar('t', 'redirect');
 				$this->SetVar('redirect_to_js', addslashes($a_location) );
 				$this->SetVar('redirect_to', $a_location);
 				return true;
 			}
 			else {
 				if ($this->GetVar('ajax') == 'yes' && $t != $this->GetVar('t')) {
 					// redirection to other then current template during ajax request
 					echo '#redirect#'.$a_location;
 				}
 				elseif (headers_sent() != '') {
 					// some output occured -> redirect using javascript
 					echo '<script type="text/javascript">window.location.href = \''.$a_location.'\';</script>';
 				}
 				else {
 					// no output before -> redirect using HTTP header
 
 //					header('HTTP/1.1 302 Found');
 					header("$location");
 				}
 			}
 		}
 
 		ob_end_flush();
 		// session expiration is called from session initialization,
 		// that's why $this->Session may be not defined here
 		$session =& $this->Application->recallObject('Session');
 		/* @var $session Session */
 
 		$this->HandleEvent( new kEvent('adm:OnBeforeShutdown') );
 		$session->SaveData();
 		exit;
 	}
 
-	function Phrase($label)
+	function Phrase($label, $allow_editing = true)
 	{
-		return $this->Phrases->GetPhrase($label);
+		return $this->Phrases->GetPhrase($label, $allow_editing);
 	}
 
 	/**
 	 * Replace language tags in exclamation marks found in text
 	 *
 	 * @param string $text
 	 * @param bool $force_escape force escaping, not escaping of resulting string
 	 * @return string
 	 * @access public
 	 */
 	function ReplaceLanguageTags($text, $force_escape=null)
 	{
 		// !!!!!!!!
 //		if( !is_object($this->Phrases) ) $this->Debugger->appendTrace();
 		return $this->Phrases->ReplaceLanguageTags($text,$force_escape);
 	}
 
 	/**
 	 * Checks if user is logged in, and creates
 	 * user object if so. User object can be recalled
 	 * later using "u.current" prefix_special. Also you may
 	 * get user id by getting "u.current_id" variable.
 	 *
 	 * @access private
 	 */
 	function ValidateLogin()
 	{
 		$session =& $this->recallObject('Session');
 		$user_id = $session->GetField('PortalUserId');
 		if (!$user_id && $user_id != -1) $user_id = -2;
 		$this->SetVar('u.current_id', $user_id);
 
 		if (!$this->IsAdmin()) {
 			// needed for "profile edit", "registration" forms ON FRONT ONLY
 			$this->SetVar('u_id', $user_id);
 		}
 
 		$this->StoreVar('user_id', $user_id);
 
 		if ($this->GetVar('expired') == 1) {
 			// this parameter is set only from admin
 			$user =& $this->recallObject('u.current');
 			$user->SetError('ValidateLogin', 'session_expired', 'la_text_sess_expired');
 		}
 
 		if (($user_id != -2) && constOn('DBG_REQUREST_LOG') ) {
 			$http_query =& $this->recallObject('HTTPQuery');
 			$http_query->writeRequestLog(DBG_REQUREST_LOG);
 		}
 
 		if ($user_id != -2) {
 			// normal users + root
 			$this->LoadPersistentVars();
 		}
 	}
 
 	/**
 	 * Loads current user persistent session data
 	 *
 	 */
 	function LoadPersistentVars()
 	{
 		$this->Session->LoadPersistentVars();
 	}
 
 	function LoadCache() {
 		$cache_key = $this->GetVar('t').$this->GetVar('m_theme').$this->GetVar('m_lang').$this->IsAdmin();
 		$query = sprintf("SELECT PhraseList, ConfigVariables FROM %s WHERE Template = %s",
 											TABLE_PREFIX.'PhraseCache',
 											$this->Conn->qstr(md5($cache_key)));
 		$res = $this->Conn->GetRow($query);
 
 		if ($res) {
 			$this->Caches['PhraseList'] = $res['PhraseList'] ? explode(',', $res['PhraseList']) : array();
 
 			$config_ids = $res['ConfigVariables'] ? explode(',', $res['ConfigVariables']) : array();
 			if (isset($this->Caches['ConfigVariables'])) {
 				$config_ids = array_diff($config_ids, $this->Caches['ConfigVariables']);
 			}
 		}
 		else {
 			$config_ids = array();
 		}
 		$this->Caches['ConfigVariables'] = $config_ids;
 		$this->ConfigCacheIds = $config_ids;
 	}
 
 	function UpdateCache()
 	{
 		$update = false;
 		//something changed
 		$update = $update || $this->Phrases->NeedsCacheUpdate();
 		$update = $update || (count($this->ConfigCacheIds) && $this->ConfigCacheIds != $this->Caches['ConfigVariables']);
 		if ($update) {
 			$cache_key = $this->GetVar('t').$this->GetVar('m_theme').$this->GetVar('m_lang').$this->IsAdmin();
 			$query = sprintf("REPLACE %s (PhraseList, CacheDate, Template, ConfigVariables)
 												VALUES (%s, %s, %s, %s)",
 												TABLE_PREFIX.'PhraseCache',
 												$this->Conn->Qstr(join(',', $this->Phrases->Ids)),
 												adodb_mktime(),
 												$this->Conn->Qstr(md5($cache_key)),
 												$this->Conn->qstr(implode(',', array_unique($this->ConfigCacheIds))));
 			$this->Conn->Query($query);
 		}
 	}
 
 	function InitConfig()
 	{
 		if (isset($this->Caches['ConfigVariables']) && count($this->Caches['ConfigVariables']) > 0) {
 			$this->ConfigHash = array_merge($this->ConfigHash, $this->Conn->GetCol(
 				'SELECT VariableValue, VariableName FROM '.TABLE_PREFIX.'ConfigurationValues
 				 WHERE VariableId IN ('.implode(',', $this->Caches['ConfigVariables']).')', 'VariableName'));
 		}
 	}
 
 	/**
 	 * Returns configuration option value by name
 	 *
 	 * @param string $name
 	 * @return string
 	 */
 	function ConfigValue($name)
 	{
 		$res = array_key_exists($name, $this->ConfigHash) ? $this->ConfigHash[$name] : false;
 		if ($res !== false) {
 			return $res;
 		}
 
 		if (defined('IS_INSTALL') && IS_INSTALL && !$this->TableFound('ConfigurationValues')) {
 			return false;
 		}
 
 		$sql = 'SELECT VariableId, VariableValue
 				FROM '.TABLE_PREFIX.'ConfigurationValues
 				WHERE VariableName = '.$this->Conn->qstr($name);
 		$res = $this->Conn->GetRow($sql);
 
 		if ($res !== false) {
 			$this->ConfigHash[$name] = $res['VariableValue'];
 			$this->ConfigCacheIds[] = $res['VariableId'];
 			return $res['VariableValue'];
 		}
 
 		return false;
 	}
 
 	function UpdateConfigCache()
 	{
 		if ($this->ConfigCacheIds) {
 
 		}
 	}
 
 	/**
 	 * Allows to process any type of event
 	 *
 	 * @param kEvent $event
 	 * @access public
 	 * @author Alex
 	 */
 	function HandleEvent(&$event, $params=null, $specificParams=null)
 	{
 		if ( isset($params) ) {
 			$event = new kEvent( $params, $specificParams );
 		}
 
 		if (!isset($this->EventManager)) {
 			$this->EventManager =& $this->recallObject('EventManager');
 		}
 
 		$this->EventManager->HandleEvent($event);
 	}
 
 	/**
 	 * Registers new class in the factory
 	 *
 	 * @param string $real_class Real name of class as in class declaration
 	 * @param string $file Filename in what $real_class is declared
 	 * @param string $pseudo_class Name under this class object will be accessed using getObject method
 	 * @param Array $dependecies List of classes required for this class functioning
 	 * @access public
 	 * @author Alex
 	 */
 	function registerClass($real_class, $file, $pseudo_class = null, $dependecies = Array() )
 	{
 		$this->Factory->registerClass($real_class, $file, $pseudo_class, $dependecies);
 	}
 
 	/**
 	 * Add $class_name to required classes list for $depended_class class.
 	 * All required class files are included before $depended_class file is included
 	 *
 	 * @param string $depended_class
 	 * @param string $class_name
 	 * @author Alex
 	 */
 	function registerDependency($depended_class, $class_name)
 	{
 		$this->Factory->registerDependency($depended_class, $class_name);
 	}
 
 	/**
 	 * Registers Hook from subprefix event to master prefix event
 	 *
 	 * @param string $hookto_prefix
 	 * @param string $hookto_special
 	 * @param string $hookto_event
 	 * @param string $mode
 	 * @param string $do_prefix
 	 * @param string $do_special
 	 * @param string $do_event
 	 * @param string $conditional
 	 * @access public
 	 * @todo take care of a lot parameters passed
 	 * @author Kostja
 	 */
 	function registerHook($hookto_prefix, $hookto_special, $hookto_event, $mode, $do_prefix, $do_special, $do_event, $conditional)
 	{
 		$event_manager =& $this->recallObject('EventManager');
 		$event_manager->registerHook($hookto_prefix, $hookto_special, $hookto_event, $mode, $do_prefix, $do_special, $do_event, $conditional);
 	}
 
 	/**
 	 * Allows one TagProcessor tag act as other TagProcessor tag
 	 *
 	 * @param Array $tag_info
 	 * @author Kostja
 	 */
 	function registerAggregateTag($tag_info)
 	{
 		$aggregator =& $this->recallObject('TagsAggregator', 'kArray');
 		$aggregator->SetArrayValue($tag_info['AggregateTo'], $tag_info['AggregatedTagName'], Array($tag_info['LocalPrefix'], $tag_info['LocalTagName'], getArrayValue($tag_info, 'LocalSpecial')));
 	}
 
 	/**
 	 * Returns object using params specified,
 	 * creates it if is required
 	 *
 	 * @param string $name
 	 * @param string $pseudo_class
 	 * @param Array $event_params
 	 * @return Object
 	 * @author Alex
 	 */
 	function &recallObject($name,$pseudo_class=null,$event_params=Array())
 	{
 		$result =& $this->Factory->getObject($name, $pseudo_class, $event_params);
 		return $result;
 	}
 
 	/**
 	 * Returns object using Variable number of params,
 	 * all params starting with 4th are passed to object consturctor
 	 *
 	 * @param string $name
 	 * @param string $pseudo_class
 	 * @param Array $event_params
 	 * @return Object
 	 * @author Alex
 	 */
 	function &recallObjectP($name,$pseudo_class=null,$event_params=Array())
 	{
 		$func_args = func_get_args();
 		$result =& ref_call_user_func_array( Array(&$this->Factory, 'getObjectP'), $func_args );
 		return $result;
 	}
 
 	/**
 	 * Returns tag processor for prefix specified
 	 *
 	 * @param string $prefix
 	 * @return kDBTagProcessor
 	 */
 	function &recallTagProcessor($prefix)
 	{
 		$this->InitParser(); // because kDBTagProcesor is in TemplateParser dependencies
 		$result =& $this->recallObject($prefix.'_TagProcessor');
 		return $result;
 	}
 
 	/**
 	 * Checks if object with prefix passes was already created in factory
 	 *
 	 * @param string $name object presudo_class, prefix
 	 * @return bool
 	 * @author Kostja
 	 */
 	function hasObject($name)
 	{
 		return isset($this->Factory->Storage[$name]);
 	}
 
 	/**
 	 * Removes object from storage by given name
 	 *
 	 * @param string $name Object's name in the Storage
 	 * @author Kostja
 	 */
 	function removeObject($name)
 	{
 		$this->Factory->DestroyObject($name);
 	}
 
 	/**
 	 * Get's real class name for pseudo class,
 	 * includes class file and creates class
 	 * instance
 	 *
 	 * @param string $pseudo_class
 	 * @return Object
 	 * @access public
 	 * @author Alex
 	 */
 	function &makeClass($pseudo_class)
 	{
 		$func_args = func_get_args();
 		$result =& ref_call_user_func_array( Array(&$this->Factory, 'makeClass'), $func_args);
 
 		return $result;
 	}
 
 	/**
 	 * Checks if application is in debug mode
 	 *
 	 * @param bool $check_debugger check if kApplication debugger is initialized too, not only for defined DEBUG_MODE constant
 	 * @return bool
 	 * @author Alex
 	 * @access public
 	 */
 	function isDebugMode($check_debugger = true)
 	{
 		$debug_mode = defined('DEBUG_MODE') && DEBUG_MODE;
 		if ($check_debugger) {
 			$debug_mode = $debug_mode && is_object($this->Debugger);
 		}
 		return $debug_mode;
 	}
 
 	/**
 	 * Checks if it is admin
 	 *
 	 * @return bool
 	 * @author Alex
 	 */
 	function IsAdmin()
 	{
 		return constOn('ADMIN');
 	}
 
 	/**
 	 * Apply url rewriting used by mod_rewrite or not
 	 *
 	 * @param bool $ssl Force ssl link to be build
 	 * @return bool
 	 */
 	function RewriteURLs($ssl = false)
 	{
 		// case #1,#4:
 		//			we want to create https link from http mode
 		//			we want to create https link from https mode
 		//			conditions: ($ssl || PROTOCOL == 'https://') && $this->ConfigValue('UseModRewriteWithSSL')
 
 		// case #2,#3:
 		//			we want to create http link from https mode
 		//			we want to create http link from http mode
 		//			conditions: !$ssl && (PROTOCOL == 'https://' || PROTOCOL == 'http://')
 
 		$allow_rewriting =
 			(!$ssl && (PROTOCOL == 'https://' || PROTOCOL == 'http://')) // always allow mod_rewrite for http
 			|| // or allow rewriting for redirect TO httpS or when already in httpS
 			(($ssl || PROTOCOL == 'https://') && $this->ConfigValue('UseModRewriteWithSSL')); // but only if it's allowed in config!
 		return constOn('MOD_REWRITE') && $allow_rewriting;
 	}
 
 	/**
 	 * Reads unit (specified by $prefix)
 	 * option specified by $option
 	 *
 	 * @param string $prefix
 	 * @param string $option
 	 * @param mixed $default
 	 * @return string
 	 * @access public
 	 * @author Alex
 	 */
 	function getUnitOption($prefix, $option, $default = false)
 	{
 		/*if (!isset($this->UnitConfigReader)) {
 			$this->UnitConfigReader =& $this->recallObject('kUnitConfigReader');
 		}*/
 		return $this->UnitConfigReader->getUnitOption($prefix, $option, $default);
 	}
 
 	/**
 	 * Set's new unit option value
 	 *
 	 * @param string $prefix
 	 * @param string $name
 	 * @param string $value
 	 * @author Alex
 	 * @access public
 	 */
 	function setUnitOption($prefix, $option, $value)
 	{
 //		$unit_config_reader =& $this->recallObject('kUnitConfigReader');
 		return $this->UnitConfigReader->setUnitOption($prefix,$option,$value);
 	}
 
 	/**
 	 * Read all unit with $prefix options
 	 *
 	 * @param string $prefix
 	 * @return Array
 	 * @access public
 	 * @author Alex
 	 */
 	function getUnitOptions($prefix)
 	{
 //		$unit_config_reader =& $this->recallObject('kUnitConfigReader');
 		return $this->UnitConfigReader->getUnitOptions($prefix);
 	}
 
 	/**
 	 * Returns true if config exists and is allowed for reading
 	 *
 	 * @param string $prefix
 	 * @return bool
 	 */
 	function prefixRegistred($prefix)
 	{
 		/*if (!isset($this->UnitConfigReader)) {
 			$this->UnitConfigReader =& $this->recallObject('kUnitConfigReader');
 		}*/
 		return $this->UnitConfigReader->prefixRegistred($prefix);
 	}
 
 	/**
 	 * Splits any mixing of prefix and
 	 * special into correct ones
 	 *
 	 * @param string $prefix_special
 	 * @return Array
 	 * @access public
 	 * @author Alex
 	 */
 	function processPrefix($prefix_special)
 	{
 		return $this->Factory->processPrefix($prefix_special);
 	}
 
 	/**
 	 * Set's new event for $prefix_special
 	 * passed
 	 *
 	 * @param string $prefix_special
 	 * @param string $event_name
 	 * @access public
 	 */
 	function setEvent($prefix_special,$event_name)
 	{
 		$event_manager =& $this->recallObject('EventManager');
 		$event_manager->setEvent($prefix_special,$event_name);
 	}
 
 
 	/**
 	 * SQL Error Handler
 	 *
 	 * @param int $code
 	 * @param string $msg
 	 * @param string $sql
 	 * @return bool
 	 * @access private
 	 * @author Alex
 	 */
 	function handleSQLError($code, $msg, $sql)
 	{
 		if ( isset($this->Debugger) )
 		{
 			$errorLevel = constOn('DBG_SQL_FAILURE') && !defined('IS_INSTALL') ? E_USER_ERROR : E_USER_WARNING;
 			$this->Debugger->appendTrace();
 
 			$error_msg = '<span class="debug_error">'.$msg.' ('.$code.')</span><br><a href="javascript:$Debugger.SetClipboard(\''.htmlspecialchars($sql).'\');"><b>SQL</b></a>: '.$this->Debugger->formatSQL($sql);
 			$long_id = $this->Debugger->mapLongError($error_msg);
 			trigger_error( mb_substr($msg.' ('.$code.') ['.$sql.']',0,1000).' #'.$long_id, $errorLevel);
 			return true;
 		}
 		else
 		{
 			//$errorLevel = constOn('IS_INSTALL') ? E_USER_WARNING : E_USER_ERROR;
 			$errorLevel = E_USER_WARNING;
 			trigger_error('<b>SQL Error</b> in sql: '.$sql.', code <b>'.$code.'</b> ('.$msg.')', $errorLevel);
 			/*echo '<b>xProcessing SQL</b>: '.$sql.'<br>';
 			echo '<b>Error ('.$code.'):</b> '.$msg.'<br>';*/
 			return $errorLevel == E_USER_ERROR ? false : true;
 		}
 	}
 
 	/**
 	 * Default error handler
 	 *
 	 * @param int $errno
 	 * @param string $errstr
 	 * @param string $errfile
 	 * @param int $errline
 	 * @param Array $errcontext
 	 */
 	function handleError($errno, $errstr, $errfile = '', $errline = '', $errcontext = '')
 	{
 		if (defined('SILENT_LOG') && SILENT_LOG) {
 			if ( !(defined('DBG_IGNORE_STRICT_ERRORS') && DBG_IGNORE_STRICT_ERRORS && defined('E_STRICT') && ($errno == E_STRICT)) ) {
 				$fp = fopen(FULL_PATH.'/silent_log.txt','a');
 				$time = adodb_date('d/m/Y H:i:s');
 				fwrite($fp, '['.$time.'] #'.$errno.': '.strip_tags($errstr).' in ['.$errfile.'] on line '.$errline."\n");
 				fclose($fp);
 			}
 		}
 
 		$debug_mode = defined('DEBUG_MODE') && DEBUG_MODE;
 		$skip_reporting = defined('DBG_SKIP_REPORTING') && DBG_SKIP_REPORTING;
 
 		if (!$this->errorHandlers || ($debug_mode && $skip_reporting)) {
 			// when debugger absent OR it's present, but we actually can't see it's error report (e.g. during ajax request)
 			$ignore_fatal_errors = defined('DBG_IGNORE_FATAL_ERRORS') && DBG_IGNORE_FATAL_ERRORS;
 
 			if (($errno == E_USER_ERROR) && !$ignore_fatal_errors) {
 				echo ('	<div style="background-color: #FEFFBF; margin: auto; padding: 10px; border: 2px solid red; text-align: center">
 							<strong>Fatal Error: </strong>'."$errstr in $errfile on line $errline".'
 						</div>');
 				exit;
 			}
 
 			if (!$this->errorHandlers) {
 				return true;
 			}
 		}
 
 		$res = false;
 		$i = 0; // while (not foreach) because it is array of references in some cases
 		$eh_count = count($this->errorHandlers);
 		while ($i < $eh_count) {
 			if ( is_array($this->errorHandlers[$i]) ) {
 				$object =& $this->errorHandlers[$i][0];
 				$method = $this->errorHandlers[$i][1];
 				$res = $object->$method($errno, $errstr, $errfile, $errline, $errcontext);
 			}
 			else {
 				$function = $this->errorHandlers[$i];
 				$res = $function($errno, $errstr, $errfile, $errline, $errcontext);
 			}
 			$i++;
 		}
 		return $res;
 	}
 
 	/**
 	 * Returns & blocks next ResourceId available in system
 	 *
 	 * @return int
 	 * @access public
 	 * @author Alex
 	 */
 	function NextResourceId()
 	{
 		$table_name = TABLE_PREFIX.'IdGenerator';
 
 		$this->Conn->Query('LOCK TABLES '.$table_name.' WRITE');
 		$this->Conn->Query('UPDATE '.$table_name.' SET lastid = lastid + 1');
 		$id = $this->Conn->GetOne('SELECT lastid FROM '.$table_name);
 		if($id === false)
 		{
 			$this->Conn->Query('INSERT INTO '.$table_name.' (lastid) VALUES (2)');
 			$id = 2;
 		}
 		$this->Conn->Query('UNLOCK TABLES');
 		return $id - 1;
 	}
 
 	/**
 	 * Returns genealogical main prefix for subtable prefix passes
 	 * OR prefix, that has been found in REQUEST and some how is parent of passed subtable prefix
 	 *
 	 * @param string $current_prefix
 	 * @param string $real_top if set to true will return real topmost prefix, regardless of its id is passed or not
 	 * @return string
 	 * @access public
 	 * @author Kostja / Alex
 	 */
 	function GetTopmostPrefix($current_prefix, $real_top = false)
 	{
 		// 1. get genealogical tree of $current_prefix
 		$prefixes = Array ($current_prefix);
 		while ( $parent_prefix = $this->getUnitOption($current_prefix, 'ParentPrefix') ) {
 			if (!$this->prefixRegistred($parent_prefix)) {
 				// stop searching, when parent prefix is not registered
 				break;
 			}
 
 			$current_prefix = $parent_prefix;
 			array_unshift($prefixes, $current_prefix);
 		}
 
 		if ($real_top) {
 			return $current_prefix;
 		}
 
 		// 2. find what if parent is passed
 		$passed = explode(',', $this->GetVar('all_passed'));
 		foreach ($prefixes as $a_prefix) {
 			if (in_array($a_prefix, $passed)) {
 				return $a_prefix;
 			}
 		}
 
 		return $current_prefix;
 	}
 
 	/**
 	 * Triggers email event of type Admin
 	 *
 	 * @param string $email_event_name
 	 * @param int $to_user_id
 	 * @param array $send_params associative array of direct send params, possible keys: to_email, to_name, from_email, from_name, message, message_text
 	 * @return unknown
 	 */
 	function &EmailEventAdmin($email_event_name, $to_user_id = -1, $send_params = false)
 	{
 		$event =& $this->EmailEvent($email_event_name, 1, $to_user_id, $send_params);
 		return $event;
 	}
 
 	/**
 	 * Triggers email event of type User
 	 *
 	 * @param string $email_event_name
 	 * @param int $to_user_id
 	 * @param array $send_params associative array of direct send params, possible keys: to_email, to_name, from_email, from_name, message, message_text
 	 * @return unknown
 	 */
 	function &EmailEventUser($email_event_name, $to_user_id = -1, $send_params = false)
 	{
 		$event =& $this->EmailEvent($email_event_name, 0, $to_user_id, $send_params);
 		return $event;
 	}
 
 	/**
 	 * Triggers general email event
 	 *
 	 * @param string $email_event_name
 	 * @param int $email_event_type ( 0 for User, 1 for Admin)
 	 * @param int $to_user_id
 	 * @param array $send_params associative array of direct send params,
 	 *  possible keys: to_email, to_name, from_email, from_name, message, message_text
 	 * @return unknown
 	 */
 	function &EmailEvent($email_event_name, $email_event_type, $to_user_id = -1, $send_params = false)
 	{
 		$params = array(
 			'EmailEventName' => $email_event_name,
 			'EmailEventToUserId' => $to_user_id,
 			'EmailEventType' => $email_event_type,
 		);
 		if ($send_params) {
 			$params['DirectSendParams'] = $send_params;
 		}
 		$event_str = isset($send_params['use_special']) ? 'emailevents.'.$send_params['use_special'].':OnEmailEvent' : 'emailevents:OnEmailEvent';
 		$this->HandleEvent($event, $event_str, $params);
 
 		return $event;
 	}
 
 	/**
 	 * Allows to check if user in this session is logged in or not
 	 *
 	 * @return bool
 	 */
 	function LoggedIn()
 	{
 		// no session during expiration process
 		return is_null($this->Session) ? false : $this->Session->LoggedIn();
 	}
 
 	/**
 	 * Check current user permissions based on it's group permissions in specified category
 	 *
 	 * @param string $name permission name
 	 * @param int $cat_id category id, current used if not specified
 	 * @param int $type permission type {1 - system, 0 - per category}
 	 * @return int
 	 */
 	function CheckPermission($name, $type = 1, $cat_id = null)
 	{
 		$perm_helper =& $this->recallObject('PermissionsHelper');
 		return $perm_helper->CheckPermission($name, $type, $cat_id);
 	}
 
 	/**
 	 * Set's any field of current visit
 	 *
 	 * @param string $field
 	 * @param mixed $value
 	 */
 	function setVisitField($field, $value)
 	{
 		$visit =& $this->recallObject('visits');
 		$visit->SetDBField($field, $value);
 		$visit->Update();
 	}
 
 	/**
 	 * Allows to check if in-portal is installed
 	 *
 	 * @return bool
 	 */
 	function isInstalled()
 	{
 		return $this->InitDone && (count($this->ModuleInfo) > 0);
 	}
 
 	/**
 	 * Allows to determine if module is installed & enabled
 	 *
 	 * @param string $module_name
 	 * @return bool
 	 */
 	function isModuleEnabled($module_name)
 	{
 		return $this->findModule('Name', $module_name) !== false;
 
 	}
 
 	function reportError($class, $method)
 	{
 		$this->Debugger->appendTrace();
 		trigger_error('depricated method <b>'.$class.'->'.$method.'(...)</b>', E_USER_ERROR);
 	}
 
 	/**
 	 * Returns Window ID of passed prefix main prefix (in edit mode)
 	 *
 	 * @param string $prefix
 	 * @return mixed
 	 */
 	function GetTopmostWid($prefix)
 	{
 		$top_prefix = $this->GetTopmostPrefix($prefix);
 		$mode = $this->GetVar($top_prefix.'_mode');
 		return $mode != '' ? substr($mode, 1) : '';
 	}
 
 	/**
 	 * Get temp table name
 	 *
 	 * @param string $table
 	 * @param mixed $wid
 	 * @return string
 	 */
 	function GetTempName($table, $wid = '')
 	{
 		if (preg_match('/prefix:(.*)/', $wid, $regs)) {
 			$wid = $this->GetTopmostWid($regs[1]);
 		}
 
 		return TABLE_PREFIX.'ses_'.$this->GetSID().($wid ? '_'.$wid : '').'_edit_'.$table;
 	}
 
 	function GetTempTablePrefix($wid = '')
 	{
 		if (preg_match('/prefix:(.*)/', $wid, $regs)) {
 			$wid = $this->GetTopmostWid($regs[1]);
 		}
 
 		return TABLE_PREFIX.'ses_'.$this->GetSID().($wid ? '_'.$wid : '').'_edit_';
 	}
 
 	function IsTempTable($table)
 	{
 		return preg_match('/'.TABLE_PREFIX.'ses_'.$this->GetSID().'(_[\d]+){0,1}_edit_(.*)/',$table);
 	}
 
 	/**
 	 * Checks, that given prefix is in temp mode
 	 *
 	 * @param string $prefix
 	 * @return bool
 	 */
 	function IsTempMode($prefix, $special = '')
 	{
 		$top_prefix = $this->Application->GetTopmostPrefix($prefix);
 
 		$var_names = Array (
 			$top_prefix,
 			rtrim($top_prefix . '_' . $special, '_'), // from post
 			rtrim($top_prefix . '.' . $special, '.'), // assembled locally
 		);
 
 		$var_names = array_unique($var_names);
 
 		$temp_mode = false;
 		foreach ($var_names as $var_name) {
 			$value = $this->Application->GetVar($var_name . '_mode');
 			if ($value && (substr($value, 0, 1) == 't')) {
 				$temp_mode = true;
 				break;
 			}
 		}
 
 		return $temp_mode;
 	}
 
 	/**
 	 * Return live table name based on temp table name
 	 *
 	 * @param string $temp_table
 	 * @return string
 	 */
 	function GetLiveName($temp_table)
 	{
 		if( preg_match('/'.TABLE_PREFIX.'ses_'.$this->GetSID().'(_[\d]+){0,1}_edit_(.*)/',$temp_table, $rets) )
 		{
 			// cut wid from table end if any
 			return $rets[2];
 		}
 		else
 		{
 			return $temp_table;
 		}
 	}
 
 	function CheckProcessors($processors)
 	{
 		foreach ($processors as $a_processor)
 		{
 			if (!isset($this->CachedProcessors[$a_processor])) {
 				$this->CachedProcessors[$a_processor] =& $this->recallObject($a_processor.'_TagProcessor');
 			}
 		}
 	}
 
 	function TimeZoneAdjustment($time_zone = null)
 	{
 		if ($time_zone == 'GMT') {
 			return (-1) * adodb_date('Z');
 		}
 		$target_zone = isset($time_zone) ? $time_zone : $this->ConfigValue('Config_Site_Time');
 		return 3600 * ($target_zone - $this->ConfigValue('Config_Server_Time'));
 	}
 
 	function ApplicationDie($message = '')
 	{
 		$message = ob_get_clean().$message;
 		if ($this->isDebugMode()) {
 			$message .= $this->Debugger->printReport(true);
 		}
 
 		echo $this->UseOutputCompression() ? gzencode($message, DBG_COMPRESSION_LEVEL) : $message;
 		exit;
 	}
 
 
 	/* moved from MyApplication */
 
 	function getUserGroups($user_id)
 	{
 		switch($user_id)
 		{
 			case -1:
 				$user_groups = $this->ConfigValue('User_LoggedInGroup');
 				break;
 			case -2:
 				$user_groups = $this->ConfigValue('User_LoggedInGroup');
 				$user_groups .= ','.$this->ConfigValue('User_GuestGroup');
 				break;
 			default:
 				$sql = 'SELECT GroupId FROM '.TABLE_PREFIX.'UserGroup WHERE PortalUserId = '.$user_id;
 				$res = $this->Conn->GetCol($sql);
 				$user_groups = Array( $this->ConfigValue('User_LoggedInGroup') );
 				if(is_array($res))
 				{
 					$user_groups = array_merge($user_groups, $res);
 				}
 				$user_groups = implode(',', $user_groups);
 		}
 		return $user_groups;
 	}
 
 
 	/**
 	 * Allows to detect if page is browsed by spider (293 agents supported)
 	 *
 	 * @return bool
 	 */
 	function IsSpider()
 	{
 		static $is_spider = null;
 
 		if (!isset($is_spider)) {
 			$user_agent = trim($_SERVER['HTTP_USER_AGENT']);
 			$robots = file(FULL_PATH.'/core/robots_list.txt');
 			foreach ($robots as $robot_info) {
 				$robot_info = explode("\t", $robot_info, 3);
 				if ($user_agent == trim($robot_info[2])) {
 					$is_spider = true;
 					break;
 				}
 			}
 		}
 
 		return $is_spider;
 	}
 
 	/**
 	 * Allows to detect table's presense in database
 	 *
 	 * @param string $table_name
 	 * @return bool
 	 */
 	function TableFound($table_name)
 	{
 		return $this->Conn->TableFound($table_name);
 	}
 
 	/**
 	 * Returns counter value
 	 *
 	 * @param string $name counter name
 	 * @param Array $params counter parameters
 	 * @param string $query_name specify query name directly (don't generate from parmeters)
 	 * @param bool $multiple_results
 	 * @return mixed
 	 */
 	function getCounter($name, $params = Array (), $query_name = null, $multiple_results = false)
 	{
 		$count_helper =& $this->Application->recallObject('CountHelper');
 		/* @var $count_helper kCountHelper */
 
 		return $count_helper->getCounter($name, $params, $query_name, $multiple_results);
 	}
 
 	/**
 	 * Resets counter, whitch are affected by one of specified tables
 	 *
 	 * @param string $tables comma separated tables list used in counting sqls
 	 */
 	function resetCounters($tables)
 	{
 		if (constOn('IS_INSTALL')) {
 			return ;
 		}
 
 		$count_helper =& $this->Application->recallObject('CountHelper');
 		/* @var $count_helper kCountHelper */
 
 		return $count_helper->resetCounters($tables);
 	}
 
 	/**
 	 * Sends XML header + optionally displays xml heading
 	 *
 	 * @param string $xml_version
 	 * @return string
 	 * @author Alex
 	 */
 	function XMLHeader($xml_version = false)
 	{
 		$lang =& $this->recallObject('lang.current');
 		header('Content-type: text/xml; charset='.$lang->GetDBField('Charset'));
 
 		return $xml_version ? '<?xml version="'.$xml_version.'" encoding="'.$lang->GetDBField('Charset').'"?>' : '';
 	}
 
 	/**
 	 * Returns category tree
 	 *
 	 * @param int $category_id
 	 * @return Array
 	 */
 	function getTreeIndex($category_id)
 	{
 		$category_template = $this->getFilename('c', $category_id); // to rebuild "category_tree" cache
 
 		$tree_index = $this->getCache('category_tree', $category_id);
 
 		if ($tree_index) {
 			$ret = Array ();
 			list ($ret['TreeLeft'], $ret['TreeRight']) = explode(';', $tree_index);
 
 			return $ret;
 		}
 
 		return false;
 	}
 }
 
 ?>
\ No newline at end of file
Index: branches/5.0.x/core/kernel/constants.php
===================================================================
--- branches/5.0.x/core/kernel/constants.php	(revision 12297)
+++ branches/5.0.x/core/kernel/constants.php	(revision 12298)
@@ -1,126 +1,125 @@
 <?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.net/license/ for copyright notices and details.
 */
 
 	// kDBList filter types (then, types are divided into classes)
 	define('HAVING_FILTER', 1);
 	define('WHERE_FILTER', 2);
 	define('AGGREGATE_FILTER', 3);
 
 	// kDBList filter classes
 	define('FLT_SYSTEM',	1);	// System Having/Where filter [AND]
 	define('FLT_NORMAL',	2);	// User Having/Where filter [OR]
 	define('FLT_SEARCH',	3);	// User "Search" Having/Where filter [OR]
 	define('FLT_VIEW',		4);	// User "View Menu" Having/Where filter [AND]
 	define('FLT_CUSTOM',	5); // Custom fields (above) grid columns [AND]
 
 	// kMultipleFilter types
 	define('FLT_TYPE_AND',	'AND');
 	define('FLT_TYPE_OR',	'OR');
 
 	// item statuses
 	define('STATUS_DISABLED', 0);
 	define('STATUS_ACTIVE', 1);
 	define('STATUS_PENDING', 2);
 	define('STATUS_PENDING_EDITING', -2);
 
 	// sections
 	define('stTREE', 1);
 	define('stTAB', 2);
 
 	// event statuses
 	define('erSUCCESS',		0);		// event finished working succsessfully
 	define('erFAIL',		-1);	// event finished working, but result is unsuccsessfull
 	define('erFATAL',		-2);	// event experienced FATAL error - no hooks should continue!
 	define('erPERM_FAIL',	-3);	// event failed on internal permission checking (user has not permission)
 	define('erSTOP',		-4);	// event requested to stop processing (don't parse templates)
 
 	// permission types
 	define('ptCATEGORY', 	0);
 	define('ptSYSTEM', 		1);
 
 	// email event types
 	define('EVENT_TYPE_FRONTEND', 0);
 	define('EVENT_TYPE_ADMIN', 1);
 
 	define('EDIT_MARK', '&|edit|&'); // replace this sequence inside filters to SID[_main_wid]
 
 	$application =& kApplication::Instance();
 	$spacer_url = $application->BaseURL().'core/admin_templates/img/spacer.gif';
 	define('SPACER_URL', $spacer_url);
 
 	if (!$application->IsAdmin()) {
 		// don't show debugger buttons on front (if not overrided in "debug.php")
 		safeDefine('DBG_TOOLBAR_BUTTONS', 0);
 	}
 
 	define('smHIDE', 0); // always hide section from tree
 	define('smNORMAL', 1); // show section even, if they were marked as smDEBUG or smSUPER_ADMIN before
 	define('smDEBUG', 2); // show section in debug mode only
 	define('smSUPER_ADMIN', 4); // show section in super admin & debug mode
 
 	// common usage regular expressions
 	define('REGEX_EMAIL_USER', '[-a-zA-Z0-9!\#$%&*+\/=?^_`{|}~.]+');
 	define('REGEX_EMAIL_DOMAIN', '[a-zA-Z0-9]{1}[-.a-zA-Z0-9_]*\.[a-zA-Z]{2,6}');
 	define('ALLOW_DEFAULT_SETTINGS', '_USE_DEFAULT_USER_DATA_'); //Allow persistent vars to take data from default user's persistent data
 
 	define('XML_NO_TEXT_NODES', 1); // Normal mode for XMLHelper
 	define('XML_WITH_TEXT_NODES', 2); // Will create text nodes for every char-data (used in kPDFHelper)
 
 	// ChangeLog actions
 	define('clCREATE', 1);
 	define('clUPDATE', 2);
 	define('clDELETE', 3);
 
 	/**
 	 * Separator for ValueList fields
 	 *
 	 */
 	define('VALUE_LIST_SEPARATOR', '||');
 
 	// template editing modes
-	define('EDITING_MODE_CMS', 1); // content block only
-	define('EDITING_MODE_LAYOUT', 2); // content blocks, marked with "layout_view" parameter
-	define('EDITING_MODE_DESIGN', 3); // blocks, used as designs
-	define('EDITING_MODE_INSIDES', 4); // all other stuff, that could be editable
+	define('EDITING_MODE_BROWSE', 1); // no changes, front-end as users see it
+	define('EDITING_MODE_CONTENT', 2); // content blocks + phrase editing
+	define('EDITING_MODE_DESIGN', 3); // all other blocks
 
 	// agent types
 	define('AGENT_TYPE_USER', 1);
 	define('AGENT_TYPE_SYSTEM', 2);
 
 	// agent last run statuses
 	define('AGENT_LAST_RUN_SUCCEDED', 1);
 	define('AGENT_LAST_RUN_FAILED', 0);
 	define('AGENT_LAST_RUN_RUNNING', 2);
 
 	// place for product file uploads (sort of "/system/images" but for all other files)
 	define('ITEM_FILES_PATH', WRITEBALE_BASE . '/downloads/');
 
 	// mailing list statuses
 	define('MAILING_LIST_NOT_PROCESSED', 1);
 	define('MAILING_LIST_PARTIALLY_PROCESSED', 2);
 	define('MAILING_LIST_PROCESSED', 3);
 	define('MAILING_LIST_CANCELLED', 4);
 
 	// theme file statuses (related to structure creation process)
 	define('SMS_MODE_AUTO', 1);
 	define('SMS_MODE_FORCE', 2);
 
 	/**
 	 * Means, that actual category Template field value should inherited from parent category
 	 *
 	 */
 	define('CATEGORY_TEMPLATE_INHERIT', '#inherit#');
 
 	define('REWRITE_MODE_BUILD', 1);
 	define('REWRITE_MODE_PARSE', 2);
Index: branches/5.0.x/core/kernel/processors/main_processor.php
===================================================================
--- branches/5.0.x/core/kernel/processors/main_processor.php	(revision 12297)
+++ branches/5.0.x/core/kernel/processors/main_processor.php	(revision 12298)
@@ -1,1158 +1,1159 @@
 <?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.net/license/ for copyright notices and details.
 */
 
 class kMainTagProcessor extends TagProcessor {
 
 	function Init($prefix, $special, $event_params = null)
 	{
 		parent::Init($prefix, $special, $event_params);
 
 		$actions =& $this->Application->recallObject('kActions');
 		$actions->Set('t', $this->Application->GetVar('t'));
 		$actions->Set('sid', $this->Application->GetSID());
 		$actions->Set('m_opener', $this->Application->GetVar('m_opener') );
 	}
 
 	/**
 	 * Used to handle calls where tag name
 	 * match with existing php function name
 	 *
 	 * @param Tag $tag
 	 * @return string
 	 */
 	function ProcessTag(&$tag)
 	{
 		if ($tag->Tag=='include') $tag->Tag='MyInclude';
 		return parent::ProcessTag($tag);
 	}
 
 	/**
 	 * Base folder for all template includes
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function TemplatesBase($params)
 	{
 		$force_admin = array_key_exists('force_admin', $params) && $params['force_admin'];
 		$module = array_key_exists('module', $params) ? $params['module'] : 'core';
 
 		if ($this->Application->IsAdmin() || $force_admin) {
 			if ($module == 'in-portal') {
 				$module = 'kernel';
 			}
 
 			$path = $force_admin ? '/core/admin_templates' : THEMES_PATH;
 			$path = preg_replace('/\/(.*?)\/(.*)/', $module.'/\\2', $path); // remove leading slash + substitute module
 		}
 		else {
 			$path = mb_substr(THEMES_PATH, 1);
 
 			if (mb_strtolower($module) == 'in-portal') {
 				$module_folder = 'platform';
 			}
 			else {
 				$module_folder = $this->Application->findModule('Name', $module, 'TemplatePath');
 			}
 
 			$path .= rtrim('/' . trim($module_folder, '/'), '/') . '/';
 		}
 
 		return $this->Application->BaseURL() . $path;
 	}
 
 	/**
 	 * Creates <base href ..> HTML tag for all templates
 	 * affects future css, js files and href params of links
 	 *
 	 * @return string
 	 * @access public
 	 */
 	function Base_Ref($params)
 	{
 		return '<base href="'.$this->TemplatesBase($params).'/" />';
 	}
 
 	/**
 	 * Returns base url for web-site
 	 *
 	 * @return string
 	 * @access public
 	 */
 	function BaseURL()
 	{
 		return $this->Application->BaseURL();
 	}
 
 	//for compatability with K3 tags
 	function Base($params)
 	{
 		return $this->TemplatesBase($params).'/';
 	}
 
 	function ProjectBase($params)
 	{
 		return $this->Application->BaseURL();
 	}
 
 	/*function Base($params)
 	{
 		return $this->Application->BaseURL().$params['add'];
 	}*/
 
 	/**
 	 * Used to create link to any template.
 	 * use "pass" paramter if "t" tag to specify
 	 * prefix & special of object to be represented
 	 * in resulting url
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function T($params)
 	{
 		//by default link to current template
 		$t = $this->SelectParam($params, 't,template');
 		unset($params['t']);
 		unset($params['template']);
 		$prefix=isset($params['prefix']) ? $params['prefix'] : ''; unset($params['prefix']);
 		$index_file = isset($params['index_file']) ? $params['index_file'] : null; unset($params['index_file']);
 
 		return $this->Application->HREF($t, $prefix, $params, $index_file);
 	}
 
 	function Link($params)
 	{
 		if (isset($params['template'])) {
 			$params['t'] = $params['template'];
 			unset($params['template']);
 		}
 		if (!isset($params['pass']) && !isset($params['no_pass'])) $params['pass'] = 'm';
 		if (isset($params['no_pass'])) unset($params['no_pass']);
 
 		if ( $this->Application->GetVar('admin') ) {
 			$params['admin'] = 1;
 
 			if (!array_key_exists('editing_mode', $params)) {
 				$params['editing_mode'] = EDITING_MODE;
 			}
 		}
 
 		return $this->T($params);
 	}
 
 	function Env($params)
 	{
 		$t = $params['template'];
 		unset($params['template']);
 		return $this->Application->BuildEnv($t, $params, 'm', null, false);
 	}
 
 	function FormAction($params)
 	{
 		$params['pass'] = 'all,m';
 		$params['pass_category'] = 1;
 
 		return $this->Application->HREF('', '', $params);
 	}
 
 	/*// NEEDS TEST
 	function Config($params)
 	{
 		return $this->Application->ConfigOption($params['var']);
 	}
 
 	function Object($params)
 	{
 		$name = $params['name'];
 		$method = $params['method'];
 
 		$tmp =& $this->Application->recallObject($name);
 		if ($tmp != null) {
 			if (method_exists($tmp, $method))
 				return $tmp->$method($params);
 			else
 				echo "Method $method does not exist in object ".get_class($tmp)." named $name<br>";
 		}
 		else
 			echo "Object $name does not exist in the appliaction<br>";
 	}*/
 
 	/**
 	 * Tag, that always returns true.
 	 * For parser testing purposes
 	 *
 	 * @param Array $params
 	 * @return bool
 	 * @access public
 	 */
 	function True($params)
 	{
 		return true;
 	}
 
 	/**
 	 * Tag, that always returns false.
 	 * For parser testing purposes
 	 *
 	 * @param Array $params
 	 * @return bool
 	 * @access public
 	 */
 	function False($params)
 	{
 		return false;
 	}
 
 	/**
 	 * Returns block parameter by name
 	 *
 	 * @param Array $params
 	 * @return stirng
 	 * @access public
 	 */
 	function Param($params)
 	{
 		//$parser =& $this->Application->recallObject('TemplateParser');
 		$name = $params['name'];
 		if (isset($this->Application->LateParsed[$name])) {
 			$f = $this->Application->PreParsedBlocks['capture_'.$name.$this->Application->LateParsed[$name]];
 			$this->Application->Parser->SetParam($name, $f(array()));
 		}
 
 		$res = $this->Application->Parser->GetParam($params['name']);
 		if ($res === false) $res = '';
 		if (isset($params['plus']))
 			$res += $params['plus'];
 		return $res;
 	}
 
 	function DefaultParam($params)
 	{
 		foreach ($params as $key => $val)	{
 			if ($this->Application->Parser->GetParam($key) === false) {
 				$this->Application->Parser->SetParam($key, $val);
 			}
 		}
 	}
 
 	/**
 	 * Gets value of specified field from specified prefix_special and set it as parser param
 	 *
 	 * @param Array $params
 	 */
 	/*function SetParam($params)
 	{
 		// <inp2:m_SetParam param="custom_name" src="cf:FieldName"/>
 		list($prefix_special, $field_name) = explode(':', $params['src']);
 
 		$object =& $this->Application->recallObject($prefix_special);
 		$name = $this->SelectParam($params, 'param,name,var');
 
 		$this->Application->Parser->SetParam($name, $object->GetField($field_name) );
 	}*/
 
 	/**
 	 * Compares block parameter with value specified
 	 *
 	 * @param Array $params
 	 * @return bool
 	 * @access public
 	 */
 	function ParamEquals($params)
 	{
 		//$parser =& $this->Application->recallObject('TemplateParser');
 		$name = $this->SelectParam($params, 'name,var,param');
 		$value = $params['value'];
 		return ($this->Application->Parser->GetParam($name) == $value);
 	}
 
 	/*function PHP_Self($params)
 	{
 		return $HTTP_SERVER_VARS['PHP_SELF'];
 	}
 	*/
 
 	/**
 	 * Returns session variable value by name
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function Recall($params)
 	{
 		$var_name = $this->SelectParam($params,'name,var,param');
 
 		if (isset($params['persistent']) && $params['persistent']) {
 			$ret = $this->Application->RecallPersistentVar($var_name);
 		}
 		else {
 			 $ret = $this->Application->RecallVar($var_name);
 		}
 
 		$ret = ($ret === false && isset($params['no_null'])) ? '' : $ret;
 		if (getArrayValue($params, 'special') || getArrayValue($params, 'htmlchars')) {
 			$ret = htmlspecialchars($ret);
 		}
 
 		if (getArrayValue($params, 'urlencode')) {
 			$ret = urlencode($ret);
 		}
 
 		return $ret;
 	}
 
 	function RemoveVar($params)
 	{
 		$this->Application->RemoveVar( $this->SelectParam($params,'name,var,param') );
 	}
 
 	// bad style to store something from template to session !!! (by Alex)
 	// Used here only to test how session works, nothing more
 	function Store($params)
 	{
 		//echo"Store $params[name]<br>";
 		$name = $params['name'];
 		$value = $params['value'];
 		$this->Application->StoreVar($name,$value);
 	}
 
 	/**
 	 * Sets application variable value(-s)
 	 *
 	 * @param Array $params
 	 * @access public
 	 */
 	function Set($params)
 	{
 		foreach ($params as $param => $value) {
 			$this->Application->SetVar($param, $value);
 		}
 	}
 
 	/**
 	 * Increment application variable
 	 * specified by number specified
 	 *
 	 * @param Array $params
 	 * @access public
 	 */
 	function Inc($params)
 	{
 		$this->Application->SetVar($params['param'], $this->Application->GetVar($params['param']) + $params['by']);
 	}
 
 	/**
 	 * Retrieves application variable
 	 * value by name
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function Get($params)
 	{
 		$ret = $this->Application->GetVar($this->SelectParam($params, 'name,var,param'), '');
 		return getArrayValue($params, 'htmlchars') ? htmlspecialchars($ret) : $ret;
 	}
 
 	/**
 	 * Retrieves application constant
 	 * value by name
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function GetConst($params)
 	{
 		return defined($this->SelectParam($params, 'name,const')) ? constant($this->SelectParam($params, 'name,const,param')) : '';
 	}
 
 	/**
 	 * Retrieves configuration variable value by name
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function GetConfig($params)
 	{
 		$config_name = $this->SelectParam($params, 'name,var');
 		$ret = $this->Application->ConfigValue($config_name);
 		if( getArrayValue($params, 'escape') ) $ret = addslashes($ret);
 		return $ret;
 	}
 
 	function ConfigEquals($params)
 	{
 		$option = $this->SelectParam($params, 'name,option,var');
 		return $this->Application->ConfigValue($option) == getArrayValue($params, 'value');
 	}
 
 	/**
 	 * Creates all hidden fields
 	 * needed for kernel_form
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function DumpSystemInfo($params)
 	{
 		$actions =& $this->Application->recallObject('kActions');
 		$actions->Set('t', $this->Application->GetVar('t') );
 
 		$params = $actions->GetParams();
 		$o='';
 		foreach ($params AS $name => $val)
 		{
 			$o .= "<input type='hidden' name='$name' id='$name' value='$val'>\n";
 		}
 		return $o;
 	}
 
 	/**
 	 * Used for search sidebox on front-end only
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @author Alex
 	 */
 	function GetFormHiddens($params)
 	{
 		$t = $this->SelectParam($params, 'template,t');
 		unset($params['template']);
 
 		$form_fields = Array ();
 		if ($this->Application->RewriteURLs()) {
 			$session =& $this->Application->recallObject('Session');
 			if ($session->NeedQueryString()) {
 				$form_fields['sid'] = $this->Application->GetSID();
 			}
 		}
 		else {
 			$form_fields['env'] = $this->Application->BuildEnv($t, $params, 'm', null, false);
 		}
 
 		if ($this->Application->GetVar('admin') == 1) {
 			$form_fields['admin'] = 1;
 		}
 
 		$ret = '';
 		$field_tpl = '<input type="hidden" name="%1$s" id="%1$s" value="%2$s"/>'."\n";
 		foreach ($form_fields as $form_field => $field_value) {
 			$ret .= sprintf($field_tpl, $form_field, $field_value);
 		}
 
 		return $ret;
 	}
 
 	function Odd_Even($params)
 	{
 		$odd = $params['odd'];
 		$even = $params['even'];
 		if (!isset($params['var'])) {
 			$var = 'odd_even';
 		}
 		else {
 			$var = $params['var'];
 		}
 
 		if ($this->Application->GetVar($var) == 'even') {
 			if (!isset($params['readonly']) || !$params['readonly']) {
 				$this->Application->SetVar($var, 'odd');
 			}
 			return $even;
 		}
 		else {
 			if (!isset($params['readonly']) || !$params['readonly']) {
 				$this->Application->SetVar($var, 'even');
 			}
 			return $odd;
 		}
 	}
 
 	/**
 	 * Returns phrase translation by name
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function Phrase($params)
 	{
 		// m:phrase name="phrase_name" default="Tr-alala" updated="2004-01-29 12:49"
 		$phrase_name = $this->SelectParam($params, 'label,name,title');
 		if (isset($params['source']) && $params['source']) {
 			$phrase_name = $this->Application->GetVar($phrase_name);
 			if (array_key_exists('default', $params) && !$phrase_name) {
 				$phrase_name = $params['default'];
 			}
 		}
 
-		$translation = $this->Application->Phrase($phrase_name);
+		$no_editing = array_key_exists('no_editing', $params) && $params['no_editing'];
+		$translation = $this->Application->Phrase($phrase_name, !$no_editing);
 
 		if (isset($params['escape']) && $params['escape']) {
 			$translation = htmlspecialchars($translation, ENT_QUOTES);
 			$translation = addslashes($translation);
 		}
 		return $translation;
 	}
 
 	// for tabs
 	function is_active($params)
 	{
 		$test_templ =  $this->SelectParam($params, 'templ,template,t');
 		if ( !getArrayValue($params,'allow_empty') )
 		{
 			$if_true=getArrayValue($params,'true') ? $params['true'] : 1;
 			$if_false=getArrayValue($params,'false') ? $params['false'] : 0;
 		}
 		else
 		{
 			$if_true=$params['true'];
 			$if_false=$params['false'];
 		}
 
 		if ( preg_match("/^".str_replace('/', '\/', $test_templ)."/i", $this->Application->GetVar('t'))) {
 			return $if_true;
 		}
 		else {
 			return $if_false;
 		}
 	}
 
 	function IsNotActive($params)
 	{
 		return !$this->is_active($params);
 	}
 
 	function IsActive($params)
 	{
 		return $this->is_active($params);
 	}
 
 	function is_t_active($params)
 	{
 		return $this->is_active($params);
 	}
 
 	function CurrentTemplate($params)
 	{
 		return $this->is_active($params);
 	}
 
 	/**
 	 * Checks if session variable
 	 * specified by name value match
 	 * value passed as parameter
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function RecallEquals($params)
 	{
 		$name = $this->SelectParam($params, 'name,var');
 		$value = $params['value'];
 
 		if (isset($params['persistent']) && $params['persistent']) {
 			return $this->Application->RecallPersistentVar($name) == $value;
 		}
 
 		return ($this->Application->RecallVar($name) == $value);
 	}
 
 	/**
 	 * Checks if application variable
 	 * specified by name value match
 	 * value passed as parameter
 	 *
 	 * @param Array $params
 	 * @return bool
 	 * @access public
 	 */
 	function GetEquals($params)
 	{
 		$name = $this->SelectParam($params, 'var,name,param');
 
 		$value = $params['value'];
 		if ($this->Application->GetVar($name) == $value) {
 			return 1;
 		}
 	}
 
 	/**
 	 * Includes template
 	 * and returns it's
 	 * parsed version
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function MyInclude($params)
 	{
 		if (defined('NPARSER') && NPARSER) {
 			return $this->Application->Parser->IncludeTemplate($params, isset($params['is_silent']) ? 1 : 0);
 		}
 
 		$BlockParser =& $this->Application->makeClass('TemplateParser');
 		/* @var $BlockParser TemplateParser */
 
 //		$BlockParser->SetParams($params);
 		$parser =& $this->Application->Parser;
 		$this->Application->Parser =& $BlockParser;
 
 		// this is for the parser to know the master template in case an error occurs,
 		// ParseTemplate will reset it anyway, but this will allow error handler to display the tempalte
 		// which tries to include missing template for example
 		$this->Application->Parser->TemplateName = $parser->TemplateName;
 
 		$t = $this->SelectParam($params, 't,template,block,name');
 		$t = eregi_replace("\.tpl$", '', $t);
 
 		if (!$t) {
 			trigger_error('Template name not specified in <b>&lt;inp2:m_include .../&gt;</b> tag', E_USER_ERROR);
 		}
 
 		if (isset($this->Application->PreParsedBlocks[$t]) ) {
 			$params['name'] = $t;
 			$res = $this->Application->ParseBlock($params);
 		}
 		else {
 			$res = $BlockParser->ParseTemplate($t, 1, $params, isset($params['is_silent']) ? 1 : 0 );
 		}
 
 		if (!$BlockParser->DataExists && ((isset($params['data_exists']) && $params['data_exists']) || isset($params['block_no_data']))) {
 			if ($block_no_data = getArrayValue($params, 'block_no_data')) {
 				if (isset($this->Application->PreParsedBlocks[$block_no_data]) ) {
 					// block_no_data is another block name
 					$res = $this->Application->ParseBlock(Array('name' => $block_no_data));
 				}
 				else {
 					// block_no_data is template name (only looks through real templates)
 					$res = $BlockParser->ParseTemplate($block_no_data, 1, Array(), getArrayValue($params, 'is_silent'));
 				}
 			}
 			else {
 				$res = '';
 			}
 		}
 
 		$this->Application->Parser =& $parser;
 		$this->Application->Parser->DataExists = $this->Application->Parser->DataExists || $BlockParser->DataExists;
 
 		if (isset($params['return_params']) && $params['return_params']) {
 			$new_params = array_merge($this->Application->Parser->Params, $BlockParser->ParamsStack[0]);
 			$this->Application->Parser->SetParams($new_params, false);
 		}
 
 		return $res;
 	}
 
 	function ModuleInclude($params)
 	{
 		$ret = '';
 		$block_params = array_merge($params, Array('is_silent' => 2)); // don't make fatal errors in case if template is missing
 		$current_template = $this->Application->GetVar('t');
 
 		$replace_main = isset($params['replace_m']) && $params['replace_m'];
 		$skip_prefixes = isset($params['skip_prefixes']) ? explode(',', $params['skip_prefixes']) : Array();
 		$cms_mode = $this->Application->GetVar('admin');
 
 		foreach ($this->Application->ModuleInfo as $module_name => $module_data) {
 			$module_key = mb_strtolower($module_name);
 
 			if ($module_name == 'In-Portal') {
 				if (!$cms_mode && $this->Application->IsAdmin()) {
 					// don't process In-Portal templates in admin
 					continue;
 				}
 
 				// Front-End still relies on In-Portal module
 				$module_prefix = $module_data['TemplatePath'];
 			}
 			else {
 				$module_prefix = $this->Application->IsAdmin() ? $module_key.'/' : rtrim($module_data['TemplatePath'], '/').'/';
 			}
 
 			$block_params['t'] = $module_prefix.$this->SelectParam($params, $module_key.'_template,'.$module_key.'_t,template,t');
 
 			$check_prefix = $module_data['Var'];
 
 			if ($check_prefix == 'adm' && $replace_main) {
 				$check_prefix = 'c';
 			}
 
 			if ($block_params['t'] == $current_template || in_array($check_prefix, $skip_prefixes)) {
 				continue;
 			}
 
 			$no_data = $this->SelectParam($params, $module_key.'_block_no_data,block_no_data');
 			if ($no_data) {
 				$block_params['block_no_data'] = $module_prefix.'/'.$no_data;
 			}
 			$ret .= $this->MyInclude($block_params);
 		}
 
 		return $ret;
 	}
 
 	function ModuleEnabled($params)
 	{
 		return $this->Application->isModuleEnabled( $params['module'] );
 	}
 
 	/*function Kernel_Scripts($params)
 	{
 		return '<script type="text/javascript" src="'.PROTOCOL.SERVER_NAME.BASE_PATH.'/kernel3/js/grid.js"></script>';
 	}*/
 
 
 	/*function GetUserPermission($params)
 	{
 		// echo"GetUserPermission $params[name]";
 		if ($this->Application->RecallVar('user_type') == 1)
 			return 1;
 		else {
 			$perm_name = $params[name];
 			$aPermissions = unserialize($this->Application->RecallVar('user_permissions'));
 			if ($aPermissions)
 				return $aPermissions[$perm_name];
 		}
 	}*/
 
 
 	/**
 	 * Set's parser block param value
 	 *
 	 * @param Array $params
 	 * @access public
 	 */
 	function AddParam($params)
 	{
 		$parser =& $this->Application->Parser; // recallObject('TemplateParser');
 		foreach ($params as $param => $value) {
 			$this->Application->SetVar($param, $value);
 			$parser->SetParam($param, $value);
 			$parser->AddParam('/\$'.$param.'/', $value);
 		}
 	}
 
 	/*function ParseToVar($params)
 	{
 		$var = $params['var'];
 		$tagdata = $params['tag'];
 		$parser =& $this->Application->Parser; //recallObject('TemplateParser');
 		$res = $this->Application->ProcessTag($tagdata);
 
 		$parser->SetParam($var, $res);
 		$parser->AddParam('/\$'.$var.'/', $res);
 		return '';
 	}*/
 
 	/*function TagNotEmpty($params)
 	{
 		$tagdata = $params['tag'];
 		$res = $this->Application->ProcessTag($tagdata);
 		return $res != '';
 	}*/
 
 	/*function TagEmpty($params)
 	{
 		return !$this->TagNotEmpty($params);
 	}*/
 
 	/**
 	 * Checks if debug mode is on
 	 *
 	 * @param Array $params
 	 * @return bool
 	 * @access public
 	 */
 	function IsDebugMode($params)
 	{
 		return $this->Application->isDebugMode();
 	}
 
 	function MassParse($params)
 	{
 		$qty = $params['qty'];
 		$block = $params['block'];
 		$mode = $params['mode'];
 
 		$o = '';
 		if ($mode == 'func') {
 			$func = create_function('$params', '
 					$o = \'<tr>\';
 					$o.= \'<td>a\'.$params[\'param1\'].\'</td>\';
 					$o.= \'<td>a\'.$params[\'param2\'].\'</td>\';
 					$o.= \'<td>a\'.$params[\'param3\'].\'</td>\';
 					$o.= \'<td>a\'.$params[\'param4\'].\'</td>\';
 					$o.= \'</tr>\';
 					return $o;
 				');
 			for ($i=1; $i<$qty; $i++) {
 				$block_params['param1'] = rand(1, 10000);
 				$block_params['param2'] = rand(1, 10000);
 				$block_params['param3'] = rand(1, 10000);
 				$block_params['param4'] = rand(1, 10000);
 				$o .= $func($block_params);
 			}
 			return $o;
 		}
 
 		$block_params['name'] = $block;
 
 		for ($i=0; $i<$qty; $i++) {
 			$block_params['param1'] = rand(1, 10000);
 			$block_params['param2'] = rand(1, 10000);
 			$block_params['param3'] = rand(1, 10000);
 			$block_params['param4'] = rand(1, 10000);
 			$block_params['passed'] = $params['passed'];
 			$block_params['prefix'] = 'm';
 
 			$o.= $this->Application->ParseBlock($block_params, 1);
 		}
 		return $o;
 	}
 
 	function LoggedIn($params)
 	{
 		return $this->Application->LoggedIn();
 	}
 
 	/**
 	 * Allows to check if permission exists directly in template and perform additional actions if required
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function CheckPermission($params)
 	{
 		$perm_helper =& $this->Application->recallObject('PermissionsHelper');
 		return $perm_helper->TagPermissionCheck($params);
 	}
 
 	/**
 	 * Checks if user is logged in and if not redirects it to template passed
 	 *
 	 * @param Array $params
 	 */
 	function RequireLogin($params)
 	{
 		$t = $this->Application->GetVar('t');
 		if ($next_t = getArrayValue($params, 'next_template')) {
 			$t = $next_t;
 		}
 
 		// check by permissions: begin
 		if ((isset($params['perm_event']) && $params['perm_event']) ||
 			(isset($params['perm_prefix']) && $params['perm_prefix']) ||
 			(isset($params['permissions']) && $params['permissions'])) {
 
 			$perm_helper =& $this->Application->recallObject('PermissionsHelper');
 			/* @var $perm_helper kPermissionsHelper */
 
 			$perm_status = $perm_helper->TagPermissionCheck($params);
 			if (!$perm_status) {
 				list($redirect_template, $redirect_params) = $perm_helper->getPermissionTemplate($params);
 				$this->Application->Redirect($redirect_template, $redirect_params);
 			}
 			else {
 				return ;
 			}
 		}
 		// check by permissions: end
 
 		// check by configuration value: begin
 		$condition = getArrayValue($params, 'condition');
 		if (!$condition) {
 			$condition = true;
 		}
 		else {
 			if (substr($condition, 0, 1) == '!') {
 				$condition = !$this->Application->ConfigValue(substr($condition, 1));
 			}
 			else {
 				$condition = $this->Application->ConfigValue($condition);
 			}
 		}
 		// check by configuration value: end
 
 		// check by belonging to group: begin
 		$group = $this->SelectParam($params, 'group');
 		$group_access = true;
 		if ($group) {
 			$conn =& $this->Application->GetADODBConnection();
 			$group_id = $conn->GetOne('SELECT GroupId FROM '.TABLE_PREFIX.'PortalGroup WHERE Name = '.$conn->qstr($group));
 			if ($group_id) {
 				$groups = explode(',', $this->Application->RecallVar('UserGroups'));
 				$group_access = in_array($group_id, $groups);
 			}
 		}
 		// check by belonging to group: end
 
 		if ((!$this->Application->LoggedIn() || !$group_access) && $condition) {
 			$redirect_params = $this->Application->HttpQuery->getRedirectParams(true);
 			$redirect_params['next_template'] = $t;
 
 			if (array_key_exists('pass_category', $params)) {
 				$redirect_params['pass_category'] = $params['pass_category'];
 			}
 
 			if ( $this->Application->LoggedIn() && !$group_access) {
 				$this->Application->Redirect( $params['no_group_perm_template'], $redirect_params);
 			}
 
 			$this->Application->Redirect($params['login_template'], $redirect_params);
 		}
 	}
 
 	function IsMember($params)
 	{
 		$group = getArrayValue($params, 'group');
 		$conn =& $this->Application->DB;
 		$group_id = $conn->GetOne('SELECT GroupId FROM '.TABLE_PREFIX.'PortalGroup WHERE Name = '.$conn->qstr($group));
 		if ($group_id) {
 			$groups = explode(',', $this->Application->RecallVar('UserGroups'));
 			$group_access = in_array($group_id, $groups);
 		}
 		return $group_access;
 	}
 
 	/**
 	 * Checks if SSL is on and redirects to SSL URL if needed
 	 * If SSL_URL is not defined in config - the tag does not do anything
 	 * If for_logged_in_only="1" exits if user is not logged in.
 	 * If called without params forces https right away. If called with by_config="1" checks the
 	 * Require SSL setting from General Config and if it is ON forces https
 	 *
 	 * @param unknown_type $params
 	 */
 	function CheckSSL($params)
 	{
 		$ssl = $this->Application->IsAdmin() ? $this->Application->ConfigValue('AdminSSL_URL') : false;
 
 		if (!$ssl) {
 			// not in admin or admin ssl url is empty
 			$ssl = $this->Application->ConfigValue('SSL_URL');
 		}
 
 		if (!$ssl) return; //SSL URL is not set - no way to require SSL
 
 		$require = false;
 
 		if (isset($params['mode']) && $params['mode'] == 'required') {
 			$require = true;
 			if (isset($params['for_logged_in_only']) && $params['for_logged_in_only'] && !$this->Application->LoggedIn()) {
 				$require = false;
 			}
 
 			if (isset($params['condition'])) {
 				if (!$this->Application->ConfigValue($params['condition'])) {
 					$require = false;
 				}
 			}
 		}
 
 		$http_query =& $this->Application->recallObject('HTTPQuery');
 		$pass = $http_query->getRedirectParams();
 
 		if ($require) {
 			if (PROTOCOL == 'https://') {
 				$this->Application->SetVar('__KEEP_SSL__', 1);
 				return;
 			}
 			$this->Application->Redirect('', array_merge_recursive2($pass, Array('__SSL__' => 1)));
 		}
 		else {
 			if (PROTOCOL == 'https://' && $this->Application->ConfigValue('Force_HTTP_When_SSL_Not_Required')) {
 				if ($this->Application->GetVar('__KEEP_SSL__')) return;
 				// $pass_more = Array ('pass' => 'm', 'm_cat_id' => 0, '__SSL__' => 0);
 				$this->Application->Redirect('', array_merge_recursive2($pass, Array('__SSL__' => 0))); // $pass_more
 			}
 		}
 	}
 
 	function ConstOn($params)
 	{
 		$name = $this->SelectParam($params,'name,const');
 		return constOn($name);
 	}
 
 	function SetDefaultCategory($params)
 	{
 		$category_id = $this->Application->findModule('Name', $params['module'], 'RootCat');
 		$this->Application->SetVar('m_cat_id', $category_id);
 	}
 
 	function XMLTemplate($params)
 	{
 		safeDefine('DBG_SKIP_REPORTING', 1);
 
 		if (isset($params['cache']) && $params['cache']) {
 			$nextyear = intval(date('Y') + 1);
 
 			$format = "D, d M Y H:i:s";
 			$expiration = gmdate($format, mktime() + $params['cache']).' GMT';
 			$last_modified = mktime();
 
 			header ('Cache-Control: public, cache, max-age='.$params['cache']);
 			header ("Expires: $expiration");
 			header ('Pragma: public');
 
 			// Getting headers sent by the client.
 			$headers = request_headers();
 
 			// Checking if the client is validating his cache and if it is current.
 			if (isset($headers['If-Modified-Since']) && (strtotime($headers['If-Modified-Since']) > $last_modified-$params['cache'])) {
 			   // Client's cache IS current, so we just respond '304 Not Modified'.
 			   header('Last-Modified: '.date($format, strtotime($headers['If-Modified-Since'])).' GMT', true, 304);
 			   exit();
 			} else {
 			   // Image not cached or cache outdated, we respond '200 OK' and output the image.
 			   header('Last-Modified: '.gmdate($format, $last_modified).' GMT', true, 200);
 			}
 		}
 
 		// xml documents are usually long
 		set_time_limit(0);
 		ini_set('memory_limit', -1);
 
 		return $this->Application->XMLHeader(getArrayValue($params, 'xml_version'));
 	}
 
 	function Header($params)
 	{
 		header($params['data']);
 	}
 
 	function NoDebug($params)
 	{
 		if (!$this->Application->GetVar('debug')) {
 			define('DBG_SKIP_REPORTING', 1);
 		}
 	}
 
 	function RootCategoryName($params)
 	{
 		$root_phrase = $this->Application->ConfigValue('Root_Name');
 		return $this->Application->Phrase($root_phrase);
 	}
 
 	/**
 	 * Allows to attach file directly from email event template
 	 *
 	 * @param Array $params
 	 */
 	function AttachFile($params)
 	{
 		$esender =& $application->recallObject('EmailSender'.(isset($params['special']) ? '.'.$params['special'] : ''));
 		/* @var $esender kEmailSendingHelper */
 
 		$path = FULL_PATH.'/'.$params['path'];
 		if (file_exists($path)) {
 			$esender->AddAttachment($path);
 		}
 	}
 
 	function CaptchaImage($params){
 		$captcha_helper =& $this->Application->recallObject('CaptchaHelper');
 		/* @var $captcha_helper kCaptchaHelper */
 		$captcha_helper->GenerateCaptchaImage(
 			$this->Application->RecallVar($this->Application->GetVar('var')),
 			$this->Application->GetVar('w'),
 			$this->Application->GetVar('h'),
 			true
 		);
 	}
 
 	function SID($params)
 	{
 		return $this->Application->GetSID();
 	}
 
 	function ModuleInfo($params)
 	{
 		return $this->Application->findModule($params['key'], $params['value'], $params['return']);
 	}
 
 	function Random($params)
 	{
 		return rand(1, 100000000);
 	}
 
 	/**
 	 * Prints parser params, available at current deep level
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function PrintCurrentParams($params)
 	{
 		$current_params = $this->Application->Parser->Params;
 
 		foreach ($current_params as $param_name => $param_value) {
 			$current_params[$param_name] = $param_name . ' = "' . $param_value . '"';
 		}
 
 		return '<pre>' . implode("\n", $current_params) . '</pre>';
 	}
 
 	/**
 	 * Gets previously defined counter result
 	 *
 	 * @param Array $params
 	 * @return int
 	 */
 	function GetCounter($params)
 	{
 		return $this->Application->getCounter($params['name'], $params);
 	}
 
 	/**
 	 * Increments PageHit counter
 	 *
 	 * @param Array $params
 	 * @return int
 	 */
 	function RegisterPageHit($params)
 	{
 		if ($this->Application->ConfigValue('UsePageHitCounter')) {
 			$db =& $this->Application->GetADODBConnection();
 
 			// get current counte
 			$sql = 'SELECT VariableValue
 					FROM '.TABLE_PREFIX.'ConfigurationValues
 					WHERE VariableName = "PageHitCounter"';
 			$page_counter = (int)$db->GetOne($sql);
 
 			$sql = 'UPDATE LOW_PRIORITY '.TABLE_PREFIX.'ConfigurationValues
 					SET VariableValue = '.($page_counter + 1).'
 					WHERE VariableName = "PageHitCounter"';
 			$db->Query($sql);
 		}
 	}
 
 	function Timestamp($params)
 	{
 		$format = isset($params['format']) ? $params['format'] : 'd.m.Y H:i:s';
 		return adodb_date($format);
 	}
 }
Index: branches/5.0.x/core/kernel/languages/phrases_cache.php
===================================================================
--- branches/5.0.x/core/kernel/languages/phrases_cache.php	(revision 12297)
+++ branches/5.0.x/core/kernel/languages/phrases_cache.php	(revision 12298)
@@ -1,282 +1,361 @@
 <?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.net/license/ for copyright notices and details.
 */
 
 class PhrasesCache extends kBase {
 
 	/**
 	* Connection to database
 	*
 	* @var kDBConnection
 	* @access public
 	*/
 	var $Conn;
 
 	var $Phrases = Array();
 	var $Ids = Array();
 	var $OriginalIds = Array(); //for comparing cache
 
 	var $LanguageId = null;
 
 	var $fromTag = false;
 
+	/**
+	 * Allows to edit existing phrases
+	 *
+	 * @var bool
+	 */
+	var $_editExisting = false;
+
+	/**
+	 * Allows to edit missing phrases
+	 *
+	 * @var bool
+	 */
+	var $_editMissing = false;
+
+	/**
+	 * Template, used for phrase adding/editing
+	 *
+	 * @var string
+	 */
+	var $_phraseEditTemplate = '';
+
+	/**
+	 * Use popup for phrase editing
+	 *
+	 * @var bool
+	 */
+	var $_usePopups = false;
+
+	/**
+	 * Use simplified form for phrase editing
+	 *
+	 * @var bool
+	 */
+	var $_simpleEditingMode = false;
+
+	/**
+	 * HTML tag used to translate phrases
+	 *
+	 * @var string
+	 */
+	var $_translateHtmlTag = 'a';
+
 	function PhrasesCache()
 	{
 		parent::kBase();
 		$this->Conn =& $this->Application->GetADODBConnection();
+
+		if (defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->IsAdmin()) {
+			// only has effect in admin, because on front-end phrases are translated in "Content Mode"
+			$this->_editMissing = defined('DBG_PHRASES') && DBG_PHRASES;
+		}
+
+		// now we use admin phrase editing template even on front-end
+		$this->_phraseEditTemplate = 'regional/phrases_edit';
+		$this->_usePopups = $this->Application->ConfigValue('UsePopups');
+	}
+
+	/**
+	 * Sets phrase editing mode, that corresponds current editing mode
+	 *
+	 */
+	function setPhraseEditing()
+	{
+		if (!$this->Application->IsAdmin() && (EDITING_MODE == EDITING_MODE_CONTENT)) {
+			$this->_editExisting = true;
+			$this->_editMissing = true;
+			$this->_simpleEditingMode = true;
+			$this->_translateHtmlTag = 'span';
+		}
 	}
 
 	function Init($prefix, $special = '')
 	{
 		if (constOn('IS_INSTALL')) {
 			$this->LanguageId = 1;
 		}
 		else {
 			if ($this->Application->IsAdmin()) {
 				$id_field = $this->Application->getUnitOption('lang', 'IDField');
 				$table_name = $this->Application->getUnitOption('lang', 'TableName');
 				$sql = 'SELECT '.$id_field.'
 						FROM '.$table_name.'
 						WHERE AdminInterfaceLang = 1';
 				$this->LanguageId = $this->Conn->GetOne($sql);
 			}
 			else {
 				$this->LanguageId = $this->Application->GetVar('m_lang');
 			}
 		}
 
 		if (isset($this->Application->Caches['PhraseList'])) {
 			$this->LoadPhrases( $this->Application->Caches['PhraseList'] );
 		}
 	}
 
 	function GetCachedIds()
 	{
-		$query = sprintf("SELECT PhraseList, ConfigVariables FROM %s WHERE Template = %s",
-											TABLE_PREFIX.'PhraseCache',
-											$this->Conn->Qstr(md5($this->Application->GetVar('t').$this->Application->GetVar('m_theme').$this->Application->GetVar('m_lang'))));
-		$res = $this->Conn->GetRow($query);
+		$cache_key = md5($this->Application->GetVar('t') . $this->Application->GetVar('m_theme') . $this->Application->GetVar('m_lang'));
+
+		$sql = 'SELECT PhraseList, ConfigVariables
+				FROM ' . TABLE_PREFIX . 'PhraseCache
+				WHERE Template = ' . $this->Conn->qstr($cache_key);
+		$res = $this->Conn->GetRow($sql);
 
 		if ($res && $res['ConfigVariables']) {
 			$this->Application->OriginalConfigCacheIds =  explode(',', $res['ConfigVariables']);
 			$this->Application->ConfigCacheIds = $this->Application->OriginalConfigCacheIds;
 		}
 
 		return ($res === false) ? Array() : explode(',', $res['PhraseList']);
 	}
 
 	function LoadPhrases($ids)
 	{
-		if ( !is_array($ids) || !implode('', $ids) ) return;
-		$query = sprintf("SELECT Translation,UPPER(Phrase) AS Phrase FROM %s WHERE LanguageId = %s AND PhraseId IN (%s)",
-											TABLE_PREFIX.'Phrase',
-											$this->LanguageId,
-											join(',', $ids));
-		$this->Phrases = $this->Conn->GetCol($query,'Phrase');
+		if ( !is_array($ids) || !implode('', $ids) ) {
+			return;
+		}
+
+		$sql = 'SELECT Translation, UPPER(Phrase) AS Phrase
+				FROM ' . TABLE_PREFIX . 'Phrase
+				WHERE (LanguageId = ' . $this->LanguageId . ') AND PhraseId IN (' . implode(',', $ids) . ')';
+		$this->Phrases = $this->Conn->GetCol($sql, 'Phrase');
+
 		/*foreach($phrases as $phrase => $tanslation)
 		{
 			$this->AddCachedPhrase(mb_strtoupper($phrase), $tanslation);
 		}*/
+
 		$this->Ids = $ids;
 		$this->OriginalIds = $ids;
 	}
 
 	function AddCachedPhrase($label, $value)
 	{
 		$label = mb_strtoupper($label);
 		$this->Phrases[$label] = $value;
 	}
 
 	function NeedsCacheUpdate()
 	{
 		return is_array($this->Ids) && count($this->Ids) > 0 && $this->Ids != $this->OriginalIds;
 	}
 
 	/**
 	 * Copy from Application->UpdateCache method
 	 *
 	 * @deprecated
 	 */
 	function UpdateCache()
 	{
 		$update = false;
 		//something changed
 		$update = $update || (is_array($this->Ids) && count($this->Ids) > 0 && $this->Ids != $this->OriginalIds);
 		$update = $update || (count($this->Application->ConfigCacheIds) && $this->Application->ConfigCacheIds != $this->Application->OriginalConfigCacheIds);
 		if ($update) {
 			$query = sprintf("REPLACE %s (PhraseList, CacheDate, Template, ConfigVariables)
 												VALUES (%s, %s, %s, %s)",
 												TABLE_PREFIX.'PhraseCache',
 												$this->Conn->Qstr(join(',', $this->Ids)),
 												adodb_mktime(),
 												$this->Conn->Qstr(md5($this->Application->GetVar('t').$this->Application->GetVar('m_theme').$this->Application->GetVar('m_lang'))),
 												$this->Conn->qstr(implode(',', array_unique($this->Application->ConfigCacheIds))));
 			$this->Conn->Query($query);
 		}
 	}
 
-	function GetPhrase($label)
+	function GetPhrase($label, $allow_editing = true)
 	{
-		if (!isset($this->LanguageId)) return 'impossible case';
-		//actually possible when custom field contains references to language labels and its being rebuilt in OnAfterConfigRead
-		//which is triggered by Sections rebuild, which in turn read all the configs and all of that happens BEFORE seeting the language...
+		if (!isset($this->LanguageId)) {
+			//actually possible when custom field contains references to language labels and its being rebuilt in OnAfterConfigRead
+			//which is triggered by Sections rebuild, which in turn read all the configs and all of that happens BEFORE seeting the language...
+			return 'impossible case';
+		}
 
-		if (ereg("^!.+!$", $label) > 0)
-		{
+		if (ereg("^!.+!$", $label) > 0) {
 			$label = substr($label, 1, -1); //cut exclamation marks
 		}
 
-		if( strlen($label) == 0 ) return '';
+		if (strlen($label) == 0) {
+			return '';
+		}
 
 		$original_label = $label;
 		$label = mb_strtoupper($label);
-		if(isset($this->Phrases[$label])) {
-			$translated_label = $this->Phrases[$label];
-			// debug mode is checked directly to improve performance
-			if (defined('DEBUG_MODE') && DEBUG_MODE && constOn('DBG_PHRASES_HIGHLIGHT')) {
-				if (!$this->Application->isDebugMode()) return $translated_label;
-
-				if ($this->Application->IsAdmin()) {
-					$sql = 'SELECT Module
-							FROM '.TABLE_PREFIX.'Phrase
-							WHERE (LanguageId = '.$this->LanguageId.') AND (Phrase = '.$this->Conn->qstr($label).')';
-					$this->Application->Debugger->appendHTML('Phrase: <b>'.$label.'</b>; Module: <b>'.$this->Conn->GetOne($sql).'</b>');
-//					$translated_label = $translated_label.' [m: '.$this->Conn->GetOne($sql).'; l: '.$label.']';
-				}
-				else {
-					// highlight text created via translated phrase (used to detect if text on screen is phrase or not)
-					$translated_label = '<span style="border: 1px solid #999999; background-color: #cccccc; color: #999999; ">'.$translated_label.'</span></a> <span style="color: red; background-color:#ffffcc">'.$original_label.'</span>';
-				}
 
-			}
+		if (array_key_exists($label, $this->Phrases)) {
+			$translated_label = $this->Phrases[$label];
 
-			if (defined('DEBUG_MODE') && DEBUG_MODE &&
-					(($this->Application->IsAdmin() && constOn('DBG_PHRASES_EDIT_ADMIN')) || (!$this->Application->IsAdmin() && constOn('DBG_PHRASES_EDIT_FRONT')) ) ) {
+			if ($this->_editExisting && $allow_editing) {
 				// option to change translation for Labels
-				list($edit_tpl, $index_file) = $this->Application->IsAdmin() ? Array('regional/phrases_edit', 'index.php') : Array('phrases_edit', 'index.php');
-
-				if ($this->Application->IsAdmin() && $this->Application->ConfigValue('UsePopups')) {
+				if ($this->_usePopups) {
 					// link to popup when using popups (only in admin)
-					$edit_url = 'javascript:translate_phrase(\''.addslashes($translated_label).'\', \''.$edit_tpl.'\');';
+					$edit_url = 'javascript:translate_phrase(\'' . addslashes($original_label) . '\', \'' . $this->_phraseEditTemplate . '\', {event: \'OnPrepareUpdate\', simple_mode: ' . ($this->_simpleEditingMode ? 'true' : 'false') . '});';
 				}
 				else {
 					// direct link, when not using popups OR on frontend
-					$edit_url = $this->Application->HREF($edit_tpl,'',Array('m_opener'=>'d','phrases_label'=>$original_label,'phrases_event'=>'OnPrepareUpdate', 'pass'=>'all,phrases'), $index_file );
+					$url_params = Array(
+						'm_opener' => 'd',
+						'phrases_label' => $original_label,
+						'phrases_event' => 'OnPrepareUpdate',
+						'simple_mode' => $this->_simpleEditingMode ? 1 : 0,
+						'pass' => 'all,phrases'
+					);
+
+					$edit_url = $this->Application->HREF($this->_phraseEditTemplate, '', $url_params, 'index.php');
+				}
+
+				$translated_label = '<' . $this->_translateHtmlTag . ' href="' . $edit_url . '" name="cms-translate-phrase" title="Edit translation">' . $translated_label . '</' . $this->_translateHtmlTag . '>';
+
+				if ($this->fromTag) {
+					$translated_label = $this->escapeTagReserved($translated_label);
 				}
-				$translated_label = '<a href="'.$edit_url.'">!'.$translated_label.'!</a>';
 			}
 
 			return $translated_label;
 		}
 
-		$this->LoadPhraseByLabel($label, $original_label);
+		$this->LoadPhraseByLabel($label, $original_label, $allow_editing);
+
 		return $this->GetPhrase($label);
 	}
 
-	function LoadPhraseByLabel($label, $original_label)
+	function LoadPhraseByLabel($label, $original_label, $allow_editing = true)
 	{
-		$query = sprintf("SELECT PhraseId, Translation FROM %s WHERE LanguageId = %s AND UPPER(Phrase) = UPPER(%s)",
-											TABLE_PREFIX.'Phrase',
-											$this->LanguageId,
-											$this->Conn->qstr($label));
-		$res = $this->Conn->GetRow($query);
-		if ($res === false || count($res) == 0)
-		{
-			$translation = '!'.$label.'!';
-			if($this->Application->isDebugMode() && constOn('DBG_PHRASES')) {
-				list($edit_tpl, $index_file) = $this->Application->IsAdmin() ? Array('regional/phrases_edit', 'index.php') : Array('phrases_edit', 'index.php');
+		$sql = 'SELECT PhraseId, Translation
+				FROM ' . TABLE_PREFIX . 'Phrase
+				WHERE (LanguageId = ' . $this->LanguageId . ') AND (UPPER(Phrase) = UPPER(' . $this->Conn->qstr($label) . '))';
+		$res = $this->Conn->GetRow($sql);
+
+		if ($res === false || count($res) == 0) {
+			$translation = '!' . $label . '!';
 
-				if ($this->Application->IsAdmin() && $this->Application->ConfigValue('UsePopups')) {
+			if ($this->_editMissing && $allow_editing) {
+				if ($this->_usePopups) {
 					// link to popup when using popups (only in admin)
-					$edit_url = 'javascript:translate_phrase(\''.addslashes($original_label).'\', \''.$edit_tpl.'\');';
+					$edit_url = 'javascript:translate_phrase(\'' . addslashes($original_label) . '\', \'' . $this->_phraseEditTemplate . '\', {event: \'OnNew\', simple_mode: ' . ($this->_simpleEditingMode ? 'true' : 'false') . '});';
 				}
 				else {
 					// direct link, when not using popups OR on frontend
-					$edit_url = $this->Application->HREF($edit_tpl,'',Array('m_opener'=>'d','phrases_label'=>$original_label,'phrases_event'=>'OnNew', 'pass'=>'all,phrases'), $index_file );
+					$url_params = Array (
+						'm_opener' => 'd',
+						'phrases_label' => $original_label,
+						'phrases_event' => 'OnNew',
+						'simple_mode' => $this->_simpleEditingMode ? 1 : 0,
+						'pass' => 'all,phrases'
+					);
+
+					$edit_url = $this->Application->HREF($this->_phraseEditTemplate, '', $url_params, 'index.php');
 				}
 
-				$translation = '<a href="'.$edit_url.'">!'.$label.'!</a>';
-				if($this->fromTag) $translation = $this->escapeTagReserved($translation);
+				$translation = '<' . $this->_translateHtmlTag . ' href="' . $edit_url . '" class="cms-translate-phrase" title="Translate">!' . $label . '!</' . $this->_translateHtmlTag . '>';
+
+				if ($this->fromTag) {
+					$translation = $this->escapeTagReserved($translation);
+				}
 			}
-			$this->AddCachedPhrase($label, $translation); //add it as already cached, as long as we dont need to cache not found phrase
+
+			// add it as already cached, as long as we dont need to cache not found phrase
+			$this->AddCachedPhrase($label, $translation);
+
 			return false;
 		}
 
 		$this->Phrases[$label] = $res['Translation'];
 		array_push($this->Ids, $res['PhraseId']);
 		$this->Ids = array_unique($this->Ids); //just to make sure
 		return true;
 	}
 
 	/**
 	 * Sort params by name and then by length
 	 *
 	 * @param string $a
 	 * @param string $b
 	 * @return int
 	 * @access private
 	 */
 	function CmpParams($a, $b)
 	{
 		$a_len = mb_strlen($a);
 		$b_len = mb_strlen($b);
 		if ($a_len == $b_len) return 0;
 		return $a_len > $b_len ? -1 : 1;
 	}
 
 	/**
 	 * Replace language tags in exclamation marks found in text
 	 *
 	 * @param string $text
 	 * @param bool $force_escape force escaping, not escaping of resulting string
 	 * @return string
 	 * @access public
 	 */
 	function ReplaceLanguageTags($text,$forse_escaping=null)
 	{
 		$this->fromTag = true;
 		if( isset($forse_escaping) ) $this->fromTag = $forse_escaping;
 		preg_match_all("(!(la|lu)[^!]+!)", $text, $res, PREG_PATTERN_ORDER);
 		$language_tags = $res[0];
 		uasort($language_tags, Array(&$this, 'CmpParams') );
 
 		$values = Array();
 		$i = 0;
 		foreach ($language_tags as $label) {
 			array_push($values, $this->GetPhrase($label) );
 			//array_push($values, $this->Application->Phrase($label) );
 			$language_tags[$i] = '/' . $language_tags[$i] . '/';
 			$i++;
 		}
 		$this->fromTag = false;
+
 		return preg_replace($language_tags, $values, $text);
 	}
 
 	/**
 	 * Escape chars in phrase translation, that could harm parser to process tag
 	 *
 	 * @param string $text
 	 * @return string
 	 * @access private
 	 */
 	function escapeTagReserved($text)
 	{
 		$reserved = Array('"',"'"); // =
 		$replacement = Array('\"',"\'"); // \=
 		return str_replace($reserved,$replacement,$text);
 	}
 
-}
-
-
-?>
\ No newline at end of file
+}
\ No newline at end of file
Index: branches/5.0.x/core/kernel/nparser/nparser.php
===================================================================
--- branches/5.0.x/core/kernel/nparser/nparser.php	(revision 12297)
+++ branches/5.0.x/core/kernel/nparser/nparser.php	(revision 12298)
@@ -1,879 +1,876 @@
 <?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.net/license/ for copyright notices and details.
 */
 
 include_once(KERNEL_PATH.'/nparser/ntags.php');
 
 define('TAG_NAMESPACE', 'inp2:');
 define('TAG_NAMESPACE_LENGTH', 5);
 
 class NParser extends kBase {
 
 	var $Stack = array();
 	var $Level = 0;
 
 	var $Buffers = array();
 	var $InsideComment = false;
 
 	var $Params = array();
 	var $ParamsStack = array();
 	var $ParamsLevel = 0;
 
 	var $Definitions = '';
 
 	var $Elements = array(); // holds dynamic elements to function names mapping during execution
 
 	/**
 	 * Holds location of element definitions inside templates.
 	 * key - element function name, value - array of 2 keys: {from_pos, to_pos}
 	 *
 	 * @var Array
 	 */
 	var $ElementLocations = Array ();
 
 	var $DataExists = false;
 
 	var $TemplateName = null;
 	var $TempalteFullPath = null;
 
 	var $CachePointers = array();
 	var $Cachable = array();
 
 	/**
 	 * Compress compiled templates
 	 *
 	 * @var bool
 	 */
 	var $_compressOutput = false;
 
 	function NParser()
 	{
 		parent::kBase();
 
 		$this->_compressOutput = $this->Application->ConfigValue('UseTemplateCompression');
 	}
 
 	function Compile($pre_parsed, $template_name = 'unknown')
 	{
 		$data = file_get_contents($pre_parsed['tname']);
 
 		if (!$this->CompileRaw($data, $pre_parsed['tname'], $template_name)) {
 			// compilation failed during errors in template
 //			trigger_error('Template "<strong>' . $template_name . '</strong>" not compiled because of errors', E_USER_WARNING);
 			return false;
 		}
 
 		// saving compiled version (only when compilation was successful)
 		if (defined('SAFE_MODE') && SAFE_MODE) { // store cache files in database since can't save on filesystem
 				if (!isset($conn)) $conn =& $this->Application->GetADODBConnection();
 				$conn->Query('REPLACE INTO '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ('.$conn->qstr($pre_parsed['fname']).','.$conn->qstr($this->Buffers[0]).','.adodb_mktime().')');
 		}
 		else {
 			$compiled = fopen($pre_parsed['fname'], 'w');
 
 			if ($this->_compressOutput) {
 				$this->Buffers[0] = $this->_compress($this->Buffers[0]);
 			}
 
 			if (!fwrite($compiled, $this->Buffers[0])) {
 				trigger_error('Saving compiled template failed', E_USER_ERROR);
 			}
 			fclose($compiled);
 		}
 
 		return true;
 	}
 
 	function Parse($raw_template, $name = null)
 	{
 		$this->CompileRaw($raw_template, $name);
 		ob_start();
 		$_parser =& $this;
 		eval('?'.'>'.$this->Buffers[0]);
 
 		return ob_get_clean();
 	}
 
 	function CompileRaw($data, $t_name, $template_name = 'unknown')
 	{
 		$code = "extract (\$_parser->Params);\n";
 		$code .= "\$_parser->ElementLocations['{$template_name}'] = Array('template' => '{$template_name}', 'start_pos' => 0, 'end_pos' => " . strlen($data) . ");\n";
 
 //		$code .= "__@@__DefinitionsMarker__@@__\n";
 
 //		$code .= "if (!\$this->CacheStart('".abs(crc32($t_name))."_0')) {\n";
 		$this->Buffers[0] = '<?'."php $code ?>\n";
 		$this->Cacheable[0] = true;
 		$this->Definitions = '';
 
 		// finding all the tags
 		$reg = '(.*?)(<[\\/]?)' . TAG_NAMESPACE . '([^>]*?)([\\/]?>)(\r\n){0,1}';
 		preg_match_all('/'.$reg.'/s', $data, $results, PREG_SET_ORDER + PREG_OFFSET_CAPTURE);
 
 		$this->InsideComment = false;
 		foreach ($results as $tag_data) {
 			$tag = array(
 				'opening' => $tag_data[2][0],
 				'tag' => $tag_data[3][0],
 				'closing' => $tag_data[4][0],
 				'line' => substr_count(substr($data, 0, $tag_data[2][1]), "\n")+1,
 				'pos' => $tag_data[2][1],
 				'file' => $t_name,
 				'template' => $template_name,
 			);
 
 			// the idea is to count number of comment openings and closings before current tag
 			// if the numbers do not match we inverse the status of InsideComment
 			if (substr_count($tag_data[1][0], '<!--') != substr_count($tag_data[1][0], '-->')) {
 				$this->InsideComment = !$this->InsideComment;
 			}
 
 			// appending any text/html data found before tag
 			$this->Buffers[$this->Level] .= $tag_data[1][0];
 			if (!$this->InsideComment) {
 				$tmp_tag = $this->Application->CurrentNTag;
 				$this->Application->CurrentNTag = $tag;
 				if ($this->ProcessTag($tag) === false) {
 					$this->Application->CurrentNTag = $tmp_tag;
 					return false;
 				}
 				$this->Application->CurrentNTag = $tmp_tag;
 			}
 			else {
 				$this->Buffers[$this->Level] .= $tag_data[2][0].$tag_data[3][0].$tag_data[4][0];
 			}
 		}
 
 		if ($this->Level > 0) {
 			$this->Application->handleError(E_USER_ERROR, 'Unclosed tag opened by '.$this->TagInfo($this->Stack[$this->Level]->Tag), $this->Stack[$this->Level]->Tag['file'], $this->Stack[$this->Level]->Tag['line']);
 			return false;
 		}
 
 		// appending text data after last tag (after its closing pos),
 		// if no tag was found at all ($tag_data is not set) - append the whole $data
 		$this->Buffers[$this->Level] .= isset($tag_data) ? substr($data, $tag_data[4][1]+strlen($tag_data[4][0])) : $data;
 		$this->Buffers[$this->Level] = preg_replace('/<!--##(.*?)##-->/s', '', $this->Buffers[$this->Level]); // remove hidden comments IB#23065
 //		$this->Buffers[$this->Level] .= '<?'.'php '."\n\$_parser->CacheEnd();\n}\n"." ?".">\n";
 //		$this->Buffers[$this->Level] = str_replace('__@@__DefinitionsMarker__@@__', $this->Definitions, $this->Buffers[$this->Level]);
 
 		return true;
 	}
 
 	function SplitParamsStr($params_str)
 	{
 		preg_match_all('/([\${}a-zA-Z0-9_.\\-\\\\#\\[\\]]+)=(["\']{1,1})(.*?)(?<!\\\)\\2/s', $params_str, $rets, PREG_SET_ORDER);
 
 		$values = Array();
 
 		// we need to replace all occurences of any current param $key with {$key} for correct variable substitution
 		foreach ($rets AS $key => $val){
 			$values[$val[1]] = str_replace('\\' . $val[2], $val[2], $val[3]);
 		}
 
 		return $values;
 	}
 
 	function SplitTag($tag)
 	{
 		if (!preg_match('/([^_ \t\r\n]*)[_]?([^ \t\r\n]*)[ \t\r\n]*(.*)$$/s', $tag['tag'], $parts)) {
 			// this is virtually impossible, but just in case
 			$this->Application->handleError(E_USER_ERROR, 'Incorrect tag format: '.$tag['tag'], $tag['file'], $tag['line']);
 			return false;
 		}
 
 		$splited['prefix'] = $parts[2] ? $parts[1] : '__auto__';
 		$splited['name'] = $parts[2] ? $parts[2] : $parts[1];
 		$splited['attrs'] = $parts[3];
 
 		return $splited;
 	}
 
 	function ProcessTag($tag)
 	{
 		$splited = $this->SplitTag($tag);
 		if ($splited === false) {
 			return false;
 		}
 
 		$tag = array_merge($tag, $splited);
 		$tag['processed'] = false;
 		$tag['NP'] = $this->SplitParamsStr($tag['attrs']);
 
 		$o = '';
 		$tag['is_closing'] = $tag['opening'] == '</' || $tag['closing'] == '/>';
 		if (class_exists('_Tag_'.$tag['name'])) { // block tags should have special handling class
 			if ($tag['opening'] == '<') {
 				$class = '_Tag_'.$tag['name'];
 				$instance = new $class($tag);
 				$instance->Parser =& $this;
 				/* @var $instance _BlockTag */
 				$this->Stack[++$this->Level] =& $instance;
 				$this->Buffers[$this->Level] = '';
 				$this->Cachable[$this->Level] = true;
 				$open_code = $instance->Open($tag);
 				if ($open_code === false) {
 					return false;
 				}
 				$o .= $open_code;
 			}
 
 			if ($tag['is_closing']) { // not ELSE here, because tag may be <empty/> and still has a handler-class
 				if ($this->Level == 0) {
 					$dump = array();
 					foreach ($this->Stack as $instance) {
 						$dump[] = $instance->Tag;
 					}
 					print_pre($dump);
 					$this->Application->handleError(E_USER_ERROR, 'Closing tag without an opening: '.$this->TagInfo($tag).' <b> - probably opening tag was removed or nested tags error</b>', $tag['file'], $tag['line']);
 					return false;
 				}
 				if ($this->Stack[$this->Level]->Tag['name'] != $tag['name']) {
 					$opening_tag = $this->Stack[$this->Level]->Tag;
 					$this->Application->handleError(E_USER_ERROR,
 					    'Closing tag '.$this->TagInfo($tag).' does not match
 							 opening tag at current nesting level ('.$this->TagInfo($opening_tag).'
 							 opened at line '.$opening_tag['line'].')', $tag['file'], $tag['line']);
 					return false;
 				}
 
 				$o .= $this->Stack[$this->Level]->Close($tag); // DO NOT use $this->Level-- here because it's used inside Close
 				$this->Level--;
 			}
 		}
 		else { // regular tags - just compile
 			if (!$tag['is_closing']) {
 				$this->Application->handleError(E_USER_ERROR, 'Tag without a handler: '.$this->TagInfo($tag).' <b> - probably missing &lt;empty <span style="color: red">/</span>&gt; tag closing</b>', $tag['file'], $tag['line']);
 				return false;
 			}
 
 			if ($this->Level > 0) $o .= $this->Stack[$this->Level]->PassThrough($tag);
 			if (!$tag['processed']) {
 				$compiled = $this->CompileTag($tag);
 				if ($compiled === false) return false;
 				if (isset($tag['NP']['cachable']) && (!$tag['NP']['cachable'] || $tag['NP']['cachable'] ==  'false')) {
 					$this->Cachable[$this->Level] = false;
 				}
 				$o .= '<?'.'php ' . $compiled . " ?>\n";
 //				$o .= '<?'.'php ';
 //				$o .= (isset($tag['NP']['cachable']) && (!$tag['NP']['cachable'] || $tag['NP']['cachable'] ==  'false')) ? $this->BreakCache($compiled, $this->GetPointer($tag)) : $compiled;
 //				$o .= " ?".">\n";
 			}
 		}
 		$this->Buffers[$this->Level] .= $o;
 		return true;
 	}
 
 	function GetPointer($tag)
 	{
 		return abs(crc32($tag['file'])).'_'.$tag['line'];
 	}
 
 	function BreakCache($code, $pointer, $condition='')
 	{
 		return "\$_parser->CacheEnd();\n}\n" . $code."\nif ( !\$_parser->CacheStart('{$pointer}'" . ($condition ? ", {$condition}" : '') . ") ) {\n";
 	}
 
 	function TagInfo($tag, $with_params=false)
 	{
 		return "<b>{$tag['prefix']}_{$tag['name']}".($with_params ? ' '.$tag['attrs'] : '')."</b>";
 	}
 
 	function CompileParamsArray($arr)
 	{
 		$to_pass = 'Array(';
 		foreach ($arr as $name => $val) {
 			$to_pass .= '"'.$name.'" => "'.str_replace('"', '\"', $val).'",';
 		}
 		$to_pass .= ')';
 		return $to_pass;
 	}
 
 	function CompileTag($tag)
 	{
 		$to_pass = $this->CompileParamsArray($tag['NP']);
 
 		$code = '';
 		if ($tag['prefix'] == '__auto__') {
 			$prefix = $this->GetParam('PrefixSpecial');
 			$code .= '$_p_ =& $_parser->GetProcessor($PrefixSpecial);'."\n";
 			$code .= 'echo $_p_->ProcessParsedTag(\''.$tag['name'].'\', '.$to_pass.', "$PrefixSpecial", \''.$tag['file'].'\', '.$tag['line'].');'."\n";
 		}
 		else {
 			$prefix = $tag['prefix'];
 			$code .= '$_p_ =& $_parser->GetProcessor("'.$tag['prefix'].'");'."\n";
 			$code .= 'echo $_p_->ProcessParsedTag(\''.$tag['name'].'\', '.$to_pass.', "'.$tag['prefix'].'", \''.$tag['file'].'\', '.$tag['line'].');'."\n";
 		}
 		if (isset($tag['NP']['result_to_var'])) {
 			$code .= "\$params['{$tag['NP']['result_to_var']}'] = \$_parser->GetParam('{$tag['NP']['result_to_var']}');\n";
 			$code .= "\${$tag['NP']['result_to_var']} = \$params['{$tag['NP']['result_to_var']}'];\n";
 		}
 		if ($prefix && strpos($prefix, '$') === false) {
 			$p =& $this->GetProcessor($prefix);
 			if (!is_object($p) || !$p->CheckTag($tag['name'], $tag['prefix'])) {
 				$this->Application->handleError(E_USER_ERROR, 'Unknown tag: '.$this->TagInfo($tag).' <b> - incorrect tag name or prefix </b>', $tag['file'], $tag['line']);
 				return false;
 			}
 		}
 		return $code;
 	}
 
 	function CheckTemplate($t, $silent=null)
 	{
 		$pre_parsed = $this->Application->TemplatesCache->GetPreParsed($t);
 		if (!$pre_parsed) {
 			if (!$silent) {
 				if ($this->Application->isDebugMode()) $this->Application->Debugger->appendTrace();
 				trigger_error('Cannot include "<strong>' . $t . '</strong>" - file does not exist', E_USER_ERROR);
 			}
 			return false;
 		}
 
 		$force_compile = defined('DBG_NPARSER_FORCE_COMPILE') && DBG_NPARSER_FORCE_COMPILE;
 		if (!$pre_parsed || !$pre_parsed['active'] || $force_compile) {
 			$inc_parser = new NParser();
 
 			if ($force_compile) {
 				// remove Front-End theme markings during total compilation
 				$t = preg_replace('/^theme:.*?\//', '', $t);
 			}
 
 			if (!$inc_parser->Compile($pre_parsed, $t)) return false;
 		}
 		return $pre_parsed;
 	}
 
 	function Run($t, $silent=null)
 	{
 		if ((strpos($t, '../') !== false) || (trim($t) !== $t)) {
 			// when relative paths or special chars are found template names from url, then it's hacking attempt
 			return false;
 		}
 
 		$pre_parsed = $this->CheckTemplate($t, $silent);
 		if (!$pre_parsed) return false;
 		$backup_template = $this->TemplateName;
 		$backup_fullpath = $this->TempalteFullPath;
 		$this->TemplateName = $t;
 		$this->TempalteFullPath = $pre_parsed['tname'];
 
 		ob_start();
 		$_parser =& $this;
 		if (defined('SAFE_MODE') && SAFE_MODE) { // read cache files from database since can't save on filesystem
 			$conn =& $this->Application->GetADODBConnection();
 			$cached = $conn->GetRow('SELECT * FROM '.TABLE_PREFIX.'Cache WHERE VarName = "'.$pre_parsed['fname'].'"');
 			if ($cached !== false && $cached['Cached'] > filemtime($pre_parsed['tname'])) {
 				eval('?'.'>'.$cached['Data']);
 			}
 		}
 		else {
 			if ($pre_parsed['mode'] == 'file') {
 				include($pre_parsed['fname']);
 			}
 			else {
 				eval('?'.'>'.$pre_parsed['content']);
 			}
 		}
 		$output = ob_get_contents();
 		ob_end_clean();
 
 		$this->TemplateName = $backup_template;
 		$this->TempalteFullPath = $backup_fullpath;
 
 		return $output;
 	}
 
 	function &GetProcessor($prefix)
 	{
 		static $Processors = array();
 		if (!isset($Processors[$prefix])) {
 			$Processors[$prefix] = $this->Application->recallObject($prefix.'_TagProcessor');
 		}
 
 		return $Processors[$prefix];
 	}
 
 	function SelectParam($params, $possible_names)
 	{
 		if (!is_array($params)) return;
 		if (!is_array($possible_names))
 
 		$possible_names = explode(',', $possible_names);
 		foreach ($possible_names as $name)
 		{
 			if( isset($params[$name]) ) return $params[$name];
 		}
 		return false;
 	}
 
 	function SetParams($params)
 	{
 		$this->Params = $params;
 		$keys = array_keys($this->Params);
 	}
 
 	function GetParam($name)
 	{
 		return isset($this->Params[$name]) ? $this->Params[$name] : false;
 	}
 
 	function SetParam($name, $value)
 	{
 		$this->Params[$name] = $value;
 	}
 
 	function PushParams($params)
 	{
 		$this->ParamsStack[$this->ParamsLevel++] = $this->Params;
 		$this->Params = $params;
 	}
 
 	function PopParams()
 	{
 		$this->Params = $this->ParamsStack[--$this->ParamsLevel];
 	}
 
 	function ParseBlock($params, $pass_params=false)
 	{
 		if (isset($params['cache_timeout']) && ($ret = $this->CacheGet($this->FormCacheKey('element_'.$params['name'])))) {
 			return $ret;
 		}
 
 		if (substr($params['name'], 0, 5) == 'html:') {
 			return substr($params['name'], 6);
 		}
 
 		if (!array_key_exists($params['name'], $this->Elements) && array_key_exists('default_element', $params)) {
 			// when given element not found, but default element name given, then render it instead
 			$params['name'] = $params['default_element'];
 			unset($params['default_element']);
 			return $this->ParseBlock($params, $pass_params);
 		}
 
 		$original_params = $params;
 
 		if ($pass_params || isset($params['pass_params'])) $params = array_merge($this->Params, $params);
 		$this->PushParams($params);
 		$data_exists_bak = $this->DataExists;
 
 		// if we are parsing design block and we have block_no_data - we need to wrap block_no_data into design,
 		// so we should set DataExists to true manually, otherwise the design block will be skipped because of data_exists in params (by Kostja)
 		//
 		// keep_data_exists is used by block RenderElement (always added in ntags.php), to keep the DataExists value
 		// from inside-content block, otherwise when parsing the design block DataExists will be reset to false resulting missing design block (by Kostja)
 		//
 		// Inside-content block parsing result is given to design block in "content" parameter (ntags.php) and "keep_data_exists"
 		// is only passed, when parsing design block. In case, when $this->DataExists is set to true, but
 		// zero-length content (in 2 cases: method NParser::CheckNoData set it OR really empty block content)
 		// is returned from inside-content block, then design block also should not be shown (by Alex)
 		$this->DataExists = (isset($params['keep_data_exists']) && isset($params['content']) && $params['content'] != '' && $this->DataExists) || (isset($params['design']) && isset($params['block_no_data']) && $params['name'] == $params['design']);
 
 		if (!array_key_exists($params['name'], $this->Elements)) {
 			$pre_parsed = $this->Application->TemplatesCache->GetPreParsed($params['name']);
 			if ($pre_parsed) {
 				$ret = $this->IncludeTemplate($params);
 
 				if (array_key_exists('no_editing', $params) && $params['no_editing']) {
 					// when individual render element don't want to be edited
 					return $ret;
 				}
 
 				return defined('EDITING_MODE') ? $this->DecorateBlock($ret, $params, true) : $ret;
 			}
 
 			if ($this->Application->isDebugMode()) {
 				$this->Application->Debugger->appendTrace();
 			}
 			$trace_results = debug_backtrace();
 			$this->Application->handleError(E_USER_ERROR, '<b>Rendering of undefined element '.$params['name'].'</b>', $trace_results[0]['file'], $trace_results[0]['line']);
 			return false;
 		}
 
 		$m_processor =& $this->GetProcessor('m');
 		$flag_values = $m_processor->PreparePostProcess($params);
 
 		$f_name = $this->Elements[$params['name']];
 		$ret = $f_name($this, $params);
 		$ret = $m_processor->PostProcess($ret, $flag_values);
 		$block_params = $this->Params; // input parameters, but modified inside rendered block
 		$this->PopParams();
 
 		$this->CheckNoData($ret, $params);
 
 		$this->DataExists = $data_exists_bak || $this->DataExists;
 
 		if (isset($original_params['cache_timeout'])) {
 			$this->CacheSet($this->FormCacheKey('element_'.$original_params['name']), $ret, $original_params['cache_timeout']);
 		}
 
 		if (array_key_exists('no_editing', $block_params) && $block_params['no_editing']) {
 			// when individual render element don't want to be edited
 			return $ret;
 		}
 
 		return defined('EDITING_MODE') ? $this->DecorateBlock($ret, $params) : $ret;
 	}
 
 	function DecorateBlock($block_content, $block_params, $is_template = false)
 	{
 		static $used_ids = Array (), $base_url = null;
 
 		if (!isset($base_url)) {
 			$base_url = $this->Application->BaseURL();
 		}
 
 //		$prepend = '[name: ' . $block_params['name'] . '] [params: ' . implode(', ', array_keys($block_params)) . ']';
 
 		$decorate = false;
+		$design = false;
 
-		if ($is_template) {
-			// content inside pair RenderElement tag
-//			$prepend = '<strong>CONTENT_OF_DESIGN:</strong> ' . $prepend;
+		if (EDITING_MODE == EDITING_MODE_DESIGN) {
+			$decorate = true;
 
-			if (EDITING_MODE == EDITING_MODE_INSIDES) {
-				$decorate = true;
-			}
-		}
-		else {
-			if (strpos($block_params['name'], '__capture_') === 0) {
-				// capture tag (usually inside pair RenderElement)
-//				$prepend = '<strong>CAPTURE:</strong> ' . $prepend;
-
-				if (EDITING_MODE == EDITING_MODE_INSIDES) {
-					$decorate = true;
-				}
-			}
-			elseif (array_key_exists('content', $block_params)) {
-				// pair RenderElement (on template, were it's used)
-//				$prepend = '<strong>PAIR_RENDER_ELEMENT:</strong> ' . $prepend;
-
-				if (EDITING_MODE == EDITING_MODE_DESIGN) {
-					$decorate = true;
-				}
+			if ($is_template) {
+				// content inside pair RenderElement tag
 			}
 			else {
-				// non-pair RenderElement
-//				$prepend = '<strong>SINGLE_RENDER_ELEMENT:</strong> ' . $prepend;
-
-				if (EDITING_MODE == EDITING_MODE_INSIDES) {
-					$decorate = true;
+				if (strpos($block_params['name'], '__capture_') === 0) {
+					// capture tag (usually inside pair RenderElement)
 				}
-
-				if (array_key_exists('layout_view', $block_params) && $block_params['layout_view'] && (EDITING_MODE == EDITING_MODE_LAYOUT)) {
-					$decorate = true;
+				elseif (array_key_exists('content', $block_params)) {
+					// pair RenderElement (on template, were it's used)
+					$design = true;
 				}
 			}
 		}
 
 		if (!$decorate) {
 			return $block_content;
 		}
 		else {
 			$block_content = /*$prepend .*/ $block_content;
 		}
 
 		$block_name = $block_params['name'];
 		$function_name = $is_template ? $block_name : $this->Elements[$block_name];
 
+		$block_title = '';
+		if (array_key_exists($function_name, $this->Application->Parser->ElementLocations)) {
+			$element_location = $this->Application->Parser->ElementLocations[$function_name];
+
+			$block_title .= $element_location['template'] . '.tpl';
+			$block_title .= ' (' . $element_location['start_pos'] . ' - ' . $element_location['end_pos'] . ')';
+		}
+
 		// ensure unique id for every div (used from print lists)
 		$container_num = 1;
 		$container_id = 'parser_block[' . $function_name . ']';
 		while (in_array($container_id . '_' . $container_num, $used_ids)) {
 			$container_num++;
 		}
 
 		$container_id .= '_' . $container_num;
 		$used_ids[] = $container_id;
 
 		// prepare parameter string
 		$param_string = $block_name . ':' . $function_name;
 
+		if ($design) {
+			$btn_text = 'Edit design';
+			$btn_class = 'cms-edit-design-btn';
+			$btn_container_class = 'block-edit-design-btn-container';
+		}
+		else {
+			$btn_text = 'Edit block';
+			$btn_class = 'cms-edit-block-btn';
+			$btn_container_class = 'block-edit-block-btn-container';
+		}
 
 		$block_editor = '
-			<div id="' . $container_id . '" params="' . $param_string . '" class="block-edit-btn-container">
-				<div class="cms-edit-btn">
+			<div id="' . $container_id . '" params="' . $param_string . '" class="' . $btn_container_class . '" title="' . htmlspecialchars($block_title) . '">
+				<div class="' . $btn_class . '">
 					<div class="cms-btn-image">
 						<img src="' . $base_url . 'core/admin_templates/img/top_frame/icons/content_mode.gif" width="15" height="16" alt=""/>
 					</div>
-					<div class="cms-btn-text" id="' . $container_id . '_btn">Edit</div>
+					<div class="cms-btn-text" id="' . $container_id . '_btn">' . $btn_text . '</div>
 				</div>
 				<div class="cms-btn-content">
 					%s
 				</div>
 			</div>';
 
 		// 1 - text before, 2 - open tag, 3 - open tag attributes, 4 - content inside tag, 5 - closing tag, 6 - text after closing tag
 		if (preg_match('/^(\s*)<(td|span)(.*?)>(.*)<\/(td|span)>(.*)$/is', $block_content, $regs)) {
 			// div inside span -> put div outside span
 			return $regs[1] . '<' . $regs[2] . ' ' . $regs[3] . '>' . str_replace('%s', $regs[4], $block_editor) . '</' . $regs[5] . '>' . $regs[6];
 		}
 
 		return str_replace('%s', $block_content, $block_editor);
 	}
 
 	function IncludeTemplate($params, $silent=null)
 	{
 		$t = is_array($params) ? $this->SelectParam($params, 't,template,block,name') : $params;
 
 		if (isset($params['cache_timeout']) && ($ret = $this->CacheGet('template:'.$t))) {
 			return $ret;
 		}
 
 		$t = eregi_replace("\.tpl$", '', $t);
 		$data_exists_bak = $this->DataExists;
 		$this->DataExists = false;
 
 		if (!isset($silent) && array_key_exists('is_silent', $params)) {
 			$silent = $params['is_silent'];
 		}
 
 		if (isset($params['pass_params'])) {
 			// ability to pass params from block to template
 			$params = array_merge($this->Params, $params);
 		}
 
 		$this->PushParams($params);
 		$ret = $this->Run($t, $silent);
 		$this->PopParams();
 
 		$this->CheckNoData($ret, $params);
 		$this->DataExists = $data_exists_bak || $this->DataExists;
 
 		if (isset($params['cache_timeout'])) {
 			$this->CacheSet('template:'.$t, $ret, $params['cache_timeout']);
 		}
 
 		return $ret;
 	}
 
 	function CheckNoData(&$ret, $params)
 	{
 		if (array_key_exists('data_exists', $params) && $params['data_exists'] && !$this->DataExists) {
 			$block_no_data = isset($params['BlockNoData']) ? $params['BlockNoData'] : (isset($params['block_no_data']) ? $params['block_no_data'] : false);
 			if ($block_no_data)	{
 				$ret = $this->ParseBlock(array('name'=>$block_no_data));
 			}
 			else {
 				$ret = '';
 			}
 		}
 	}
 
 	function CacheGet($name)
 	{
 		if (!$this->Application->ConfigValue('SystemTagCache')) return false;
 		return $this->Application->CacheGet($name);
 	}
 
 	function CacheSet($name, $value, $expiration=0)
 	{
 		if (!$this->Application->ConfigValue('SystemTagCache')) return false;
 		return $this->Application->CacheSet($name, $value, $expiration);
 	}
 
 	function FormCacheKey($element, $file=null, $add_prefixes=null)
 	{
 		if (!isset($file)) {
 			$file = str_replace(FULL_PATH, '', $this->TempalteFullPath).':'.$this->Application->GetVar('t');
 		}
 		$parts = array(
 			'file_'.$file.'('.filemtime($this->TempalteFullPath).')' => 'serials:file_ts', // theme + template timestamp
 			'm_lang_'.$this->Application->GetVar('m_lang') => 'serials:lang_ts',
 			'm_cat_id_'.$this->Application->GetVar('m_cat_id') => 'serials:cat_'.$this->Application->GetVar('m_cat_id').'_ts',
 			'm_cat_page'.$this->Application->GetVar('m_cat_page') => false,
 		);
 		if (isset($add_prefixes)) {
 			foreach ($add_prefixes as $prefix) {
 				$parts[$prefix.'_id_'.$this->Application->GetVar("{$prefix}_id")] = "serials:$prefix_".$this->Application->GetVar("{$prefix}_id").'_ts';
 				$parts[$prefix.'_page_'.$this->Application->GetVar("{$prefix}_Page")] = false;
 			}
 		}
 		$key = '';
 		foreach ($parts as $part => $ts_name) {
 			if ($ts_name) {
 				$ts = $this->Application->CacheGet($ts_name);
 				$key .= "$part($ts):";
 			}
 			else {
 				$key .= "$part:";
 			}
 		}
 		$key .= $element;
 
 		return crc32($key);
 	}
 
 	function PushPointer($pointer)
 	{
 		$this->CachePointers[++$this->CacheLevel] = $this->FormCacheKey('pointer:'.$pointer);
 		return $this->CachePointers[$this->CacheLevel];
 	}
 
 	function PopPointer()
 	{
 		return $this->CachePointers[$this->CacheLevel--];
 	}
 
 	function CacheStart($pointer=null)
 	{
 		if ($ret = $this->CacheGet($this->PushPointer($pointer)) ) {
 			echo $ret;
 			$this->PopPointer();
 			return true;
 		}
 		ob_start();
 		return false;
 	}
 
 	function CacheEnd($elem=null)
 	{
 		$ret = ob_get_clean();
 		$this->CacheSet($this->PopPointer(), $ret); // . ($this->CurrentKeyPart ? ':'.$this->CurrentKeyPart : '')
 		echo $ret;
 	}
 
 	function _compress($src) {
 		// Whitespaces left and right from this signs can be ignored
 		static $IW = array(
 			T_CONCAT_EQUAL,             // .=
 			T_DOUBLE_ARROW,             // =>
 			T_BOOLEAN_AND,              // &&
 			T_BOOLEAN_OR,               // ||
 			T_IS_EQUAL,                 // ==
 			T_IS_NOT_EQUAL,             // != or <>
 			T_IS_SMALLER_OR_EQUAL,      // <=
 			T_IS_GREATER_OR_EQUAL,      // >=
 			T_INC,                      // ++
 			T_DEC,                      // --
 			T_PLUS_EQUAL,               // +=
 			T_MINUS_EQUAL,              // -=
 			T_MUL_EQUAL,                // *=
 			T_DIV_EQUAL,                // /=
 			T_IS_IDENTICAL,             // ===
 			T_IS_NOT_IDENTICAL,         // !==
 			T_DOUBLE_COLON,             // ::
 			T_PAAMAYIM_NEKUDOTAYIM,     // ::
 			T_OBJECT_OPERATOR,          // ->
 			T_DOLLAR_OPEN_CURLY_BRACES, // ${
 			T_AND_EQUAL,                // &=
 			T_MOD_EQUAL,                // %=
 			T_XOR_EQUAL,                // ^=
 			T_OR_EQUAL,                 // |=
 			T_SL,                       // <<
 			T_SR,                       // >>
 			T_SL_EQUAL,                 // <<=
 			T_SR_EQUAL,                 // >>=
 		);
 
 		$tokens = token_get_all($src);
 
 		$new = "";
 		$c = sizeof($tokens);
 		$iw = false; // ignore whitespace
 		$ih = false; // in HEREDOC
 		$ls = "";    // last sign
 		$ot = null;  // open tag
 
 		for ($i = 0; $i < $c; $i++) {
 			$token = $tokens[$i];
 
 			if (is_array($token)) {
 				list ($tn, $ts) = $token; // tokens: number, string, line
 				$tname = token_name($tn);
 
 				if ($tn == T_INLINE_HTML) {
 					$new .= $ts;
 					$iw = false;
 				} else {
 					if ($tn == T_OPEN_TAG) {
 						if (strpos($ts, " ") || strpos($ts, "\n") || strpos($ts, "\t") || strpos($ts, "\r")) {
 							$ts = rtrim($ts);
 						}
 
 						$ts .= " ";
 						$new .= $ts;
 						$ot = T_OPEN_TAG;
 						$iw = true;
 					} elseif ($tn == T_OPEN_TAG_WITH_ECHO) {
 						$new .= $ts;
 						$ot = T_OPEN_TAG_WITH_ECHO;
 						$iw = true;
 					} elseif ($tn == T_CLOSE_TAG) {
 						if ($ot == T_OPEN_TAG_WITH_ECHO) {
 							$new = rtrim($new, "; ");
 						} else {
 							$ts = " ".$ts;
 						}
 
 						$new .= $ts;
 						$ot = null;
 						$iw = false;
 					} elseif (in_array($tn, $IW)) {
 						$new .= $ts;
 						$iw = true;
 					} elseif ($tn == T_CONSTANT_ENCAPSED_STRING	|| $tn == T_ENCAPSED_AND_WHITESPACE) {
 						if ($ts[0] == '"') {
 							$ts = addcslashes($ts, "\n\t\r");
 						}
 
 						$new .= $ts;
 						$iw = true;
 					} elseif ($tn == T_WHITESPACE) {
 						$nt = @$tokens[$i+1];
 						if (!$iw && (!is_string($nt) || $nt == '$') && !in_array($nt[0], $IW)) {
 							$new .= " ";
 						}
 
 						$iw = false;
 					} elseif ($tn == T_START_HEREDOC) {
 						$new .= "<<<S\n";
 						$iw = false;
 						$ih = true; // in HEREDOC
 	                } elseif ($tn == T_END_HEREDOC) {
 	                	$new .= "S;";
 	                	$iw = true;
 	                	$ih = false; // in HEREDOC
 	                	for ($j = $i + 1; $j < $c; $j++) {
 	                		if (is_string($tokens[$j]) && $tokens[$j] == ";") {
 	                			$i = $j;
 	                			break;
 	                		} else if ($tokens[$j][0] == T_CLOSE_TAG) {
 	                			break;
 	                		}
 						}
 					} elseif ($tn == T_COMMENT || $tn == T_DOC_COMMENT) {
 						$iw = true;
 					} else {
 						/*if (!$ih) {
 							// this also lowecases attribute names :(
 							$ts = strtolower($ts);
 						}*/
 
 						$new .= $ts;
 						$iw = false;
 					}
 				}
 
 				$ls = "";
 			} else {
 				if (($token != ";" && $token != ":") || $ls != $token) {
 					$new .= $token;
 					$ls = $token;
 				}
 
 				$iw = true;
 			}
 	    }
 
 	    return $new;
 	}
 }
\ No newline at end of file
Index: branches/5.0.x/core/units/theme_files/theme_file_eh.php
===================================================================
--- branches/5.0.x/core/units/theme_files/theme_file_eh.php	(revision 12297)
+++ branches/5.0.x/core/units/theme_files/theme_file_eh.php	(revision 12298)
@@ -1,220 +1,220 @@
 <?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.net/license/ for copyright notices and details.
 */
 
 	class ThemeFileEventHandler extends kDBEventHandler {
 
 		/**
 		 * Allows to override standart permission mapping
 		 *
 		 */
 		function mapPermissions()
 		{
 			parent::mapPermissions();
 
 			$permissions = Array (
 				'OnLoadBlock' => Array ('subitem' => true),
 				'OnSaveBlock' => Array ('subitem' => true),
 				'OnSaveLayout' => Array ('subitem' => true),
 			);
 
 			$this->permMapping = array_merge($this->permMapping, $permissions);
 		}
 
 		/**
 		 * Changes permission section to one from REQUEST, not from config
 		 *
 		 * @param kEvent $event
 		 */
 		function CheckPermission(&$event)
 		{
 			if ($event->Name == 'OnLoadBlock' || $event->Name == 'OnSaveBlock') {
 				return $this->Application->LoggedIn() && $this->Application->IsAdmin();
 			}
 
 			return parent::CheckPermission($event);
 		}
 
 		/**
 		 * Loads template contents into virtual field
 		 *
 		 * @param kEvent $event
 		 */
 		function OnAfterItemLoad(&$event)
 		{
 			parent::OnAfterItemLoad($event);
 
 			$object =& $event->getObject();
 			/* @var $object kDBItem */
 
 			$filename = $this->_getTemplatePath($object);
 
 			if (file_exists($filename)) {
 				$object->SetDBField('FileContents', file_get_contents($filename));
 			}
 			else {
 				$object->SetError('FileContents', 'template_file_missing', 'la_error_TemplateFileMissing');
 			}
 		}
 
 		/**
 		 * Trim contents of edited template
 		 *
 		 * @param kEvent $event
 		 */
 		function OnBeforeItemUpdate(&$event)
 		{
 			parent::OnBeforeItemUpdate($event);
 
 			$object =& $event->getObject();
 			/* @var $object kDBItem */
 
 			$file_data = $object->GetDBField('FileContents');
 
 			$file_data = str_replace("\r\n", "\n", $file_data);
 			$file_data = str_replace("\r", "\n", $file_data);
 
 			$object->SetDBField('FileContents', trim($file_data));
 		}
 
 		/**
 		 * Saves updated content to template
 		 *
 		 * @param kEvent $event
 		 */
 		function OnAfterItemUpdate(&$event)
 		{
 			parent::OnAfterItemUpdate($event);
 
 			$object =& $event->getObject();
 			/* @var $object kDBItem */
 
 			$filename = $this->_getTemplatePath($object);
 
 			if (file_exists($filename) && is_writable($filename)) {
 				$fp = fopen($filename, 'w');
 				fwrite($fp, $object->GetDBField('FileContents'));
 				fclose($fp);
 
 				$themes_helper =& $this->Application->recallObject('ThemesHelper');
 				/* @var $themes_helper kThemesHelper */
 
 				$meta_info = $themes_helper->parseTemplateMetaInfo($filename);
 				$file_description = array_key_exists('desc', $meta_info) ? $meta_info['desc'] : '';
 
 				$object->SetDBField('Description', $file_description);
 				$object->SetDBField('FileMetaInfo', serialize($meta_info));
 				$object->Update();
 			}
 		}
 
 		/**
 		 * Returns full path to template file
 		 *
 		 * @param kDBItem $object
 		 * @return string
 		 */
 		function _getTemplatePath(&$object)
 		{
 			$theme =& $this->Application->recallObject('theme');
 			/* @var $theme kDBItem */
 
 			$path = FULL_PATH . '/themes/' . $theme->GetDBField('Name');
 
 			$path .= $object->GetDBField('FilePath') . '/' . $object->GetDBField('FileName');
 
 			return $path;
 		}
 
 		/**
 		 * Loads block data based on it's name in request
 		 *
 		 * @param kEvent $event
 		 */
 		function OnLoadBlock(&$event)
 		{
 			parent::OnNew($event);
 
 			$object =& $event->getObject();
 			/* @var $object kDBItem */
 
 			$template_helper =& $this->Application->recallObject('TemplateHelper');
 			/* @var $template_helper TemplateHelper */
 
 			$template_helper->InitHelper($object);
 
 			$object->SetDBField('FileName', $template_helper->blockInfo('template_file'));
 			$object->SetDBField('BlockPosition', $template_helper->blockInfo('start_pos') . ' - ' . $template_helper->blockInfo('end_pos'));
 			$object->SetDBField('FileContents', $template_helper->blockInfo('content'));
 
 		}
 
 		/**
 		 * Saves changed template block
 		 *
 		 * @param kEvent $event
 		 */
 		function OnSaveBlock(&$event)
 		{
 			$object =& $event->getObject( Array('skip_autoload' => true) );
 			/* @var $object kDBItem */
 
 			$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
 			if ($items_info) {
 				list ($id, $field_values) = each($items_info);
 				$object->SetFieldsFromHash($field_values);
 				$object->setID($id);
 			}
 
 			$status = $object->Validate();
 
 			$template_helper =& $this->Application->recallObject('TemplateHelper');
 			/* @var $template_helper TemplateHelper */
 
 			$template_helper->InitHelper($object);
 
 			$status = $status && $template_helper->saveBlock($object);
 
 			if ($status) {
 				$event->SetRedirectParam('opener', 'u');
 			}
 			else {
 				$event->status = erFAIL;
 			}
 		}
 
 		/**
 		 * Saves layout on given template
 		 *
 		 * @param kEvent $event
 		 */
 		function OnSaveLayout(&$event)
 		{
 			$event->status = erSTOP;
-			if (($this->Application->GetVar('ajax') != 'yes') || (EDITING_MODE != EDITING_MODE_LAYOUT)) {
+			if (($this->Application->GetVar('ajax') != 'yes') || (EDITING_MODE != EDITING_MODE_DESIGN)) {
 				return ;
 			}
 
 			$target_order = $this->Application->GetVar('target_order');
 
 			$template_helper =& $this->Application->recallObject('TemplateHelper');
 			/* @var $template_helper TemplateHelper */
 
 			if ($template_helper->moveTemplateElements($target_order)) {
 				echo 'OK';
 				return ;
 			}
 
 			echo 'FAILED';
 		}
 	}
\ No newline at end of file
Index: branches/5.0.x/core/units/categories/categories_tag_processor.php
===================================================================
--- branches/5.0.x/core/units/categories/categories_tag_processor.php	(revision 12297)
+++ branches/5.0.x/core/units/categories/categories_tag_processor.php	(revision 12298)
@@ -1,2080 +1,2135 @@
 <?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.net/license/ for copyright notices and details.
 */
 
 class CategoriesTagProcessor extends kDBTagProcessor {
 
 	/**
 	 * Cached version of site menu
 	 *
 	 * @var Array
 	 */
 	var $Menu = null;
 
 	/**
 	 * Parent path mapping used in CachedMenu tag
 	 *
 	 * @var Array
 	 */
 	var $ParentPaths = Array ();
 
 	function SubCatCount($params)
 	{
 		$object =& $this->getObject($params);
 
 		if (isset($params['today']) && $params['today']) {
 			$sql = 'SELECT COUNT(*)
 					FROM '.$object->TableName.'
 					WHERE (ParentPath LIKE "'.$object->GetDBField('ParentPath').'%") AND (CreatedOn > '.(adodb_mktime() - 86400).')';
 			return $this->Conn->GetOne($sql) - 1;
 		}
 
 		return $object->GetDBField('CachedDescendantCatsQty');
 	}
 
 	/**
 	 * Returns category count in system
 	 *
 	 * @param Array $params
 	 * @return int
 	 */
 	function CategoryCount($params)
 	{
 		$count_helper =& $this->Application->recallObject('CountHelper');
 		/* @var $count_helper kCountHelper */
 
 		$today_only = isset($params['today']) && $params['today'];
 		return $count_helper->CategoryCount($today_only);
 	}
 
 	function IsNew($params)
 	{
 		$object =& $this->getObject($params);
 		return $object->GetDBField('IsNew') ? 1 : 0;
 	}
 
 	function IsPick($params)
 	{
 		return $this->IsEditorsPick($params);
 	}
 
 	/**
 	 * Returns item's editors pick status (using not formatted value)
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function IsEditorsPick($params)
 	{
 		$object =& $this->getObject($params);
 
 		return $object->GetDBField('EditorsPick') == 1;
 	}
 
 	function ItemIcon($params)
 	{
 		// only for categories, not structure
 		if ($this->Prefix != 'c') {
 			return parent::ItemIcon($params);
 		}
 
 		$object =& $this->getObject($params);
 		if ($object->GetDBField('IsMenu')) {
 			$status = $object->GetDBField('Status');
 			if ($status == 1) {
 				$ret = $object->GetDBField('IsNew') ? 'icon16_cat_new.gif' : 'icon16_folder.gif';
 			}
 			else {
 				$ret = $status ? 'icon16_cat_pending.gif' : 'icon16_cat_disabled.gif';
 			}
 		}
 		else {
 			$ret = 'icon16_folder-red.gif';
 		}
 
 		return $ret;
 	}
 
 	function ItemCount($params)
 	{
 		$object =& $this->getObject($params);
 		$ci_table = $this->Application->getUnitOption('l-ci', 'TableName');
 
 		$sql = 'SELECT COUNT(*)
 				FROM ' . $object->TableName . ' c
 				LEFT JOIN ' . $ci_table . ' ci ON c.CategoryId = ci.CategoryId
 				WHERE (c.TreeLeft BETWEEN ' . $object->GetDBField('TreeLeft') . ' AND ' . $object->GetDBField('TreeRight') . ') AND NOT (ci.CategoryId IS NULL)';
 		return $this->Conn->GetOne($sql);
 	}
 
 	function ListCategories($params)
 	{
 		return $this->PrintList2($params);
 	}
 
 	function RootCategoryName($params)
 	{
 		return $this->Application->ProcessParsedTag('m', 'RootCategoryName', $params);
 	}
 
 	function CheckModuleRoot($params)
 	{
 		$module_name = getArrayValue($params, 'module') ? $params['module'] : 'In-Commerce';
 		$module_root_cat = $this->Application->findModule('Name', $module_name, 'RootCat');
 
 		$additional_cats = $this->SelectParam($params, 'add_cats');
 		if ($additional_cats) {
 			$additional_cats = explode(',', $additional_cats);
 		}
 		else {
 			$additional_cats = array();
 		}
 
 		if ($this->Application->GetVar('m_cat_id') == $module_root_cat || in_array($this->Application->GetVar('m_cat_id'), $additional_cats)) {
 			$home_template = getArrayValue($params, 'home_template');
 			if (!$home_template) return;
 			$this->Application->Redirect($home_template, Array('pass'=>'all'));
 		};
 	}
 
 	function CategoryPath($params)
 	{
 		$category_helper =& $this->Application->recallObject('CategoryHelper');
 		/* @var $category_helper CategoryHelper */
 
 		return $category_helper->NavigationBar($params);
 	}
 
 	/**
 	 * Shows category path to specified category
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function FieldCategoryPath($params)
 	{
 		$object =& $this->getObject();
 		/* @var $object kDBItem */
 
 		$field = $this->SelectParam($params, 'name,field');
 		$category_id = $object->GetDBField($field);
 
 		if ($category_id) {
 			$params['cat_id'] = $category_id;
 			return $this->CategoryPath($params);
 		}
 
 		return '';
 	}
 
 	function CurrentCategoryName($params)
 	{
 		$cat_object =& $this->Application->recallObject($this->getPrefixSpecial(), $this->Prefix.'_List');
 		$sql = 'SELECT '.$this->getTitleField().'
 				FROM '.$cat_object->TableName.'
 				WHERE CategoryId = '.$this->Application->GetVar('m_cat_id');
 		return $this->Conn->GetOne($sql);
 	}
 
 	/**
 	 * Returns current category name
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @todo Find where it's used
 	 */
 	function CurrentCategory($params)
 	{
 		return $this->CurrentCategoryName($params);
 	}
 
 	function getTitleField()
 	{
 		$ml_formatter =& $this->Application->recallObject('kMultiLanguage');
 		return $ml_formatter->LangFieldName('Name');
 	}
 
 	function getCategorySymLink($category_id)
 	{
 		static $cache = null;
 
 		if (!isset($cache)) {
 			$id_field = $this->Application->getUnitOption($this->Prefix, 'IDField');
 			$table_name = $this->Application->getUnitOption($this->Prefix, 'TableName');
 
 			$sql = 'SELECT SymLinkCategoryId, '.$id_field.'
 					FROM '.$table_name.'
 					WHERE SymLinkCategoryId IS NOT NULL';
 			$cache = $this->Conn->GetCol($sql, $id_field);
 		}
 
 		if (isset($cache[$category_id])) {
 
 			//check if sym. link category is valid
 			$id_field = $this->Application->getUnitOption($this->Prefix, 'IDField');
 			$table_name = $this->Application->getUnitOption($this->Prefix, 'TableName');
 
 			$sql = 'SELECT '.$id_field.'
 					FROM '.$table_name.'
 					WHERE '.$id_field.' = '.$cache[$category_id];
 
 			$category_id = $this->Conn->GetOne($sql)? $cache[$category_id] : $category_id;
 		}
 
 		return $category_id;
 	}
 
 	function CategoryLink($params)
 	{
 		$category_id = getArrayValue($params, 'cat_id');
 
 		if ($category_id === false) {
 			$category_id = $this->Application->GetVar($this->getPrefixSpecial().'_id');
 		}
 
 		if ("$category_id" == 'Root') {
 			$category_id = $this->Application->findModule('Name', $params['module'], 'RootCat');
 		}
 		elseif ("$category_id" == 'current') {
 			$category_id = $this->Application->GetVar('m_cat_id');
 		}
 
 		$category_id = $this->getCategorySymLink($category_id);
 
 		unset($params['cat_id'], $params['module']);
 
 		$new_params = Array ('pass' => 'm', 'm_cat_id' => $category_id, 'pass_category' => 1);
 		$params = array_merge_recursive2($params, $new_params);
 
 		return $this->Application->ProcessParsedTag('m', 't', $params);
 	}
 
 	function CategoryList($params)
 	{
 		//$object =& $this->Application->recallObject( $this->getPrefixSpecial() , $this->Prefix.'_List', $params );
 		$object =& $this->GetList($params);
 
 
 		if ($object->RecordsCount == 0)
 		{
 			if (isset($params['block_no_cats'])) {
 				$params['name'] = $params['block_no_cats'];
 				return $this->Application->ParseBlock($params);
 			}
 			else {
 				return '';
 			}
 		}
 
 		if (isset($params['block'])) {
 			return $this->PrintList($params);
 		}
 		else {
 			$params['block'] = $params['block_main'];
 			if (isset($params['block_row_start'])) {
 				$params['row_start_block'] = $params['block_row_start'];
 			}
 
 			if (isset($params['block_row_end'])) {
 				$params['row_end_block'] = $params['block_row_end'];
 			}
 			return $this->PrintList2($params);
 		}
 	}
 
 	function Meta($params)
 	{
 		$object =& $this->Application->recallObject($this->Prefix); // .'.-item'
 		/* @var $object CategoriesItem */
 
 		$meta_type = $params['name'];
 		if ($object->isLoaded()) {
 			// 1. get module prefix by current category
 			$category_helper =& $this->Application->recallObject('CategoryHelper');
 			/* @var $category_helper CategoryHelper */
 
 			$category_path = explode('|', substr($object->GetDBField('ParentPath'), 1, -1));
 			$module_info = $category_helper->getCategoryModule($params,  $category_path);
 
 			// In-Edit & Proj-CMS module prefixes doesn't have custom field with item template
 			if ($module_info && $module_info['Var'] != 'adm' && $module_info['Var'] != 'st') {
 
 				// 2. get item template by current category & module prefix
 				$mod_rewrite_helper = $this->Application->recallObject('ModRewriteHelper');
 				/* @var $mod_rewrite_helper kModRewriteHelper */
 
 				$category_params = Array (
 				'CategoryId' => $object->GetID(),
 				'ParentPath' => $object->GetDBField('ParentPath'),
 				);
 
 				$item_template = $mod_rewrite_helper->GetItemTemplate($category_params, $module_info['Var']);
 
 				if ($this->Application->GetVar('t') == $item_template) {
 					// we are located on item's details page
 					$item =& $this->Application->recallObject($module_info['Var']);
 					/* @var $item kCatDBItem */
 
 					// 3. get item's meta data
 					$value = $item->GetField('Meta'.$meta_type);
 					if ($value) {
 						return $value;
 					}
 				}
 
 				// 4. get category meta data
 				$value = $object->GetField('Meta'.$meta_type);
 				if ($value) {
 					return $value;
 				}
 			}
 		}
 
 		// 5. get default meta data
 		switch ($meta_type) {
 			case 'Description':
 				$config_name = 'Category_MetaDesc';
 				break;
 			case 'Keywords':
 				$config_name = 'Category_MetaKey';
 				break;
 		}
 
 		return $this->Application->ConfigValue($config_name);
 	}
 
 	function BuildListSpecial($params)
 	{
 		if ( isset($params['parent_cat_id']) ) {
 			$parent_cat_id = $params['parent_cat_id'];
 		}
 		else {
 			$parent_cat_id = $this->Application->GetVar($this->Prefix.'_id');
 			if (!$parent_cat_id) {
 				$parent_cat_id = $this->Application->GetVar('m_cat_id');
 			}
 			if (!$parent_cat_id) {
 				$parent_cat_id = 0;
 			}
 		}
 
 		$no_special = isset($params['no_special']) && $params['no_special'];
 		if ($no_special) return $this->Special;
 
 		$list_unique_key = $this->getUniqueListKey($params);
 		// check for "admin" variable, because we are parsing front-end template from admin when using template editor feature
 		if ($this->Application->GetVar('admin') || !$this->Application->IsAdmin()) {
 			// add parent category to special, when on Front-End,
 			// because there can be many category lists on same page
 			$list_unique_key .= $parent_cat_id;
 		}
 
 		if ($list_unique_key == '') {
 			return parent::BuildListSpecial($params);
 		}
 
 		return crc32($list_unique_key);
 	}
 
 	function IsCurrent($params)
 	{
 		$object =& $this->getObject($params);
 		if ($object->GetID() == $this->Application->GetVar('m_cat_id')) {
 			return true;
 		}
 		else {
 			return false;
 		}
 	}
 
 	/**
 	 * Substitutes category in last template base on current category
 	 * This is required becasue when you navigate catalog using AJAX, last_template is not updated
 	 * but when you open item edit from catalog last_template is used to build opener_stack
 	 * So, if we don't substitute m_cat_id in last_template, after saving item we'll get redirected
 	 * to the first category we've opened, not the one we navigated to using AJAX
 	 *
 	 * @param Array $params
 	 */
 	function UpdateLastTemplate($params)
 	{
 		$category_id = $this->Application->GetVar('m_cat_id');
 
 		$wid = $this->Application->GetVar('m_wid');
 		list($index_file, $env) = explode('|', $this->Application->RecallVar(rtrim('last_template_'.$wid, '_')), 2);
 
 		$vars_backup = Array ();
 		$vars = $this->Application->HttpQuery->processQueryString( str_replace('%5C', '\\', $env) );
 
 		foreach ($vars as $var_name => $var_value) {
 			$vars_backup[$var_name] = $this->Application->GetVar($var_name);
 			$this->Application->SetVar($var_name, $var_value);
 		}
 
 		// update required fields
 		$this->Application->SetVar('m_cat_id', $category_id);
 		$this->Application->Session->SaveLastTemplate($params['template']);
 
 		foreach ($vars_backup as $var_name => $var_value) {
 			$this->Application->SetVar($var_name, $var_value);
 		}
 	}
 
 	function GetParentCategory($params)
 	{
 		$parent_id = 0;
 		$id_field = $this->Application->getUnitOption($this->Prefix, 'IDField');
 		$table = $this->Application->getUnitOption($this->Prefix,'TableName');
 		$cat_id = $this->Application->GetVar('m_cat_id');
 		if ($cat_id > 0) {
 			$sql = 'SELECT ParentId
 					FROM '.$table.'
 					WHERE '.$id_field.' = '.$cat_id;
 			$parent_id = $this->Conn->GetOne($sql);
 		}
 		return $parent_id;
 	}
 
 	function InitCacheUpdater($params)
 	{
 		safeDefine('CACHE_PERM_CHUNK_SIZE', 30);
 
 		$continue = $this->Application->GetVar('continue');
 		$total_cats = (int) $this->Conn->GetOne('SELECT COUNT(*) FROM '.TABLE_PREFIX.'Category');
 
 		if ($continue === false && $total_cats > CACHE_PERM_CHUNK_SIZE) {
 			// first step, if category count > CACHE_PERM_CHUNK_SIZE, then ask for cache update
 			return true;
 		}
 
 		if ($continue === false) {
 			// if we don't have to ask, then assume user selected "Yes" in permcache update dialog
 			$continue = 1;
 		}
 
 		$updater =& $this->Application->recallObject('kPermCacheUpdater', null, Array('continue' => $continue));
 		/* @var $updater kPermCacheUpdater */
 		if ($continue === '0') { // No in dialog
 			$updater->clearData();
 			$this->Application->Redirect($params['destination_template']);
 		}
 
 		$ret = false; // don't ask for update
 		if ($continue == 1) {  // Initial run
 			$updater->setData();
 		}
 		if ($continue == 2) { // Continuing
 			// called from AJAX request => returns percent
 			$needs_more = true;
 			while ($needs_more && $updater->iteration <= CACHE_PERM_CHUNK_SIZE) {
 				// until proceeeded in this step category count exceeds category per step limit
 				$needs_more = $updater->DoTheJob();
 			}
 
 			if ($needs_more) {
 				// still some categories are left for next step
 				$updater->setData();
 			}
 			else {
 				// all done -> redirect
 				$updater->SaveData();
 				$this->Application->RemoveVar('PermCache_UpdateRequired');
 				$this->Application->Redirect($params['destination_template']);
 			}
 
 			$ret = $updater->getDonePercent();
 		}
 		return $ret;
 	}
 
 	/**
 	 * Parses warning block, but with style="display: none;". Used during permissions saving from AJAX
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function SaveWarning($params)
 	{
 		if ($this->Prefix == 'st') {
 			// don't use this method for other prefixes then Category, that use this tag processor
 			return parent::SaveWarning($params);
 		}
 
 		$main_prefix = getArrayValue($params, 'main_prefix');
 		if ($main_prefix && $main_prefix != '$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) {
 			$this->Application->RemoveVar($top_prefix.'_modified');
 			return '';
 		}
 
 		$block_name = $this->SelectParam($params, 'render_as,name');
 		if ($block_name) {
 			$block_params = $this->prepareTagParams($params);
 			$block_params['name'] = $block_name;
 			$block_params['edit_mode'] = $temp_tables ? 1 : 0;
 			$block_params['display'] = $temp_tables && $modified ? 1 : 0;
 			return $this->Application->ParseBlock($block_params);
 		}
 		else {
 			return $temp_tables && $modified ? 1 : 0;
 		}
 		return ;
 	}
 
 	/**
 	 * Allows to detect if this prefix has something in clipboard
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function HasClipboard($params)
 	{
 		$clipboard = $this->Application->RecallVar('clipboard');
 		if ($clipboard) {
 			$clipboard = unserialize($clipboard);
 			foreach ($clipboard as $prefix => $clipboard_data) {
 				foreach ($clipboard_data as $mode => $ids) {
 					if (count($ids)) return 1;
 				}
 			}
 		}
 		return 0;
 	}
 
 	/**
 	 * Allows to detect if root category being edited
 	 *
 	 * @param Array $params
 	 */
 	function IsRootCategory($params)
 	{
 		$object =& $this->getObject($params);
 		return $object->IsRoot();
 	}
 
 	/**
 	 * Returns home category id
 	 *
 	 * @param Array $params
 	 * @return int
 	 */
 	function HomeCategory($params)
 	{
 		static $root_category = null;
 
 		if (!isset($root_category)) {
 			$root_category = $this->Application->findModule('Name', 'Core', 'RootCat');
 		}
 
 		return $root_category;
 	}
 
 	/**
 	 * Used for disabling "Home" and "Up" buttons in category list
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function ModuleRootCategory($params)
 	{
 		return $this->Application->GetVar('m_cat_id') == $this->HomeCategory($params);
 	}
 
 	function CatalogItemCount($params)
 	{
 		$params['skip_quering'] = true;
 		$object =& $this->GetList($params);
 
 		if (!$object->Counted) {
 			$object->CountRecs();
 		}
 
 		return $object->NoFilterCount != $object->RecordsCount ? $object->RecordsCount.' / '.$object->NoFilterCount : $object->RecordsCount;
 	}
 
 	/**
 	 * Print grid pagination using
 	 * block names specified
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function PrintPages($params)
 	{
 		if ($this->Application->Parser->GetParam('no_special')) {
 			$params['no_special'] = $this->Application->Parser->GetParam('no_special');
 		}
 		return parent::PrintPages($params);
 	}
 
 	function InitCatalog($params)
 	{
 		$tab_prefixes = $this->Application->GetVar('tp'); // {all, <prefixes_list>, none}
 		if ($tab_prefixes === false) $tab_prefixes = 'all';
 		$skip_prefixes = isset($params['skip_prefixes']) && $params['skip_prefixes'] ? explode(',', $params['skip_prefixes']) : Array();
 		$replace_main = isset($params['replace_m']) && $params['replace_m'];
 
 		// get all prefixes available
 		$prefixes = Array();
 		foreach ($this->Application->ModuleInfo as $module_name => $module_data) {
 			$prefix = $module_data['Var'];
 
 			if ($prefix == 'adm'/* || $prefix == 'm'*/) continue;
 
 			if ($prefix == 'm' && $replace_main) {
 				$prefix = 'c';
 			}
 
 			$prefixes[] = $prefix;
 		}
 
 		if ($tab_prefixes == 'none') {
 			$skip_prefixes = array_unique(array_merge($skip_prefixes, $prefixes));
 			unset($skip_prefixes[ array_search($replace_main ? 'c' : 'm', $skip_prefixes) ]);
 		}
 		elseif ($tab_prefixes != 'all') {
 			// prefix list here
 			$tab_prefixes = explode(',', $tab_prefixes); // list of prefixes that should stay
 			$skip_prefixes = array_unique(array_merge($skip_prefixes, array_diff($prefixes, $tab_prefixes)));
 		}
 
 		$params['name'] = $params['render_as'];
 		$params['skip_prefixes'] = implode(',', $skip_prefixes);
 		return $this->Application->ParseBlock($params, 1);
 	}
 
 	/**
 	 * Determines, that printed category/menu item is currently active (will also match parent category)
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function IsActive($params)
 	{
 		static $current_path = null;
 
 		if (!isset($current_path)) {
 			$sql = 'SELECT ParentPath
 					FROM ' . TABLE_PREFIX . 'Category
 					WHERE CategoryId = ' . $this->Application->GetVar('m_cat_id');
 			$current_path = $this->Conn->GetOne($sql);
 		}
 
 		if (array_key_exists('parent_path', $params)) {
 			$test_path = $params['parent_path'];
 		}
 		else {
 			$template = $params['template'];
 			if ($template) {
 				// when using from "c:CachedMenu" tag
 				$sql = 'SELECT ParentPath
 						FROM ' . TABLE_PREFIX . 'Category
 						WHERE NamedParentPath = ' . $this->Conn->qstr('Content/' . $template);
 				$test_path = $this->Conn->GetOne($sql);
 			}
 			else {
 				// when using from "c:PrintList" tag
 				$cat_id = array_key_exists('cat_id', $params) && $params['cat_id'] ? $params['cat_id'] : false;
 				if ($cat_id === false) {
 					// category not supplied -> get current from PrintList
 					$category =& $this->getObject($params);
 				}
 				else {
 					if ("$cat_id" == 'Root') {
 						$cat_id = $this->Application->findModule('Name', $params['module'], 'RootCat');
 					}
 
 					$category =& $this->Application->recallObject($this->Prefix . '.-c' . $cat_id, $this->Prefix, Array ('skip_autoload' => true));
 					$category->Load($cat_id);
 				}
 
 				$test_path = $category->GetDBField('ParentPath');
 			}
 		}
 
 		return strpos($current_path, $test_path) !== false;
 	}
 
 	/**
 	 * Checks if user have one of required permissions
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function HasPermission($params)
 	{
 		$perm_helper =& $this->Application->recallObject('PermissionsHelper');
 		/* @var $perm_helper kPermissionsHelper */
 
 		$params['raise_warnings'] = 0;
 		$object =& $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$params['cat_id'] = $object->isLoaded() ? $object->GetDBField('ParentPath') : $this->Application->GetVar('m_cat_id');
 		return $perm_helper->TagPermissionCheck($params);
 	}
 
 	/**
 	 * Prepares name for field with event in it (used only on front-end)
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function SubmitName($params)
 	{
 		return 'events['.$this->Prefix.']['.$params['event'].']';
 	}
 
 	/**
 	 * Returns last modification date of items in category / system
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function LastUpdated($params)
 	{
 		$category_id = $this->Application->GetVar('m_cat_id');
 		$table_name = $this->Application->getUnitOption($this->Prefix, 'TableName');
 
 		if (isset($params['local']) && $params['local'] && $category_id > 0) {
 			// scan only current category & it's children
 			$sql = 'SELECT TreeLeft, TreeRight
 	        		FROM '.TABLE_PREFIX.'Category
 	        		WHERE CategoryId = '.$category_id;
 			$tree_info = $this->Conn->GetRow($sql);
 
 			$sql = 'SELECT MAX(c.Modified) AS ModDate, MAX(c.CreatedOn) AS NewDate
 	        		FROM '.TABLE_PREFIX.'Category c
 	        		WHERE c.TreeLeft BETWEEN '.$tree_info['TreeLeft'].' AND '.$tree_info['TreeRight'];
 		}
 		else {
 			// scan all categories in system
 			$sql = 'SELECT MAX(Modified) AS ModDate, MAX(CreatedOn) AS NewDate
 	       			FROM '.$table_name;
 		}
 
 		$row_data = $this->Conn->GetRow($sql);
 		if (!$row_data) {
 			return '';
 		}
 
 		$date = $row_data[ $row_data['NewDate'] > $row_data['ModDate'] ? 'NewDate' : 'ModDate' ];
 
 		// format date
 		$format = isset($params['format']) ? $params['format'] : '_regional_DateTimeFormat';
 		if (preg_match("/_regional_(.*)/", $format, $regs)) {
 			$lang =& $this->Application->recallObject('lang.current');
 			if ($regs[1] == 'DateTimeFormat') {
 				// combined format
 				$format = $lang->GetDBField('DateFormat').' '.$lang->GetDBField('TimeFormat');
 			}
 			else {
 				// simple format
 				$format = $lang->GetDBField($regs[1]);
 			}
 		}
 
 		return adodb_date($format, $date);
 	}
 
 	function CategoryItemCount($params)
 	{
 		$object =& $this->getObject($params);
 		/* @var $object kDBList */
 
 		$params['cat_id'] = $object->GetID();
 
 		$count_helper =& $this->Application->recallObject('CountHelper');
 		/* @var $count_helper kCountHelper */
 
 		return $count_helper->CategoryItemCount($params['prefix'], $params);
 	}
 
 	/**
 	 * Returns prefix + any word (used for shared between categories per page settings)
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function VarName($params)
 	{
 		return $this->Prefix.'_'.$params['type'];
 	}
 
 	/**
 	 * Checks if current category is valid symbolic link to another category
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function IsCategorySymLink($params)
 	{
 		$object =& $this->getObject($params);
 		/* @var $object kDBList */
 
 		$sym_category_id = $object->GetDBField('SymLinkCategoryId');
 
 		if (is_null($sym_category_id))
 		{
 			return false;
 		}
 
 		$id_field = $this->Application->getUnitOption($this->Prefix, 'IDField');
 		$table_name = $this->Application->getUnitOption($this->Prefix, 'TableName');
 
 		$sql = 'SELECT '.$id_field.'
 				FROM '.$table_name.'
 				WHERE '.$id_field.' = '.$sym_category_id;
 
 		return $this->Conn->GetOne($sql)? true : false;
 	}
 
 	/**
 	 * Returns module prefix based on root category for given
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function GetModulePrefix($params)
 	{
 		$object =& $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$parent_path = explode('|', substr($object->GetDBField('ParentPath'), 1, -1));
 
 		$category_helper =& $this->Application->recallObject('CategoryHelper');
 		/* @var $category_helper CategoryHelper */
 
 		$module_info = $category_helper->getCategoryModule($params, $parent_path);
 		return $module_info['Var'];
 	}
 
 	function ImageSrc($params)
 	{
 		list ($ret, $tag_processed) = $this->processAggregatedTag('ImageSrc', $params, $this->getPrefixSpecial());
 		return $tag_processed ? $ret : false;
 	}
 
 	function PageLink($params)
 	{
 		$t = isset($params['template']) ? $params['template'] : '';
 		unset($params['template']);
 
 		if (!$t) $t = $this->Application->GetVar('t');
 
 		if (isset($params['page'])) {
 			$this->Application->SetVar($this->getPrefixSpecial().'_Page', $params['page']);
 			unset($params['page']);
 		}
 
 		$params['m_cat_page'] = $this->Application->GetVar($this->getPrefixSpecial().'_Page');
 
 		if (!isset($params['pass'])) {
 			$params['pass'] = 'm,'.$this->getPrefixSpecial();
 		}
 
 		return $this->Application->HREF($t, '', $params);
 	}
 
 	/**
 	 * Returns spelling suggestions against search keyword
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function SpellingSuggestions($params)
 	{
 		$keywords = unhtmlentities( trim($this->Application->GetVar('keywords')) );
 		if (!$keywords) {
 			return ;
 		}
 
 		// 1. try to get already cached suggestion
 		$suggestion = $this->Application->getCache('search.suggestion', $keywords);
 		if ($suggestion !== false) {
 			return $suggestion;
 		}
 
 		$table_name = $this->Application->getUnitOption('spelling-dictionary', 'TableName');
 
 		// 2. search suggestion in database
 		$sql = 'SELECT SuggestedCorrection
 				FROM ' . $table_name . '
 				WHERE MisspelledWord = ' . $this->Conn->qstr($keywords);
 		$suggestion = $this->Conn->GetOne($sql);
 		if ($suggestion !== false) {
 			$this->Application->setCache('search.suggestion', $keywords, $suggestion);
 			return $suggestion;
 		}
 
 		// 3. suggestion not found in database, ask webservice
 		$app_id = $this->Application->ConfigValue('YahooApplicationId');
 		$url = 'http://search.yahooapis.com/WebSearchService/V1/spellingSuggestion?appid=' . $app_id . '&query=';
 
 		$curl_helper =& $this->Application->recallObject('CurlHelper');
 		/* @var $curl_helper kCurlHelper */
 
 		$xml_data = $curl_helper->Send($url . urlencode($keywords));
 
 		$xml_helper =& $this->Application->recallObject('kXMLHelper');
 		/* @var $xml_helper kXMLHelper */
 
 		$root_node =& $xml_helper->Parse($xml_data);
 
 		$result = $root_node->FindChild('RESULT');
 		/* @var $result kXMLNode */
 
 		if (is_object($result)) {
 			// webservice responded -> save in local database
 			$fields_hash = Array (
 			'MisspelledWord' => $keywords,
 			'SuggestedCorrection' => $result->Data,
 			);
 
 			$this->Conn->doInsert($fields_hash, $table_name);
 			$this->Application->setCache('search.suggestion', $keywords, $result->Data);
 
 			return $result->Data;
 		}
 
 		return '';
 	}
 
 	/**
 	 * Shows link for searching by suggested word
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function SuggestionLink($params)
 	{
 		$params['keywords'] = $this->SpellingSuggestions($params);
 
 		return $this->Application->ProcessParsedTag('m', 'Link', $params);
 	}
 
 	function InitCatalogTab($params)
 	{
 		$tab_params['mode'] = $this->Application->GetVar('tm'); // single/multi selection possible
 		$tab_params['special'] = $this->Application->GetVar('ts'); // use special for this tab
 		$tab_params['dependant'] = $this->Application->GetVar('td'); // is grid dependant on categories grid
 
 		// set default params (same as in catalog)
 		if ($tab_params['mode'] === false) $tab_params['mode'] = 'multi';
 		if ($tab_params['special'] === false) $tab_params['special'] = '';
 		if ($tab_params['dependant'] === false) $tab_params['dependant'] = 'yes';
 
 		// pass params to block with tab content
 		$params['name'] = $params['render_as'];
 		$special = $tab_params['special'] ? $tab_params['special'] : $this->Special;
 		$params['prefix'] = trim($this->Prefix.'.'.$special, '.');
 
 		$prefix_append = $this->Application->GetVar('prefix_append');
 		if ($prefix_append) {
 			$params['prefix'] .= $prefix_append;
 		}
 
 		$default_grid = array_key_exists('default_grid', $params) ? $params['default_grid'] : 'Default';
 		$radio_grid = array_key_exists('radio_grid', $params) ? $params['radio_grid'] : 'Radio';
 
 		$params['cat_prefix'] = trim('c.'.($tab_params['special'] ? $tab_params['special'] : $this->Special), '.');
 		$params['tab_mode'] = $tab_params['mode'];
 		$params['grid_name'] = ($tab_params['mode'] == 'multi') ? $default_grid : $radio_grid;
 		$params['tab_dependant'] = $tab_params['dependant'];
 		$params['show_category'] = $tab_params['special'] == 'showall' ? 1 : 0; // this is advanced view -> show category name
 
 		if ($special == 'showall' || $special == 'user') {
 			$params['grid_name'] .= 'ShowAll';
 		}
 
 		return $this->Application->ParseBlock($params, 1);
 	}
 
 	/**
 	 * Show CachedNavbar of current item primary category
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function CategoryName($params)
 	{
 		// show category cachednavbar of
 		$object =& $this->getObject($params);
 		$category_id = isset($params['cat_id']) ? $params['cat_id'] : $object->GetDBField('CategoryId');
 
 		$category_path = $this->Application->getCache('category_paths', $category_id);
 		if ($category_path === false) {
 			// not chached
 			if ($category_id > 0) {
 				$cached_navbar = $object->GetField('CachedNavbar');
 
 				if ($category_id == $object->GetDBField('ParentId')) {
 					// parent category cached navbar is one element smaller, then current ones
 					$cached_navbar = explode('&|&', $cached_navbar);
 					array_pop($cached_navbar);
 					$cached_navbar = implode('&|&', $cached_navbar);
 				}
 				else {
 					// no relation with current category object -> query from db
 					$sql = 'SELECT l' . $this->Application->GetVar('m_lang') . '_CachedNavbar
 							FROM ' . $object->TableName . '
 							WHERE ' . $object->IDField . ' = ' . $category_id;
 					$cached_navbar = $this->Conn->GetOne($sql);
 				}
 
 				$cached_navbar = preg_replace('/^(Content&\|&|Content)/i', '', $cached_navbar);
 
 				$category_path = trim($this->CategoryName( Array('cat_id' => 0) ).' > '.str_replace('&|&', ' > ', $cached_navbar), ' > ');
 			}
 			else {
 				$category_path = $this->Application->Phrase( $this->Application->ConfigValue('Root_Name') );
 			}
 			$this->Application->setCache('category_paths', $category_id, $category_path);
 		}
 		return $category_path;
 	}
 
 	// structure related
 
 	/**
 	 * Returns page object based on requested params
 	 *
 	 * @param Array $params
 	 * @return PagesItem
 	 */
 	function &_getPage($params)
 	{
 		$page =& $this->Application->recallObject($this->Prefix . '.-virtual', null, $params);
 		/* @var $page kDBItem */
 
 		// 1. load by given id
 		$page_id = array_key_exists('page_id', $params) ? $params['page_id'] : false;
 		if ($page_id) {
 			if ($page_id != $page->GetID()) {
 				// load if different
 				$page->Load($page_id);
 			}
 
 			return $page;
 		}
 
 		// 2. load by template
 		$template = array_key_exists('page', $params) ? $params['page'] : '';
 		if (!$template) {
 			$template = $this->Application->GetVar('t');
 		}
 
 		// different path in structure AND design template differes from requested template
 		$structure_path_match = strtolower( $page->GetDBField('NamedParentPath') ) == strtolower('Content/' . $template);
 		$design_match = $page->GetDBField('CachedTemplate') == $template;
 
 		if (!$structure_path_match && !$design_match) {
 			// Same sql like in "c:getPassedID". Load, when current page object doesn't match requested page object
 			$themes_helper =& $this->Application->recallObject('ThemesHelper');
 			/* @var $themes_helper kThemesHelper */
 
 			$page_id = $themes_helper->getPageByTemplate($template);
 
 			$page->Load($page_id);
 		}
 
 		return $page;
 	}
 
 	/**
 	 * Returns requested content block content of current or specified page
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function ContentBlock($params)
 	{
 		$num = getArrayValue($params, 'num');
 		if (!$num) {
 			return 'NO CONTENT NUM SPECIFIED';
 		}
 
 		$page =& $this->_getPage($params);
 		/* @var $page kDBItem */
 
 		if (!$page->isLoaded()) {
 			// page is not created yet => all blocks are empty
 			return '';
 		}
 
 		$page_id = $page->GetID();
 
 		$content =& $this->Application->recallObject('content.-block', null, Array ('skip_autoload' => true));
 		/* @var $content kDBItem */
 
 		$data = Array ('PageId' => $page_id, 'ContentNum' => $num);
 		$content->Load($data);
 
 		if (!$content->isLoaded()) {
 			// bug: missing content blocks are created even if user have no SMS-management rights
 			$content->SetFieldsFromHash($data);
 			$content->Create();
 		}
 
 		$edit_code_before = $edit_code_after = '';
 
-		if (EDITING_MODE == EDITING_MODE_CMS) {
+		if (EDITING_MODE == EDITING_MODE_CONTENT) {
 			$bg_color = isset($params['bgcolor']) ? $params['bgcolor'] : '#ffffff';
 			$url_params = Array (
 				'pass'			=>	'm,c,content',
 				'm_opener'		=>	'd',
 				'c_id'			=>	$page->GetID(),
 				'content_id'	=>	$content->GetID(),
 				'front'			=>	1,
 				'admin'			=>	1,
 				'__URLENCODE__'	=>	1,
 				'__NO_REWRITE__'=>	1,
 				'escape'		=>	1,
 				'index_file' => 'index.php',
 //				'bgcolor' => $bg_color,
 //				'__FORCE_SID__' => 1
 			);
 
 			$additional_css = '';
 
 			if (isset($params['float'])) {
 				$additional_css .= 'position: relative; width: 100%; float: ' . $params['float'] . ';';
 			}
 
 			// link from Front-End to admin, don't remove "index.php"
 			$edit_url = $this->Application->HREF('categories/edit_content', ADMIN_DIRECTORY, $url_params, 'index.php');
 			$edit_code_before = '
 				<div class="cms-edit-btn-container">
 					<div class="cms-edit-btn" style="' . $additional_css . '" onclick="$form_name=\'kf_cont_'.$content->GetID().'\'; open_popup(\'content\', \'OnEdit\', \'categories/edit_content\');">
 						<div class="cms-btn-image">
 							<img src="' . $this->Application->BaseURL() . 'core/admin_templates/img/top_frame/icons/content_mode.gif" width="15" height="16" alt=""/>
 						</div>
-						<div class="cms-btn-text">Edit '.(defined('DEBUG_MODE') && DEBUG_MODE ? " - #{$num}" : '').'</div>
+						<div class="cms-btn-text">Edit content '.(defined('DEBUG_MODE') && DEBUG_MODE ? " - #{$num}" : '').'</div>
 					</div>
 					<div class="cms-btn-content">';
 
 			$edit_form = '<form method="POST" style="display: inline; margin: 0px" name="kf_cont_'.$content->GetID().'" id="kf_cont_'.$content->GetID().'" action="'.$edit_url.'">';
 			$edit_form .= '<input type="hidden" name="c_id" value="'.$page->GetID().'"/>';
 			$edit_form .= '<input type="hidden" name="content_id" value="'.$content->GetID().'"/>';
 			$edit_form .= '<input type="hidden" name="front" value="1"/>';
 			$edit_form .= '<input type="hidden" name="bgcolor" value="'.$bg_color.'"/>';
 			$edit_form .= '<input type="hidden" name="m_lang" value="'.$this->Application->GetVar('m_lang').'"/>';
 			$edit_form .= '</form>';
 
 			$edit_code_after = '</div></div>';
 
 			if (array_key_exists('forms_later', $params) && $params['forms_later']) {
 				$all_forms = $this->Application->GetVar('all_forms');
 				$this->Application->SetVar('all_forms', $all_forms . $edit_form);
 			}
 			else {
 				$edit_code_after .= $edit_form;
 			}
 		}
 
 		if ($this->Application->GetVar('_editor_preview_') == 1) {
 			$data = $this->Application->RecallVar('_editor_preview_content_');
 		} else {
 			$data = $content->GetField('Content');
 		}
 
 		$data = $edit_code_before . $this->_transformContentBlockData($data, $params) . $edit_code_after;
 
 		if ($data != '') {
 			$this->Application->Parser->DataExists = true;
 		}
 
 		return $data;
 	}
 
 	/**
 	 * Apply all kinds of content block data transformations without rewriting ContentBlock tag
 	 *
 	 * @param string $data
 	 * @return string
 	 */
 	function _transformContentBlockData(&$data, $params)
 	{
 		return $data;
 	}
 
 	/**
 	 * Returns current page name or page based on page/page_id parameters
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @todo Used?
 	 */
 	function PageName($params)
 	{
 		$page =& $this->_getPage($params);
 
 		return $page->GetDBField('Name');
 	}
 
 	/**
 	 * Returns current/given page information
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function PageInfo($params)
 	{
 		$page =& $this->_getPage($params);
 
 		if ($params['type'] == 'index_tools') {
 			$page_info = $page->GetDBField('IndexTools');
 			if ($page_info) {
 				return $page_info;
 			}
 			else {
 				if (PROTOCOL == 'https://') {
 					return $this->Application->ConfigValue('cms_DefaultIndextoolsCode_SSL');
 				}
 				else {
 					return $this->Application->ConfigValue('cms_DefaultIndextoolsCode');
 				}
 			}
 		}
 
 		switch ($params['type']) {
 			case 'title':
 				$db_field = 'Title';
 				break;
 
 			case 'htmlhead_title':
 				$db_field = 'Name';
 				break;
 
 			case 'meta_title':
 				$db_field = 'MetaTitle';
 				break;
 
 			case 'meta_keywords':
 				$db_field = 'MetaKeywords';
 				$cat_field = 'Keywords';
 				break;
 
 			case 'meta_description':
 				$db_field = 'MetaDescription';
 				$cat_field = 'Description';
 				break;
 
 			default:
 				return '';
 		}
 
 		$default = isset($params['default']) ? $params['default'] : '';
 		$val = $page->GetField($db_field);
 		if (!$default) {
 			if ($this->Application->isModuleEnabled('In-Portal')) {
 				if (!$val && ($params['type'] == 'meta_keywords' || $params['type'] == 'meta_description')) {
 					// take category meta if it's not set for the page
 					return $this->Application->ProcessParsedTag('c', 'Meta', Array('name' => $cat_field));
 				}
 			}
 		}
 
 		if (isset($params['force_default']) && $params['force_default']) {
 			return $default;
 		}
 
 		if (preg_match('/^_Auto:/', $val)) {
 			$val = $default;
 
 			/*if ($db_field == 'Title') {
 				$page->SetDBField($db_field, $default);
 				$page->Update();
 			}*/
 		}
 		elseif ($page->GetID() == false) {
 			return $default;
 		}
 
 		return $val;
 	}
 
 	/**
 	 * Includes admin css and js, that are required for cms usage on Front-Edn
 	 *
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function EditingScripts($params)
 	{
 		if ($this->Application->GetVar('admin_scripts_included') || !EDITING_MODE) {
 			return ;
 		}
 
 		$this->Application->SetVar('admin_scripts_included', 1);
 
 		$js_url = $this->Application->BaseURL() . 'core/admin_templates/js';
 
 		$ret = '<link rel="stylesheet" href="' . $js_url . '/jquery/thickbox/thickbox.css" type="text/css" media="screen"/>' . "\n";
 		$ret .= '<link rel="stylesheet" href="' . $js_url . '/../incs/cms.css" type="text/css" media="screen"/>' . "\n";
 
-		if (EDITING_MODE == EDITING_MODE_LAYOUT) {
+		if (EDITING_MODE == EDITING_MODE_DESIGN) {
 			$ret .= '	<style type="text/css" media="all">
 							div.movable-element .movable-header { cursor: move; }
 						</style>';
 		}
 
 		$ret .= '<script type="text/javascript" src="' . $js_url . '/jquery/jquery.pack.js"></script>' . "\n";
 		$ret .= '<script type="text/javascript" src="' . $js_url . '/jquery/jquery-ui.custom.min.js"></script>' . "\n";
 		$ret .= '<script type="text/javascript" src="' . $js_url . '/is.js"></script>' . "\n";
 		$ret .= '<script type="text/javascript" src="' . $js_url . '/application.js"></script>' . "\n";
 		$ret .= '<script type="text/javascript" src="' . $js_url . '/script.js"></script>' . "\n";
 		$ret .= '<script type="text/javascript" src="' . $js_url . '/jquery/thickbox/thickbox.js"></script>' . "\n";
 		$ret .= '<script type="text/javascript" src="' . $js_url . '/template_manager.js"></script>' . "\n";
 		$ret .= '<script language="javascript">' . "\n";
 		$ret .= "TB.pathToImage = 'js/jquery/thickbox/loadingAnimation.gif';" . "\n";
 
 		$template = $this->Application->GetVar('t');
 		$theme_id = $this->Application->GetVar('m_theme');
 
 		$url_params = Array ('block' => '#BLOCK#', 'theme-file_event' => '#EVENT#', 'theme_id' => $theme_id, 'source' => $template, 'pass' => 'all,theme-file', 'front' => 1, 'no_amp' => 1);
 		$edit_template_url = $this->Application->HREF('themes/template_edit', ADMIN_DIRECTORY, $url_params, 'index.php');
 
 		$url_params = Array ('theme-file_event' => 'OnSaveLayout', 'source' => $template, 'pass' => 'all,theme-file', 'no_amp' => 1);
 		$save_layout_url = $this->Application->HREF('index', '', $url_params);
 
 		$this_url = $this->Application->HREF('', '', Array ('editing_mode' => '#EDITING_MODE#', 'no_amp' => 1));
 		$ret .= "var aTemplateManager = new TemplateManager('" . $edit_template_url . "', '" . $this_url . "', '" . $save_layout_url . "', " . (int)EDITING_MODE . ");\n";
 
-		$ret .= "var \$modal_windows = " . ($this->Application->ConfigValue('UseModalWindows') ? 'true' : 'false') . ";\n";
-		$ret .= "var main_title = '" . addslashes( $this->Application->ConfigValue('Site_Name') ) . "';" . "\n";
-		$ret .= "var base_url = '" . $this->Application->BaseURL() . "';" . "\n";
-		$ret .= 'TB.closeHtml = \'<img src="' . $js_url . '/../img/close_window15.gif" width="15" height="15" style="border-width: 0px;" alt="close"/><br/>\';' . "\n";
-
-		$url_params = Array('m_theme' => '', 'pass' => 'm', 'm_opener' => 'r', 'no_amp' => 1);
-		$browse_url = $this->Application->HREF('catalog/catalog', ADMIN_DIRECTORY, $url_params, 'index.php');
-		$browse_url = preg_replace('/&(admin|editing_mode)=[\d]/', '', $browse_url);
-
-		$ret .= '
-			var topmost = window.top;
-
-			topmost.document.title = document.title + \' - '.$this->Application->Phrase('la_AdministrativeConsole').'\';
-			t = \''.$this->Application->GetVar('t').'\';
-
-			if (window.parent.frames["menu"] != undefined) {
-				if ( $.isFunction(window.parent.frames["menu"].SyncActive) ) {
-					window.parent.frames["menu"].SyncActive("' . $browse_url . '");
+		if (EDITING_MODE != EDITING_MODE_BROWSE) {
+			$ret .= "var \$modal_windows = " . ($this->Application->ConfigValue('UseModalWindows') ? 'true' : 'false') . ";\n";
+			$ret .= "var main_title = '" . addslashes( $this->Application->ConfigValue('Site_Name') ) . "';" . "\n";
+			$ret .= "var base_url = '" . $this->Application->BaseURL() . "';" . "\n";
+			$ret .= 'TB.closeHtml = \'<img src="' . $js_url . '/../img/close_window15.gif" width="15" height="15" style="border-width: 0px;" alt="close"/><br/>\';' . "\n";
+
+			$url_params = Array('m_theme' => '', 'pass' => 'm', 'm_opener' => 'r', 'no_amp' => 1);
+			$browse_url = $this->Application->HREF('catalog/catalog', ADMIN_DIRECTORY, $url_params, 'index.php');
+			$browse_url = preg_replace('/&(admin|editing_mode)=[\d]/', '', $browse_url);
+
+			$ret .= '
+				var topmost = window.top;
+
+				topmost.document.title = document.title + \' - '.$this->Application->Phrase('la_AdministrativeConsole', false).'\';
+				t = \''.$this->Application->GetVar('t').'\';
+
+				if (window.parent.frames["menu"] != undefined) {
+					if ( $.isFunction(window.parent.frames["menu"].SyncActive) ) {
+						window.parent.frames["menu"].SyncActive("' . $browse_url . '");
+					}
 				}
-			}
-		';
+			';
+		}
 
 		$ret .= '</script>' . "\n";
 
-		// add form, so admin scripts could work
-		$ret .= '<form id="kernel_form" name="kernel_form" enctype="multipart/form-data" method="post" action="' . $browse_url . '">
-					<input type="hidden" name="MAX_FILE_SIZE" id="MAX_FILE_SIZE" value="' . MAX_UPLOAD_SIZE . '" />
-					<input type="hidden" name="sid" id="sid" value="' . $this->Application->GetSID() . '" />
-				</form>';
+		if (EDITING_MODE != EDITING_MODE_BROWSE) {
+			// add form, so admin scripts could work
+			$ret .= '<form id="kernel_form" name="kernel_form" enctype="multipart/form-data" method="post" action="' . $browse_url . '">
+						<input type="hidden" name="MAX_FILE_SIZE" id="MAX_FILE_SIZE" value="' . MAX_UPLOAD_SIZE . '" />
+						<input type="hidden" name="sid" id="sid" value="' . $this->Application->GetSID() . '" />
+					</form>';
+		}
 
 		return $ret;
 	}
 
 	/**
 	 * Prints "Edit Page" button on cms page
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function EditPage($params)
 	{
 		if (!EDITING_MODE) {
 			return '';
 		}
 
 		$display_mode = array_key_exists('mode', $params) ? $params['mode'] : false;
 		$edit_code = '';
 
 		$page =& $this->_getPage($params);
 
-		if (!$page->isLoaded()) {
+		if (!$page->isLoaded() || (($display_mode != 'end') && (EDITING_MODE == EDITING_MODE_BROWSE))) {
 			// when "EditingScripts" tag is not used, make sure, that scripts are also included
 			return $this->EditingScripts($params);
 		}
 
 		// show "EditPage" button only for pages, that exists in structure
 		if ($display_mode != 'end') {
-			$url_params = Array(
-				'pass'			=>	'm,c',
-				'm_opener'		=>	'd',
-				'c_id'		=>	$page->GetID(),
-				'c_mode'		=>	't',
-				'c_event'		=>	'OnEdit',
-				'front'			=>	1,
-				'__URLENCODE__'	=>	1,
-				'__NO_REWRITE__'=>	1,
-				'escape'		=>	1,
-				'index_file' => 'index.php',
-			);
+			$edit_btn = '';
 
-			$edit_url = $this->Application->HREF('categories/categories_edit', '/admin', $url_params);
+			if (EDITING_MODE == EDITING_MODE_CONTENT) {
+				$url_params = Array(
+					'pass'			=>	'm,c',
+					'm_opener'		=>	'd',
+					'c_id'			=>	$page->GetID(),
+					'c_mode'		=>	't',
+					'c_event'		=>	'OnEdit',
+					'front'			=>	1,
+					'__URLENCODE__'	=>	1,
+					'__NO_REWRITE__'=>	1,
+					'escape'		=>	1,
+					'index_file' => 'index.php',
+				);
 
-			$edit_btn = '';
+				$edit_url = $this->Application->HREF('categories/categories_edit', '/admin', $url_params);
 
-			if (EDITING_MODE == EDITING_MODE_LAYOUT) {
 				$edit_btn .= '
-					<div class="cms-save-layout-btn"' . ($display_mode === false ? ' style="margin: 0px;"' : '') . ' onclick="aTemplateManager.saveLayout(); return false;">
+					<div class="cms-section-properties-btn"' . ($display_mode === false ? ' style="margin: 0px;"' : '') . ' onmouseover="window.status=\''.$edit_url.'\'; return true" onclick="$form_name=\'kf_'.$page->GetID().'\'; open_popup(\'c\', \'OnEdit\', \'categories/categories_edit\');">
 						<div class="cms-btn-image">
 							<img src="' . $this->Application->BaseURL() . 'core/admin_templates/img/top_frame/icons/content_mode.gif" width="15" height="16" alt=""/>
 						</div>
-						<div class="cms-btn-text">Save Layout</div>
+						<div class="cms-btn-text">Section Properties</div>
 					</div>' . "\n";
-			}
+			} elseif (EDITING_MODE == EDITING_MODE_DESIGN) {
+				$url_params = Array(
+					'pass'			=>	'm,theme',
+					'm_opener'		=>	'd',
+					'theme_id'		=>	$this->Application->GetVar('m_theme'),
+					'theme_mode'	=>	't',
+					'theme_event'	=>	'OnEdit',
+					'theme-file_id' =>	$this->_getThemeFileId(),
+					'front'			=>	1,
+					'__URLENCODE__'	=>	1,
+					'__NO_REWRITE__'=>	1,
+					'escape'		=>	1,
+					'index_file' => 'index.php',
+				);
 
-			$edit_btn .= '
-				<div class="cms-section-properties-btn"' . ($display_mode === false ? ' style="margin: 0px;"' : '') . ' onmouseover="window.status=\''.$edit_url.'\'; return true" onclick="$form_name=\'kf_'.$page->GetID().'\'; open_popup(\'c\', \'OnEdit\', \'categories/categories_edit\');">
-					<div class="cms-btn-image">
-						<img src="' . $this->Application->BaseURL() . 'core/admin_templates/img/top_frame/icons/content_mode.gif" width="15" height="16" alt=""/>
+				$edit_url = $this->Application->HREF('themes/file_edit', '/admin', $url_params);
+
+				$edit_btn .= '
+					<div class="cms-layout-btn-container"' . ($display_mode === false ? ' style="margin: 0px;"' : '') . '>
+						<div class="cms-save-layout-btn" onclick="aTemplateManager.saveLayout(); return false;">
+							<div class="cms-btn-image">
+								<img src="' . $this->Application->BaseURL() . 'core/admin_templates/img/top_frame/icons/content_mode.gif" width="15" height="16" alt=""/>
+							</div>
+							<div class="cms-btn-text">Save changes</div>
+						</div>
+						<div class="cms-cancel-layout-btn" onclick="aTemplateManager.cancelLayout(); return false;">
+							<div class="cms-btn-image">
+								<img src="' . $this->Application->BaseURL() . 'core/admin_templates/img/top_frame/icons/content_mode.gif" width="15" height="16" alt=""/>
+							</div>
+							<div class="cms-btn-text">Cancel</div>
+						</div>
 					</div>
-					<div class="cms-btn-text">Section Properties</div>
-				</div>' . "\n";
+
+					<div class="cms-section-properties-btn"' . ($display_mode === false ? ' style="margin: 0px;"' : '') . ' onmouseover="window.status=\''.$edit_url.'\'; return true" onclick="$form_name=\'kf_'.$page->GetID().'\'; open_popup(\'theme\', \'OnEdit\', \'themes/file_edit\');">
+						<div class="cms-btn-image">
+							<img src="' . $this->Application->BaseURL() . 'core/admin_templates/img/top_frame/icons/content_mode.gif" width="15" height="16" alt=""/>
+						</div>
+						<div class="cms-btn-text">Section Template</div>
+					</div>' . "\n";
+			}
 
 			if ($display_mode == 'start') {
 				// button with border around the page
 				$edit_code .= '<div class="cms-section-properties-btn-container">' . $edit_btn . '<div class="cms-btn-content">';
 
 			}
 			else {
 				// button without border around the page
 				$edit_code .= $edit_btn;
 			}
 		}
 
 		if ($display_mode == 'end') {
 			// draw border around the page
 			$edit_code .= '</div></div>';
 		}
 
 		if ($display_mode != 'end') {
 			$edit_code .= '<form method="POST" style="display: inline; margin: 0px" name="kf_'.$page->GetID().'" id="kf_'.$page->GetID().'" action="'.$edit_url.'"></form>';
 
 			// when "EditingScripts" tag is not used, make sure, that scripts are also included
 			$edit_code .= $this->EditingScripts($params);
 		}
 
 		return $edit_code;
 	}
 
+	function _getThemeFileId()
+	{
+		$template = $this->Application->GetVar('t');
+
+		if (!$this->Application->TemplatesCache->TemplateExists($template) && !$this->Application->IsAdmin()) {
+			$cms_handler =& $this->Application->recallObject($this->Prefix . '_EventHandler');
+			/* @var $cms_handler CategoriesEventHandler */
+
+			$template = ltrim($cms_handler->GetDesignTemplate(), '/');
+		}
+
+		$file_path = dirname($template) == '.' ? '' : '/' . dirname($template);
+		$file_name = basename($template);
+
+		$sql = 'SELECT FileId
+				FROM ' . TABLE_PREFIX . 'ThemeFiles
+				WHERE (FilePath = ' . $this->Conn->qstr($file_path) . ') AND (FileName = ' . $this->Conn->qstr($file_name . '.tpl') . ')';
+		return $this->Conn->GetOne($sql);
+	}
+
 	/**
 	 * Builds cached menu version
 	 *
 	 * @return Array
 	 */
 	function _prepareMenu()
 	{
 		static $root_cat = null;
 		static $root_path = null;
 
 		if (!$root_cat) {
 			$root_cat = $this->Application->ModuleInfo['Core']['RootCat'];
 			$root_path = $this->Conn->GetOne('SELECT ParentPath FROM '.TABLE_PREFIX.'Category WHERE CategoryId = '.$root_cat);
 		}
 
 		if (!$this->Menu) {
 			$menu = $this->Conn->GetRow('SELECT Data, Cached FROM '.TABLE_PREFIX.'Cache WHERE VarName = "cms_menu"');
 			if ($menu && $menu['Cached'] > 0) {
 				$menu = unserialize($menu['Data']);
 				$this->ParentPaths = $menu['ParentPaths'];
 			}
 			else {
 				$menu = $this->_altBuildMenuStructure(array('CategoryId' => $root_cat, 'ParentPath' => $root_path));
 				$menu['ParentPaths'] = $this->ParentPaths;
 				$this->Conn->Query('REPLACE '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("cms_menu", '.$this->Conn->qstr(serialize($menu)).', '.adodb_mktime().')');
 			}
 			unset($menu['ParentPaths']);
 			$this->Menu = $menu;
 		}
 
 		return Array ($this->Menu, $root_path);
 	}
 
 	/**
 	 * Returns category id based tag parameters
 	 *
 	 * @param Array $params
 	 * @return int
 	 */
 	function _getCategoryId($params)
 	{
 		$cat = isset($params['category_id']) && $params['category_id'] != '' ? $params['category_id'] : $this->Application->GetVar('m_cat_id');
 		if ("$cat" == 'parent') {
 			$this_category =& $this->Application->recallObject('c');
 			/* @var $this_category kDBItem */
 
 			$cat = $this_category->GetDBField('ParentId');
 		}
 		else if ($cat == 0) {
 			$cat = $this->Application->ModuleInfo['Core']['RootCat'];
 		}
 
 		return $cat;
 	}
 
 	/**
 	 * Prepares cms menu item block parameters
 	 *
 	 * @param Array $page
 	 * @param int $real_cat_id
 	 * @param string $root_path
 	 * @return Array
 	 */
 	function _prepareMenuItem($page, $real_cat_id, $root_path)
 	{
 		static $language_id = null;
 		static $primary_language_id = null;
 
 		if (!isset($language_id)) {
 			$language_id = $this->Application->GetVar('m_lang');
 			$primary_language_id = $this->Application->GetDefaultLanguageId();
 		}
 
 		$title = $page['l'.$language_id.'_ItemName'] ? $page['l'.$language_id.'_ItemName'] : $page['l'.$primary_language_id.'_ItemName'];
 		$active = false;
 		$category_active = false;
 
 		if ($page['ItemType'] == 'cat') {
 			if ( isset($this->ParentPaths[$real_cat_id])) {
 				$active = strpos($this->ParentPaths[$real_cat_id], $page['ParentPath']) !== false;
 			}
 			$category_active = $page['CategoryId'] == $real_cat_id;
 		}
 
 		if ($page['ItemType'] == 'cat_index') {
 			$check_path = str_replace($root_path, '', $page['ParentPath']);
 			$active = strpos($parent_path, $check_path) !== false;
 		}
 
 		if ($page['ItemType'] == 'page') {
 			$active = $page['ItemPath'] == preg_replace('/^Content\//i', '', $this->Application->GetVar('t'));
 		}
 
 		$block_params = Array (
 		'title'=> $title,
 		'template'=> preg_replace('/^Content\//i', '', $page['ItemPath']),
 		'active'=>$active,
 		'category_active' => $category_active, // new
 		'parent_path'=>$page['ParentPath'],
 		'parent_id'=>$page['ParentId'],
 		'cat_id'=>$page['CategoryId'],
 		'is_index'=>$page['IsIndex'],
 		'item_type'=>$page['ItemType'],
 		'page_id'=>$page['ItemId'],
 		'has_sub_menu' => isset($page['sub_items']) && count($page['sub_items']) > 0,
 		'external_url' => $page['UseExternalUrl'] ? $page['ExternalUrl'] : false,
 		'menu_icon' => $page['UseMenuIconUrl'] ? $page['MenuIconUrl'] : false,
 
 		);
 
 		return $block_params;
 	}
 
 	/**
 	 * Builds site menu
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function CachedMenu($params)
 	{
 		list ($menu, $root_path) = $this->_prepareMenu();
 		$cat = $this->_getCategoryId($params);
 
 		$parent_path = isset($this->ParentPaths[$cat]) ? $this->ParentPaths[$cat] : '';
 		$parent_path = str_replace($root_path, '', $parent_path); //menu starts from module path
 		$levels = explode('|',trim($parent_path,'|'));
 		if ($levels[0] === '') $levels = array();
 		if (isset($params['level']) && $params['level'] > count($levels)) return ;
 
 		$level = max(isset($params['level']) ? $params['level']-1 : count($levels)-1, 0);
 		$parent = isset($levels[$level]) ? $levels[$level] : 0;
 
 		$cur_menu =& $menu;
 		$menu_path = array_slice($levels, 0, $level+1);
 		foreach ($menu_path as $elem) {
 			$cur_menu =& $cur_menu['c'.$elem]['sub_items'];
 		}
 
 		$ret = '';
 		$block_params = $this->prepareTagParams($params);
 		$block_params['name'] = $params['render_as'];
 
 		$this->Application->SetVar('cur_parent_path', $parent_path);
 		$real_cat_id = $this->Application->GetVar('m_cat_id');
 		if (is_array($cur_menu) && $cur_menu) {
 			$cur_item = 1;
 			$cur_menu = $this->_removeNonMenuItems($cur_menu);
 			$block_params['total_items'] = count($cur_menu);
 
 			foreach ($cur_menu as $page) {
 				$block_params = array_merge_recursive2(
 				$block_params,
 				$this->_prepareMenuItem($page, $real_cat_id, $root_path)
 				);
 
 				$block_params['is_last'] = $cur_item == $block_params['total_items'];
 				$block_params['is_first'] = $cur_item == 1;
 
 				// bug #1: this breaks active section highlighting when 2 menu levels are printed on same page (both visible)
 				// bug #2: people doesn't pass cat_id parameter to m_Link tags in their blocks, so this line helps them; when removed their links will lead to nowhere
 				$this->Application->SetVar('m_cat_id', $page['CategoryId']);
 
 				$ret .= $this->Application->ParseBlock($block_params, 1);
 				$cur_item++;
 			}
 
 			$this->Application->SetVar('m_cat_id', $real_cat_id);
 		}
 
 		return $ret;
 	}
 
 	/**
 	 * Returns only items, that are visible in menu
 	 *
 	 * @param Array $menu
 	 * @return Array
 	 */
 	function _removeNonMenuItems($menu)
 	{
 		foreach ($menu as $menu_index => $menu_item) {
 			// $menu_index is in "cN" format, where N is category id
 			if (!$menu_item['IsMenu']) {
 				unset($menu[$menu_index]);
 			}
 		}
 
 		return $menu;
 	}
 
 	/**
 	 * Trick to allow some kind of output formatting when using CachedMenu tag
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function SplitColumn($params)
 	{
 		return $this->Application->GetVar($params['i']) > ceil($params['total'] / $params['columns']);
 	}
 
 	/**
 	 * Returns direct children count of given category
 	 *
 	 * @param Array $params
 	 * @return int
 	 */
 	function HasSubCats($params)
 	{
 		$sql = 'SELECT COUNT(*)
 				FROM ' . TABLE_PREFIX . 'Category
 				WHERE ParentId = ' . $params['cat_id'];
 
 		return $this->Conn->GetOne($sql);
 	}
 
 	/**
 	 * Prints sub-pages of given/current page.
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @todo This could be reached by using "parent_cat_id" parameter. Only difference here is new block parameter "path". Need to rewrite.
 	 */
 	function PrintSubPages($params)
 	{
 		$list =& $this->Application->recallObject($this->getPrefixSpecial(), $this->Prefix.'_List', $params);
 		/* @var $list kDBList */
 
 		$category_id = array_key_exists('category_id', $params) ? $params['category_id'] : $this->Application->GetVar('m_cat_id');
 
 		$list->addFilter('current_pages', TABLE_PREFIX . 'CategoryItems.CategoryId = ' . $category_id);
 		$list->Query();
 		$list->GoFirst();
 
 		$o = '';
 		$block_params = $this->prepareTagParams($params);
 		$block_params['name'] = $params['render_as'];
 
 		while (!$list->EOL()) {
 			$block_params['path'] = $list->GetDBField('Path');
 			$o .= $this->Application->ParseBlock($block_params, 1);
 
 			$list->GoNext();
 		}
 
 		return $o;
 	}
 
 	/**
 	 * Builds link for browsing current page on Front-End
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function PageBrowseLink($params)
 	{
 		$object =& $this->getObject($params);
 
 		$template = $object->GetDBField('NamedParentPath');
 		$url_params = Array ('admin' => 1, 'pass' => 'm', 'm_cat_id' => $object->GetID(), 'index_file' => 'index.php');
 
 		return $this->Application->HREF($template, '_FRONT_END_', $url_params);
 	}
 
 	/**
 	 * Builds link to cms page (used?)
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function ContentPageLink($params)
 	{
 		$object =& $this->getObject($params);
 		$params['t'] = $object->GetDBField('NamedParentPath');
 		$params['m_cat_id'] = 0;
 
 		return $this->Application->ProcessParsedTag('m', 'Link', $params);
 	}
 
 	/**
 	 * Builds cache for children of given category (no matter, what menu status is)
 	 *
 	 * @param Array $parent
 	 * @return Array
 	 */
 	function _altBuildMenuStructure($parent)
 	{
 		static $languages_count = null;
 
 		if (!isset($languages_count)) {
 			$sql = 'SELECT COUNT(*)
 					FROM ' . TABLE_PREFIX . 'Language';
 			$languages_count = ceil($this->Conn->GetOne($sql) / 5) * 5;
 		}
 
 		$items = Array ();
 
 		$lang_part = '';
 		for ($i = 1; $i <= $languages_count; $i++) {
 //			$lang_part .= 'c.l' . $i . '_Name AS l' . $i . '_ItemName,' . "\n";
 			$lang_part .= 'c.l' . $i . '_MenuTitle AS l' . $i . '_ItemName,' . "\n";
 		}
 
 		// Sub-categories from current category
 		$query = 'SELECT
 								c.CategoryId AS CategoryId,
 								CONCAT(\'c\', c.CategoryId) AS ItemId,
 								c.Priority AS ItemPriority,
 								' . $lang_part . '
 								LOWER( IF(IsIndex = 2, (
 											SELECT cc.NamedParentPath FROM ' . TABLE_PREFIX . 'Category AS cc
 											WHERE
 												cc.ParentId = c.CategoryId
 												AND
 												cc.Status IN (1,4)
 												AND
 												cc.IsIndex = 1
 										),
 									 c.NamedParentPath) ) AS ItemPath,
 								0 AS IsIndex,
 								c.ParentPath AS ParentPath,
 								c.ParentId As ParentId,
 								\'cat\' AS ItemType,
 								c.IsMenu, c.UseExternalUrl, c.ExternalUrl, c.UseMenuIconUrl, c.MenuIconUrl
 							FROM ' . TABLE_PREFIX . 'Category AS c
 							WHERE
 								 c.Status IN (1,4) AND
 								 #c.IsMenu = 1 AND
 								 c.ParentId = ' . $parent['CategoryId'];
 		$items = array_merge($items, $this->Conn->Query($query, 'ItemId'));
 
 		uasort($items, Array (&$this, '_menuSort'));
 
 		$the_items = array();
 		foreach ($items as $an_item) {
 			$the_items[ $an_item['ItemId'] ] = $an_item;
 			$this->ParentPaths[ $an_item['CategoryId'] ] = $an_item['ParentPath'];
 		}
 
 		$items = $the_items;
 		foreach ($items as $key => $menu_item) {
 			if ($menu_item['CategoryId'] == $parent['CategoryId']) {
 				continue;
 			}
 
 			$sub_items = $this->_altBuildMenuStructure($menu_item);
 			if ($sub_items) {
 				$items[$key]['sub_items'] = $sub_items;
 			}
 		}
 
 		return $items;
 	}
 
 	/**
 	 * Method for sorting pages by priority in decending order
 	 *
 	 * @param Array $a
 	 * @param Array $b
 	 * @return int
 	 */
 	function _menuSort($a, $b)
 	{
 		if ($a['ItemPriority'] == $b['ItemPriority']) {
 			return 0;
 		}
 
 		return ($a['ItemPriority'] < $b['ItemPriority']) ? 1 : -1; //descending
 	}
 
 	/**
 	 * Prepares cms page description for search result page
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function SearchDescription($params)
 	{
 		$object =& $this->getObject($params);
 		$desc =  $object->GetField('MetaDescription');
 		if (!$desc) {
 			$sql = 'SELECT *
 					FROM ' . TABLE_PREFIX . 'PageContent
 					WHERE PageId = ' . $object->GetID() . ' AND ContentNum = 1';
 			$content = $this->Conn->GetRow($sql);
 
 			if ($content['l'.$this->Application->GetVar('m_lang').'_Content']) {
 				$desc = $content['l'.$this->Application->GetVar('m_lang').'_Content'];
 			}
 			else {
 				$desc = $content['l'.$this->Application->GetDefaultLanguageId().'_Content'];
 			}
 		}
 
 		return mb_substr($desc, 0, 300).(mb_strlen($desc) > 300 ? '...' : '');
 	}
 
 	/**
 	 * Simplified version of "c:CategoryLink" for "c:PrintList"
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @todo Used? Needs refactoring.
 	 */
 	function EnterCatLink($params)
 	{
 		$object =& $this->getObject($params);
 
 		$url_params = Array ('pass' => 'm', 'm_cat_id' => $object->GetID());
 		return $this->Application->HREF($params['template'], '', $url_params);
 	}
 
 	/**
 	 * Simplified version of "c:CategoryPath", that do not use blocks for rendering
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @todo Used? Maybe needs to be removed.
 	 */
 	function PagePath($params)
 	{
 		$object =& $this->getObject($params);
 		$path = $object->GetField('CachedNavbar');
 		if ($path) {
 			$items = explode('&|&', $path);
 			array_shift($items);
 			return implode(' -&gt; ', $items);
 		}
 
 		return '';
 	}
 
 	/**
 	 * Returns configuration variable value
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @todo Needs to be replaced with "m:GetConfig" tag; Not used now (were used on structure_edit.tpl).
 	 */
 	function AllowManualFilenames($params)
 	{
 		return $this->Application->ConfigValue('ProjCMSAllowManualFilenames');
 	}
 
 	/**
 	 * Draws path to current page (each page can be link to it)
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function CurrentPath($params)
 	{
 		$block_params = $this->prepareTagParams($params);
 		$block_params['name'] = $block_params['render_as'];
 
 		$object =& $this->Application->recallObject($this->Prefix);
 		/* @var $object kDBItem */
 
 		$category_ids = explode('|', substr($object->GetDBField('ParentPath'), 1, -1));
 
 		$id_field = $this->Application->getUnitOption($this->Prefix, 'IDField');
 		$table_name = $this->Application->getUnitOption($this->Prefix, 'TableName');
 
 		$language = $this->Application->GetVar('m_lang');
 
 		$sql = 'SELECT l'.$language.'_Name AS Name, NamedParentPath
 				FROM '.$table_name.'
 				WHERE '.$id_field.' IN ('.implode(',', $category_ids).')';
 		$categories_data = $this->Conn->Query($sql);
 
 		$ret = '';
 		foreach ($categories_data as $index => $category_data) {
 			if ($category_data['Name'] == 'Content') {
 				continue;
 			}
 			$block_params['title'] = $category_data['Name'];
 			$block_params['template'] = preg_replace('/^Content\//i', '', $category_data['NamedParentPath']);
 			$block_params['is_first'] = $index == 1; // because Content is 1st element
 			$block_params['is_last'] = $index == count($categories_data) - 1;
 
 			$ret .= $this->Application->ParseBlock($block_params);
 		}
 
 		return $ret;
 	}
 
 	/**
 	 * Synonim to PrintList2 for "onlinestore" theme
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function ListPages($params)
 	{
 		return $this->PrintList2($params);
 	}
 
 	/**
 	 * Returns information about parser element locations in template
 	 *
 	 * @param Array $params
 	 * @return mixed
 	 */
 	function BlockInfo($params)
 	{
 		if (!EDITING_MODE) {
 			return '';
 		}
 
 		$template_helper =& $this->Application->recallObject('TemplateHelper');
 		/* @var $template_helper TemplateHelper */
 
 		return $template_helper->blockInfo( $params['name'] );
 	}
 
 	/**
 	 * Hide all editing tabs except permission tab, when editing "Home" (ID = 0) category
 	 *
 	 * @param Array $params
 	 */
 	function ModifyUnitConfig($params)
 	{
 		$root_category = $this->Application->RecallVar('IsRootCategory_' . $this->Application->GetVar('m_wid'));
 		if (!$root_category) {
 			return ;
 		}
 
 		$edit_tab_presets = $this->Application->getUnitOption($this->Prefix, 'EditTabPresets');
 		$edit_tab_presets['Default'] = Array (
 			'permissions' => $edit_tab_presets['Default']['permissions'],
 		);
 		$this->Application->setUnitOption($this->Prefix, 'EditTabPresets', $edit_tab_presets);
 	}
 
 	/**
 	 * Prints catalog export templates
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function PrintCatalogExportTemplates($params)
 	{
 		$prefixes = explode(',', $params['prefixes']);
 
 		$ret = Array ();
 		foreach ($prefixes as $prefix) {
 			if ($this->Application->prefixRegistred($prefix)) {
 				$ret[$prefix] = $this->Application->getUnitOption($prefix, 'ModuleFolder') . '/export';
 			}
 		}
 
 		$json_helper =& $this->Application->recallObject('JSONHelper');
 		/* @var $json_helper JSONHelper */
 
 		return $json_helper->encode($ret);
 	}
 
 	/**
 	 * Checks, that "view in browse mode" functionality available
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function BrowseModeAvailable($params)
 	{
 		$valid_special = $params['Special'] != 'user';
 		$not_selector = $this->Application->GetVar('type') != 'item_selector';
 
 		return $valid_special && $not_selector;
 	}
 
 	/**
 	 * Returns a link for editing product
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function ItemEditLink($params)
 	{
 		$object =& $this->getObject();
 		/* @var $object kDBList */
 
 		$edit_template = $this->Application->getUnitOption($this->Prefix, 'AdminTemplatePath') . '/' . $this->Application->getUnitOption($this->Prefix, 'AdminTemplatePrefix') . 'edit';
 
 		$url_params = Array (
 			'm_opener'				=>	'd',
 			$this->Prefix.'_mode'	=>	't',
 			$this->Prefix.'_event'	=>	'OnEdit',
 			$this->Prefix.'_id'		=>	$object->GetID(),
 			'm_cat_id'				=>	$object->GetDBField('ParentId'),
 			'pass'					=>	'all,'.$this->Prefix,
 			'no_pass_through'		=>	1,
 		);
 
 		return $this->Application->HREF($edit_template,'', $url_params);
 	}
 }
\ No newline at end of file
Index: branches/5.0.x/core/units/sections/site_config_tp.php
===================================================================
--- branches/5.0.x/core/units/sections/site_config_tp.php	(revision 12297)
+++ branches/5.0.x/core/units/sections/site_config_tp.php	(revision 12298)
@@ -1,60 +1,59 @@
 <?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.net/license/ for copyright notices and details.
 */
 
 	class SiteConfigTagProcessor extends TagProcessor {
 
 		function PrintEditingModes($params)
 		{
 			$editing_modes = Array (
-				1 => Array ('image' => 'show_structure', 'title' => 'Browse Mode'),
-				4 => Array ('image' => 'content_mode', 'title' => 'Content Mode'),
-				2 => Array ('image' => 'show_all', 'title' => 'Layout Mode'),
-				3 => Array ('image' => 'show_all', 'title' => 'Design Mode'),
+				EDITING_MODE_BROWSE => Array ('image' => 'show_structure', 'title' => 'Browse Mode'),
+				EDITING_MODE_CONTENT => Array ('image' => 'content_mode', 'title' => 'Content Mode'),
+				EDITING_MODE_DESIGN => Array ('image' => 'show_all', 'title' => 'Design Mode'),
 			);
 
 			$preset_name = $this->Application->ConfigValue('AdminConsoleInterface');
 			$base_path = FULL_PATH . ADMIN_DIRECTORY . '/system_presets/' . $preset_name;
 
 			if (file_exists($base_path . DIRECTORY_SEPARATOR . 'settings.php')) {
 				include_once $base_path . DIRECTORY_SEPARATOR . 'settings.php'; // will get $visible_editing_modes
 
 				foreach ($editing_modes as $editing_mode => $data) {
 					if (!in_array($editing_mode, $visible_editing_modes)) {
 						unset($editing_modes[$editing_mode]);
 					}
 				}
 
 				if (count($editing_modes) == 1) {
 					// don't show buttons, when there only one left
 					return '';
 				}
 			}
 
 			$ret = '';
 			$i = 1;
 			$count = count($editing_modes);
 			$block_params = Array ('name' => $params['render_as']);
 
 			foreach ($editing_modes as $editing_mode => $data) {
 				$block_params = array_merge($block_params, $data);
 				$block_params['editing_mode'] = $editing_mode;
 				$block_params['is_last'] = $i == $count;
 
 				$ret .= $this->Application->ParseBlock($block_params);
 				$i++;
 			}
 
 			return $ret;
 		}
 	}
\ No newline at end of file
Index: branches/5.0.x/core/units/phrases/phrases_config.php
===================================================================
--- branches/5.0.x/core/units/phrases/phrases_config.php	(revision 12297)
+++ branches/5.0.x/core/units/phrases/phrases_config.php	(revision 12298)
@@ -1,218 +1,218 @@
 <?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.net/license/ for copyright notices and details.
 */
 
 	$config = Array (
 		'Prefix' => 'phrases',
 
 		'Clones' => Array (
 			'phrases-single' => Array (
 				'ForeignKey' => false,
 				'ParentTableKey' => false,
 				'ParentPrefix' => false,
 			)
 		),
 
 		'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'),
 		'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'),
 		'EventHandlerClass' => Array ('class' => 'PhrasesEventHandler', 'file' => 'phrases_event_handler.php', 'build_event' => 'OnBuild'),
-		'TagProcessorClass' => Array ('class' => 'kDBTagProcessor', 'file' => '', 'build_event' => 'OnBuild'),
+		'TagProcessorClass' => Array ('class' => 'PhraseTagProcessor', 'file' => 'phrase_tp.php', 'build_event' => 'OnBuild'),
 
 		'AutoLoad' => true,
 
 		'Hooks' => Array (
 			Array (
 				'Mode' => hBEFORE,
 				'Conditional' => false,
 				'HookToPrefix' => 'phrases',
 				'HookToSpecial' => '',
 				'HookToEvent' => Array('OnCreate'),
 				'DoPrefix' => 'phrases',
 				'DoSpecial' => '',
 				'DoEvent' => 'OnBeforePhraseCreate',
 			),
 
 			Array (
 				'Mode' => hAFTER,
 				'Conditional' => false,
 				'HookToPrefix' => 'phrases',
 				'HookToSpecial' => '',
 				'HookToEvent' => Array('OnBeforeItemCreate', 'OnBeforeItemUpdate'),
 				'DoPrefix' => 'phrases',
 				'DoSpecial' => '',
 				'DoEvent' => 'OnSetLastUpdated',
 			),
 		),
 
 		'QueryString' => Array (
 			1 => 'id',
 			2 => 'page',
 			3 => 'event',
 			4 => 'label',
 			5 => 'mode', // labels can be edited directly
 		),
 
 		'IDField' => 'PhraseId',
 		'TitleField' => 'Phrase',
 
 		'TitlePresets' => Array (
 			'default' => Array (
 				'new_status_labels' => Array ('phrases' => '!la_title_Adding_Phrase!'),
 				'edit_status_labels' => Array ('phrases' => '!la_title_Editing_Phrase!'),
 			),
 
 			'phrase_edit' => Array (
 				'prefixes' => Array ('phrases'), 'format' => '#phrases_status# #phrases_titlefield#',
 				'toolbar_buttons' => Array ('select', 'cancel', 'reset_edit', 'prev', 'next'),
 				),
 
 			// for separate phrases list
 			'phrases_list_st' => Array (
 				'prefixes' => Array ('phrases.st_List'), 'format' => "!la_title_Phrases!",
 				'toolbar_buttons' => Array ('new_item', 'edit', 'delete', 'view', 'dbl-click'),
 				),
 
 			'phrase_edit_single' => Array (
 				'prefixes' => Array ('phrases'), 'format' => '#phrases_status# #phrases_titlefield#',
 				'toolbar_buttons' => Array ('select', 'cancel', 'reset_edit', 'prev', 'next'),
 				),
 		),
 
 		'FilterMenu' => Array (
 			'Groups' => Array (
 				Array ('mode' => 'AND', 'filters' => Array ('show_front', 'show_admin', 'show_both'), 'type' => WHERE_FILTER),
 				Array ('mode' => 'AND', 'filters' => Array ('translated', 'not_translated'), 'type' => WHERE_FILTER),
 			),
 			'Filters' => Array (
 				'show_front' => Array ('label' =>'la_PhraseType_Front', 'on_sql' => '', 'off_sql' => '%1$s.PhraseType != 0'),
 				'show_admin' => Array ('label' => 'la_PhraseType_Admin', 'on_sql' => '', 'off_sql' => '%1$s.PhraseType != 1'),
 				'show_both' => Array ('label' => 'la_PhraseType_Both', 'on_sql' => '', 'off_sql' => '%1$s.PhraseType != 2'),
 				's1' => Array (),
 				'translated' => Array ('label' => 'la_PhraseTranslated', 'on_sql' => '', 'off_sql' => '%1$s.Translation = pri.Translation'),
 				'not_translated' => Array ('label' => 'la_PhraseNotTranslated', 'on_sql' => '', 'off_sql' => '%1$s.Translation != pri.Translation'),
 			)
 		),
 
 		'Sections' => Array (
 			// "Phrases"
 			'in-portal:phrases' => Array (
 				'parent'		=>	'in-portal:site',
 				'icon'			=>	'conf_regional',
 				'label'			=>	'la_title_Phrases',
 				'url'			=>	Array ('t' => 'languages/phrase_list', 'pass' => 'm'),
 				'permissions'	=>	Array ('view', 'add', 'edit', 'delete'),
 //				'perm_prefix'	=>	'lang',
 				'priority'		=>	5,
 //				'show_mode'		=>	smSUPER_ADMIN,
 				'type'			=>	stTREE,
 			),
 		),
 
 		'TableName' => TABLE_PREFIX . 'Phrase',
 
 		'CalculatedFields' => Array (
 			'' => Array (
 				'PrimaryTranslation' => 'pri.Translation',
 			),
 
 			'st' => Array (
 				'PackName' => 'lang.PackName',
 			),
 		),
 
 		'ListSQLs' => Array(
 			'' => '	SELECT %1$s.* %2$s
 					FROM %1$s
 					LEFT JOIN ' . TABLE_PREFIX . 'Phrase pri ON (%1$s.Phrase = pri.Phrase) AND (pri.LanguageId = 1)',
 			'st' => 'SELECT %1$s.* %2$s
     				FROM %1$s
     				LEFT JOIN ' . TABLE_PREFIX . 'Language lang ON (%1$s.LanguageId = lang.LanguageId)',
 		),
 
 		'ListSortings' => Array (
 			'' => Array (
 				'Sorting' => Array ('Phrase' => 'asc'),
 			)
 		),
 
 		'ForeignKey' => 'LanguageId',
 		'ParentTableKey' => 'LanguageId',
 		'ParentPrefix' => 'lang',
 		'AutoDelete' => true,
 		'AutoClone' => true,
 
 		'Fields' => Array (
             'Phrase' => Array (
             	'type' => 'string',
             	'required' => 1, 'unique' => Array ('LanguageId'),
             	'not_null' => 1, 'default' => ''
             ),
 
             'Translation' => Array ('type' => 'string', 'formatter' => 'kFormatter', 'required' => 1, 'not_null' => 1, 'using_fck' => 1, 'default' => ''),
             'PhraseType' => Array ('type' => 'int', 'required'=>1,'formatter' => 'kOptionsFormatter', 'options'=>Array (0=>'la_PhraseType_Front',1=>'la_PhraseType_Admin',2=>'la_PhraseType_Both'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0),
             'PhraseId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
 
             'LanguageId' => Array (
             	'type' => 'int',
             	'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Language ORDER BY LocalName', 'option_key_field' => 'LanguageId', 'option_title_field' => 'LocalName',
             	'not_null' => 1, 'default' => 0
             ),
 
             'LastChanged' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'not_null' => 1, 'default' => 0),
 			'LastChangeIP' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 			'Module' => Array (
 				'type' => 'string',
 				'formatter' => 'kOptionsFormatter', 'options'=>Array ('' => ''), 'options_sql' => 'SELECT %s FROM '.TABLE_PREFIX.'Modules WHERE Loaded = 1 ORDER BY LoadOrder', 'option_key_field' => 'Name', 'option_title_field' => 'Name',
 				'not_null' => 1, 'default' => 'In-Portal'
 			),
         ),
 
 		'VirtualFields' => Array (
 			'PrimaryTranslation' => Array (),
 			'LangFile' => Array (),
 			'ImportOverwrite' => Array (),
 			'DoNotEncode' => Array (),
 			'PackName' => Array (
 				'type' => 'string',
 				'formatter' => 'kOptionsFormatter',
 				'options_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Language ORDER BY PackName', 'option_title_field' => 'PackName', 'option_key_field' => 'PackName',
 			),
 		),
 
 		'Grids'	=> Array (
 			'Default' => Array (
 				'Icons' => Array ('default' => 'icon16_language_var.gif'),
 				'Fields' => Array (
 					'Phrase' => Array ('title' => 'la_col_Label', 'data_block' => 'grid_checkbox_td'),
 					'Translation' => Array ('title' => 'la_col_Translation'),
 					'PrimaryTranslation' => Array ('title' => 'la_col_PrimaryValue'),
 					'PhraseType' => Array ('title' => 'la_col_PhraseType', 'filter_block' => 'grid_options_filter'),
 					'LastChanged' => Array ('title' => 'la_col_LastChanged', 'filter_block' => 'grid_date_range_filter'),
 					'Module' => Array ('title' => 'la_col_Module', 'filter_block' => 'grid_options_filter'),
 				),
 			),
 
 			'Phrases' => Array (
 				'Icons' => Array ('default' => 'icon16_language_var.gif'),
 				'Fields' => Array (
 					'PhraseId' => Array ('title' => 'la_col_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 50),
 					'Phrase' => Array ('title' => 'la_col_Name', 'filter_block' => 'grid_like_filter', 'width' => 150),
 					'Translation' => Array ('title' => 'la_col_Translation', 'filter_block' => 'grid_like_filter', 'width' => 150),
 					'PackName' => Array ('title' => 'la_col_Language', 'filter_block' => 'grid_options_filter', 'width' => 100),
 					'PhraseType' => Array ('title' => 'la_col_Location', 'filter_block' => 'grid_options_filter', 'width' => 80),
 					'LastChanged' => Array ('title' => 'la_col_LastChanged', 'filter_block' => 'grid_date_range_filter'),
 					'Module' => Array ('title' => 'la_col_Module', 'filter_block' => 'grid_options_filter'),
 				),
 			),
 		),
 	);
\ No newline at end of file
Index: branches/5.0.x/core/units/phrases/phrases_event_handler.php
===================================================================
--- branches/5.0.x/core/units/phrases/phrases_event_handler.php	(revision 12297)
+++ branches/5.0.x/core/units/phrases/phrases_event_handler.php	(revision 12298)
@@ -1,161 +1,173 @@
 <?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.net/license/ for copyright notices and details.
 */
 
 	class PhrasesEventHandler extends kDBEventHandler
 	{
 		/**
 		 * Apply some special processing to
 		 * object beeing recalled before using
 		 * it in other events that call prepareObject
 		 *
 		 * @param Object $object
 		 * @param kEvent $event
 		 * @access protected
 		 */
 		function prepareObject(&$object, &$event)
 		{
 			// don't call parent
 		}
 
 		/**
 		 * Allow to create phrases from front end in debug mode with DBG_PHRASES constant set
 		 *
 		 * @param kEvent $event
 		 */
 		function CheckPermission(&$event)
 		{
 			if (!$this->Application->IsAdmin() && $this->Application->isDebugMode() && constOn('DBG_PHRASES')) {
-				if ($event->Name == 'OnNew' || $event->Name == 'OnCreate' || $event->Name == 'OnPrepareUpdate' || $event->Name == 'OnUpdate') {
+				$allow_events = Array ('OnCreate', 'OnUpdate');
+
+				if (in_array($event->Name, $allow_events)) {
 					return true;
 				}
 			}
 
-
-
 			return parent::CheckPermission($event);
 		}
 
 		function mapPermissions()
 		{
 			parent::mapPermissions();
-				$permissions = Array (
-					'OnItemBuild' => Array('self' => true, 'subitem' => true),
-				);
+
+			$permissions = Array (
+				'OnItemBuild' => Array('self' => true, 'subitem' => true),
+				'OnNew' => Array('self' => true, 'subitem' => true),
+				'OnPrepareUpdate' => Array('self' => true, 'subitem' => true),
+			);
 
 			$this->permMapping = array_merge($this->permMapping, $permissions);
 		}
 
 		/**
 		 * Forces new label in case if issued from get link
 		 *
 		 * @param kEvent $event
 		 */
 		function OnNew(&$event)
 		{
 			parent::OnNew($event);
 			$label = $this->Application->GetVar('phrases_label');
 
-			$object =& $event->getObject( $label ? Array('live_table'=>true, 'skip_autoload' => true) : Array('skip_autoload' => true) );
+			$object =& $event->getObject( $label ? Array('live_table' => true, 'skip_autoload' => true) : Array('skip_autoload' => true) );
 			if ($label) {
-				$object->SetDBField('Phrase',$label);
+				$object->SetDBField('Phrase', $label);
 				// phrase is created in language, used to display phrases
-				$object->SetDBField('LanguageId', $this->Application->Phrases->LanguageId);
-				$object->SetDBField('PhraseType',1);
+				$object->SetDBField('LanguageId', $this->Application->GetVar('m_lang'));
+				$object->SetDBField('PhraseType', 1);
 
 				$primary_language = $this->Application->GetDefaultLanguageId();
 				$live_table = $this->Application->getUnitOption($event->Prefix, 'TableName');
 				$sql = 'SELECT Translation FROM %s WHERE Phrase = %s';
 				$primary_value = $this->Conn->GetOne( sprintf($sql, $live_table, $this->Conn->qstr($label) ) );
 				$object->SetDBField('PrimaryTranslation', $primary_value);
 			}
 
 			$last_module = $this->Application->GetVar('last_module');
-			if($last_module) $object->SetDBField('Module', $last_module);
+			if ($last_module) {
+				$object->SetDBField('Module', $last_module);
+			}
 
-			if($event->Special == 'export' || $event->Special == 'import')
-			{
+			if ($event->Special == 'export' || $event->Special == 'import') {
 				$object->SetDBField('PhraseType', '|0|1|2|');
 				$modules = $this->Conn->GetCol('SELECT Name FROM '.TABLE_PREFIX.'Modules');
 				$object->SetDBField('Module', '|'.implode('|', $modules).'|' );
 			}
 		}
 
+		/**
+		 * Prepares existing phrase editing
+		 *
+		 * @param kEvent $event
+		 */
 		function OnPrepareUpdate(&$event)
 		{
 			$language_id = $this->Application->GetVar('m_lang');
 			$label = $this->Application->GetVar('phrases_label');
 
 			$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
 			$label_idfield = $this->Application->getUnitOption($event->Prefix, 'IDField');
 
-			$sql = 'SELECT '.$label_idfield.' FROM '.$table_name.' WHERE Phrase = '.$this->Conn->qstr($label).' AND LanguageId = '.$language_id;
+			$sql = 'SELECT ' . $label_idfield . '
+					FROM ' . $table_name . '
+					WHERE Phrase = '.$this->Conn->qstr($label).' AND LanguageId = '.$language_id;
 			$this->Application->SetVar($event->getPrefixSpecial() . '_id', $this->Conn->GetOne($sql));
-//			$event->redirect = false;
+
+			$event->redirect = false;
 		}
 
 		/**
 		 * Forces create to use live table
 		 *
 		 * @param kEvent $event
 		 */
 		function OnBeforePhraseCreate(&$event)
 		{
 			$edit_direct = $this->Application->GetVar($event->Prefix.'_label');
 			if ($edit_direct) {
 				$object =& $event->getObject( Array('skip_autoload' => true) );
 				if ($this->Application->GetVar('m_lang') != $this->Application->GetVar('lang_id')) {
 					$object->SwitchToLive();
 				}
 			}
 		}
 
 		/**
 		 * Save phrase change date & ip translation was made from
 		 *
 		 * @param kEvent $event
 		 */
 		function OnSetLastUpdated(&$event)
 		{
 			$object =& $event->getObject();
 			$prev_translation = $this->Conn->GetOne('SELECT Translation FROM '.$object->TableName.' WHERE '.$object->IDField.' = '.(int)$object->GetId() );
 			if( $prev_translation != $object->GetDBField('Translation') )
 			{
 				$ip_address = getenv('HTTP_X_FORWARDED_FOR') ? getenv('HTTP_X_FORWARDED_FOR') : getenv('REMOTE_ADDR');
 				$object->SetDBField('LastChanged_date', adodb_mktime() );
 				$object->SetDBField('LastChanged_time', adodb_mktime() );
 				$object->SetDBField('LastChangeIP', $ip_address);
 			}
 
 			$this->Application->Session->SetCookie('last_module', $object->GetDBField('Module'));
 		}
 
 		/**
 		 * Changes default module to custom (when available)
 		 *
 		 * @param kEvent $event
 		 */
 		function OnAfterConfigRead(&$event)
 		{
 			parent::OnAfterConfigRead($event);
 
 			if ($this->Application->findModule('Name', 'Custom')) {
 				$fields = $this->Application->getUnitOption($event->Prefix, 'Fields');
 				$fields['Module']['default'] = 'Custom';
 				$this->Application->setUnitOption($event->Prefix, 'Fields', $fields);
 			}
 		}
 	}
 
 
 ?>
\ No newline at end of file
Index: branches/5.0.x/core/units/phrases/phrase_tp.php
===================================================================
--- branches/5.0.x/core/units/phrases/phrase_tp.php	(nonexistent)
+++ branches/5.0.x/core/units/phrases/phrase_tp.php	(revision 12298)
@@ -0,0 +1,30 @@
+<?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.net/license/ for copyright notices and details.
+*/
+
+	class PhraseTagProcessor extends kDBTagProcessor {
+
+		/**
+		 * Determines, that hidden field with language id should be shown
+		 *
+		 * @param Array $params
+		 * @return bool
+		 */
+		function ShowHiddenLanguage($params)
+		{
+			$simple_mode = $this->Application->GetVar('simple_mode');
+			$phrases_label = $this->Application->GetVar('phrases_label');
+
+			return $simple_mode || !$phrases_label;
+		}
+	}
\ No newline at end of file

Property changes on: branches/5.0.x/core/units/phrases/phrase_tp.php
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id
\ No newline at end of property
Index: branches/5.0.x/core/admin_templates/themes/file_edit.tpl
===================================================================
--- branches/5.0.x/core/admin_templates/themes/file_edit.tpl	(revision 12297)
+++ branches/5.0.x/core/admin_templates/themes/file_edit.tpl	(revision 12298)
@@ -1,52 +1,52 @@
 <inp2:adm_SetPopupSize width="1100" height="700"/>
 
 <inp2:m_include t="incs/header"/>
 <inp2:m_RenderElement name="combined_header" section="in-portal:configure_themes" prefix="theme" title_preset="theme_file_edit"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 							submit_event('theme-file','<inp2:theme-file_SaveEvent/>');
 						}
 					) );
 
 				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
 							cancel_edit('theme-file', 'OnCancelEdit','<inp2:theme-file_SaveEvent/>','<inp2:m_Phrase label="la_FormCancelConfirmation" escape="1"/>');
 						}
 				 ) );
 
 			 	a_toolbar.AddButton( new ToolBarButton('reset_edit', '<inp2:m_phrase label="la_ToolTip_Reset" escape="1"/>', function() {
 						reset_form('theme-file', 'OnReset', '<inp2:m_Phrase label="la_FormResetConfirmation" escape="1"/>');
 					}
 			 	) );
 
 				a_toolbar.Render();
 			</script>
 		</td>
 	</tr>
 </tbody>
 </table>
 
 <inp2:theme-file_SaveWarning name="grid_save_warning"/>
 <inp2:theme-file_ErrorWarning name="form_error_warning"/>
 
 <inp2:m_RenderElement name="inp_edit_hidden" prefix="theme-file" field="ThemeId"/>
 
 <div id="scroll_container">
 	<table class="edit-form">
 		<inp2:m_RenderElement name="subsection" prefix="theme-file" fields="FileId,FileName,FilePath,Description,FileContents" title="!la_section_General!"/>
 			<inp2:m_RenderElement name="inp_id_label" prefix="theme-file" field="FileId" title="!la_fld_Id!"/>
 			<inp2:m_RenderElement name="inp_label" prefix="theme-file" field="FileName" title="la_fld_FileName"/>
-			<inp2:m_RenderElement name="inp_label" prefix="theme-file" field="FilePath" title="la_fld_FileName"/>
+			<inp2:m_RenderElement name="inp_label" prefix="theme-file" field="FilePath" title="la_fld_FilePath"/>
 			<inp2:m_RenderElement name="inp_label" prefix="theme-file" field="Description" title="la_fld_Description"/>
 			<inp2:m_RenderElement name="inp_edit_codepress" prefix="theme-file" field="FileContents" title="la_fld_FileContents"/>
 			<inp2:m_RenderElement name="inp_edit_filler" control_options="{height: 8}"/>
 	</table>
 </div>
 
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: branches/5.0.x/core/admin_templates/themes/template_edit.tpl
===================================================================
--- branches/5.0.x/core/admin_templates/themes/template_edit.tpl	(revision 12297)
+++ branches/5.0.x/core/admin_templates/themes/template_edit.tpl	(revision 12298)
@@ -1,56 +1,56 @@
 <inp2:adm_SetPopupSize width="1100" height="700"/>
 
 <inp2:m_include t="incs/header"/>
 <inp2:m_RenderElement name="combined_header" section="in-portal:configure_themes" prefix="theme" title_preset="block_edit"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 							submit_event('theme-file','OnSaveBlock');
 						}
 					) );
 
 				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
-							submit_event('theme-file', 'OnGoBack');
+							window_close(); // submit_event('theme-file', 'OnGoBack');
 						}
 				 ) );
 
 				a_toolbar.Render();
 			</script>
 		</td>
 	</tr>
 </tbody>
 </table>
 
 <inp2:theme-file_SaveWarning name="grid_save_warning"/>
 <inp2:theme-file_ErrorWarning name="form_error_warning"/>
 
 <inp2:m_RenderElement name="inp_edit_hidden" prefix="theme-file" field="ThemeId"/>
 <input type="hidden" id="block" name="block" value="<inp2:m_Get name='block'/>"/>
 <input type="hidden" id="theme_id" name="theme_id" value="<inp2:m_Get name='theme_id'/>"/>
 <input type="hidden" id="source" name="source" value="<inp2:m_Get name='source'/>"/>
 
 <div id="scroll_container">
 	<table class="edit-form">
 		<inp2:m_RenderElement name="inp_label" prefix="theme-file" field="FileName" title="la_fld_FileName"/>
 		<inp2:m_RenderElement name="inp_label" prefix="theme-file" field="BlockPosition" title="la_fld_BlockPosition"/>
 		<inp2:m_RenderElement name="inp_edit_codepress" prefix="theme-file" field="FileContents" title="la_fld_FileContents"/>
 		<!--<inp2:m_RenderElement name="inp_edit_filler" control_options="{height: 8}"/>-->
 	</table>
 </div>
 
 <script type="text/javascript">
 Application.setHook(
 	new Array ('theme-file:OnSaveBlock'),
 	function($event) {
 		FileContents.toggleEditor(); // enable textarea back to save data
 		$event.status = true;
 	}
 );
 </script>
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: branches/5.0.x/core/admin_templates/js/script.js
===================================================================
--- branches/5.0.x/core/admin_templates/js/script.js	(revision 12297)
+++ branches/5.0.x/core/admin_templates/js/script.js	(revision 12298)
@@ -1,1759 +1,1764 @@
 if ( !( isset($init_made) && $init_made ) ) {
 	var Application = new kApplication();
 	var Grids = new Array();
 	var GridScrollers = new Array ();
 	var Toolbars = new Array();
 	var $Menus = new Array();
 	var $ViewMenus = new Array();
 	var $nls_menus = new Array();
 	var $MenuNames = new Array();
 
 	var $form_name = 'kernel_form';
 	if(!$fw_menus) var $fw_menus = new Array();
 
 	var $env = '';
 	var submitted = false;
 	var unload_legal = false;
 	var $edit_mode = false;
 	var $init_made = true; // in case of double inclusion of script.js :)
 
 	// hook processing
 	var hBEFORE	= 1; // this is const, but including this twice causes errors
 	var hAFTER	= 2; // this is const, but including this twice causes errors
 	replaceFireBug();
 }
 
 function use_popups($prefix_special, $event) {
 	return $use_popups;
 }
 
 function getArrayValue()
 {
 	var $value = arguments[0];
 	var $current_key = 0;
 	$i = 1;
 	while ($i < arguments.length) {
 		$current_key = arguments[$i];
 		if (isset($value[$current_key])) {
 			$value = $value[$current_key];
 		}
 		else {
 			return false;
 		}
 		$i++;
 	}
 	return $value;
 }
 
 function setArrayValue()
 {
 	// first argument - array, other arguments - keys (arrays too), last argument - value
 	var $array = arguments[0];
 	var $current_key = 0;
 	$i = 1;
 	while ($i < arguments.length - 1) {
 		$current_key = arguments[$i];
 		if (!isset($array[$current_key])) {
 			$array[$current_key] = new Array();
 		}
 		$array = $array[$current_key];
 		$i++;
 	}
 	$array[$array.length] = arguments[arguments.length - 1];
 }
 
 function resort_grid($prefix_special, $field, $ajax)
 {
 	set_form($prefix_special, $ajax);
 	set_hidden_field($prefix_special + '_Sort1', $field);
 	submit_event($prefix_special, 'OnSetSorting', null, null, $ajax);
 }
 
 function direct_sort_grid($prefix_special, $field, $direction, $field_pos, $ajax)
 {
 	if(!isset($field_pos)) $field_pos = 1;
 	set_form($prefix_special, $ajax);
 	set_hidden_field($prefix_special+'_Sort'+$field_pos,$field);
 	set_hidden_field($prefix_special+'_Sort'+$field_pos+'_Dir',$direction);
 	set_hidden_field($prefix_special+'_SortPos',$field_pos);
 	submit_event($prefix_special,'OnSetSortingDirect', null, null, $ajax);
 }
 
 function reset_sorting($prefix_special, $ajax)
 {
 	submit_event($prefix_special,'OnResetSorting', null, null, $ajax);
 }
 
 function set_per_page($prefix_special, $per_page, $ajax)
 {
 	set_form($prefix_special, $ajax);
 	set_hidden_field($prefix_special + '_PerPage', $per_page);
 	submit_event($prefix_special, 'OnSetPerPage', null, null, $ajax);
 }
 
 function set_refresh_interval($prefix_special, $refresh_interval, $ajax)
 {
 	set_form($prefix_special, $ajax);
 	set_hidden_field('refresh_interval', $refresh_interval);
 	submit_event($prefix_special, 'OnSetAutoRefreshInterval', null, null, $ajax);
 }
 
 function submit_event(prefix_special, event, t, form_action, $ajax)
 {
 	if (!Application.processHooks(prefix_special + ':' + event)) {
 		return false;
 	}
 	if ($ajax) {
 		return $Catalog.submit_event(prefix_special, event, t);
 	}
 
 	if (event) {
 		set_hidden_field('events[' + prefix_special + ']', event);
 	}
 	if (t) set_hidden_field('t', t);
 
 	if (form_action) {
 		var old_env = '';
 		if (!form_action.match(/\?/)) {
 			document.getElementById($form_name).action.match(/.*(\?.*)/);
 			old_env = RegExp.$1;
 		}
 		document.getElementById($form_name).action = form_action + old_env;
 	}
 	submit_kernel_form();
 
 	// reset remove special mark (otherwise all future events will have special removed too)
 	set_hidden_field('remove_specials[' + prefix_special + ']', null);
 }
 
 function submit_action($url, $action)
 {
 	$form = document.getElementById($form_name);
 	$form.action = $url;
 	set_hidden_field('Action', $action);
 	submit_kernel_form();
 }
 
 function show_form_data()
 {
 	var $kf = document.getElementById($form_name);
 	$ret = '';
 	for(var i in $kf.elements)
 	{
 		$elem = $kf.elements[i];
 		$ret += $elem.id + ' = ' + $elem.value + "\n";
 	}
 	alert($ret);
 }
 
 function submit_kernel_form()
 {
 	if (submitted) {
 		return;
 	}
 
 	submitted = true;
 	unload_legal = true; // bug: when opening new popup from this window, then this window is not refreshed and this mark stays forever
 
 	var $form = document.getElementById($form_name);
 
 	if (typeof $form.onsubmit == 'function') {
 		$form.onsubmit();
 	}
 
 	$form.submit();
 
 	$form.target = '';
 	set_hidden_field('t', t);
 
 //	window.setTimeout(function() {submitted = false}, 500);
 }
 
 function set_event(prefix_special, event)
 {
 	var event_field=document.getElementById('events[' + prefix_special + ']');
 	if(isset(event_field))
 	{
 		event_field.value = event;
 	}
 }
 
 function isset(variable)
 {
 	if(variable==null) return false;
 	return (typeof(variable)=='undefined')?false:true;
 }
 
 function in_array(needle, haystack)
 {
 	return array_search(needle, haystack) != -1;
 }
 
 function array_search(needle, haystack)
 {
 	for (var i=0; i<haystack.length; i++)
 	{
 		if (haystack[i] == needle) return i;
 	}
 	return -1;
 }
 
 function print_pre(variable, msg)
 {
 	if (!isset(msg)) msg = '';
 	var s = msg;
 	for (prop in variable)   {
       s += prop+" => "+variable[prop] + "\n";
   }
   alert(s);
 }
 
 function go_to_page($prefix_special, $page, $ajax)
 {
 	set_form($prefix_special, $ajax);
 	set_hidden_field($prefix_special + '_Page', $page);
 	submit_event($prefix_special, 'OnSetPage', null, null, $ajax);
 }
 
 function go_to_list(prefix_special, tab)
 {
 	set_hidden_field(prefix_special+'_GoTab', tab);
 	submit_event(prefix_special,'OnUpdateAndGoToTab',null);
 }
 
 function go_to_tab(prefix_special, tab)
 {
 	set_hidden_field(prefix_special+'_GoTab', tab);
 	submit_event(prefix_special,'OnPreSaveAndGoToTab',null);
 }
 
 function go_to_id(prefix_special, id)
 {
 	set_hidden_field(prefix_special+'_GoId', id);
  	submit_event(prefix_special,'OnPreSaveAndGo')
 }
 
 // in-portal compatibility functions: begin
 function getScriptURL($script_name, tpl)
 {
 	tpl = tpl ? '-'+tpl : '';
 	var $asid = get_hidden_field('sid');
 	return base_url+$script_name+'?env='+( isset($env)&&$env?$env:$asid )+tpl+'&en=0';
 }
 
 function OpenEditor(extra_env,TargetForm,TargetField)
 {
 	var $url = getScriptURL('admin/index.php', 'popups/editor');
 	$url = $url+'&TargetForm='+TargetForm+'&TargetField='+TargetField+'&destform=popup';
 	if(extra_env.length>0) $url += extra_env;
 	openwin($url,'html_edit',800,575);
 }
 // in-portal compatibility functions: end
 
 function InitTranslator(prefix, field, t, multi_line, $before_callback)
 {
 	var $window_name = 'select_' + t.replace(/(\/|-)/g, '_');
 
 	var $options = {
 		onAfterShow: function ($popup_window) {
 			if ($modal_windows) {
 				getFrame('main').initTranslatorOnAfterShow(prefix, field, t, multi_line, $before_callback);
 			}
 			else {
 				initTranslatorOnAfterShow(prefix, field, t, multi_line, $before_callback, $popup_window);
 			}
 		}
 	};
 
 	openwin('', $window_name, 750, 400, $options);
 }
 
 function initTranslatorOnAfterShow(prefix, field, t, multi_line, $before_callback, $popup_window) {
 	var $window_name = 'select_' + t.replace(/(\/|-)/g, '_');
 
 	$popup_window = onAfterWindowOpen($window_name, undefined, $popup_window);
 	if ($popup_window === false) {
 		// iframe onload happens on frame content change too -> don't react on it
 		return ;
 	}
 
 	var $opener = getWindowOpener($popup_window);
 	var $prev_opener = get_hidden_field('m_opener');
 
 	$opener.set_hidden_field('m_opener', 'p');
 	$opener.set_hidden_field('translator_wnd_name', $window_name);
 	$opener.set_hidden_field('translator_field', field);
 	$opener.set_hidden_field('translator_t', t);
 	$opener.set_hidden_field('translator_prefixes', prefix);
 	$opener.set_hidden_field('translator_multi_line', isset(multi_line) ? multi_line : 0);
 
 	if ($.isFunction($before_callback)) {
 		$before_callback($opener);
 	}
 
 	$opener.document.getElementById($opener.$form_name).target = $window_name;
 
 	var split_prefix = prefix.split(',');
 	$opener.submit_event(split_prefix[0], 'OnPreSaveAndOpenTranslator');
 
 	$opener.set_hidden_field('m_opener', $prev_opener);
 	$opener.submitted = false;
 }
 
 function PreSaveAndOpenTranslator(prefix, field, t, multi_line)
 {
 	InitTranslator(prefix, field, t, multi_line);
 }
 
 function PreSaveAndOpenTranslatorCV(prefix, field, t, resource_id, multi_line)
 {
 	InitTranslator(
 		prefix, field, t, multi_line,
 		function ($opener) {
 			$opener.set_hidden_field('translator_resource_id', resource_id);
 		}
 	);
 }
 
 function openTranslator(prefix,field,url,wnd)
 {
 	var $kf = document.getElementById($form_name);
 
 	set_hidden_field('trans_prefix', prefix);
 	set_hidden_field('trans_field', field);
 	set_hidden_field('events[trans]', 'OnLoad');
 
 	var $regex = new RegExp('(.*)\?env=(' + document.getElementById('sid').value + ')?-(.*?):(.*)');
 	var $t = $regex.exec(url)[3];
 	$kf.target = wnd;
 	submit_event(prefix,'',$t,url);
 	submitted = false;
 }
 
 function openwin($url, $name, $width, $height, $options)
 {
 	var $settings = {
 		url: base_url + 'core/admin_templates/blank.html?width=' + $width + '&height=' + $height + '&TB_iframe=true&modal=true',
 		caption: 'Loading ...',
 		onAfterShow: function ($popup_window) {
 			if ($modal_windows) {
 				getFrame('main').onAfterWindowOpen($name, $url);
 			}
 			else {
 				onAfterWindowOpen($name, $url, $popup_window);
 			}
 		}
 	};
 
 	if ($options !== undefined) {
 		$.extend($settings, $options);
 	}
 
 	if ($modal_windows) {
 		if (window.name != 'main') {
 			// all popups are opened based on main frame
 			return getFrame('main').TB.show($settings);
 		}
 
 		TB.show($settings);
 
 		return ;
 	}
 
 	// prevent window from opening larger, then screen resolution on user's computer (to Kostja)
 	var left = Math.round((screen.width - $width) / 2);
 	var top = Math.round((screen.height - $height) / 2);
 	var cur_x = document.all ? window.screenLeft : window.screenX;
 	var cur_y = document.all ? window.screenTop : window.screenY;
 
 	var $window_params = 'left='+left+',top='+top+',width='+$width+',height='+$height+',status=yes,resizable=yes,menubar=no,scrollbars=yes,toolbar=no';
 	var $popup_window = window.open($url, $name, $window_params);
 
 	if ( $.isFunction($settings.onAfterShow) ) {
 		$settings.onAfterShow($popup_window);
 	}
 
 	return $popup_window;
 }
 
 function onAfterWindowOpen($window_name, $url, $popup_window) {
 	// this is always invoked from "main" frame
 	if ($popup_window === undefined) {
 		var $popup_window = $('#' + TB.getId('TB_iframeContent')).get(0).contentWindow;
 		if (!$.isFunction($popup_window.onLoad)) {
 			// iframe onload happens on frame content change too -> don't react on it
 			return false;
 		}
 
 		$popup_window.onLoad();
 	}
 
 	$popup_window.name = $window_name;
 
 	if ($url !== undefined) {
 		$popup_window.location.href = $url;
 	}
 
 	if ($modal_windows) {
 		TB.setWindowMetaData('window_name', $window_name); // used to simulate window.opener functionality
 	}
 
 	return $popup_window;
 }
 
 function OnResizePopup(e) {
 	if (!document.all) {
 		var $winW = window.innerWidth;
 		var $winH = window.innerHeight;
 	}
 	else {
 		var $winW = window.document.body.offsetWidth;
 		var $winH = window.document.body.offsetHeight;
 	}
 
 	window.status = '[width: ' + $winW + '; height: ' + $winH + ']';
 }
 
 function opener_action(new_action)
 {
 	var $prev_opener = get_hidden_field('m_opener');
 	set_hidden_field('m_opener', new_action);
 	return $prev_opener;
 }
 
 function open_popup($prefix_special, $event, $t, $window_size, $onAfterOpenPopup) {
 	if (!$window_size) {
 		// if no size given, then query it from ajax
 		var $default_size = '750x400';
 		var $pm = getFrame('head').$popup_manager;
 		if ($pm) {
 			// popup manager was found in head frame
 			$pm.ResponceFunction = function ($responce) {
 				if (!$responce.match(/([\d]+)x([\d]+)/)) {
 					// invalid responce was received, may be php fatal error during AJAX request
 					$responce = $default_size;
 				}
 
 				open_popup($prefix_special, $event, $t, $responce, $onAfterOpenPopup);
 			}
 
 			$pm.GetSize($t);
 			return ;
 		}
 
 		$window_size = $default_size;
 	}
 
 	$window_size = $window_size.split('x');
 	var $window_name = $t.replace(/(\/|-)/g, '_'); // replace "/" and "-" with "_"
 
 	var $options = {
 		onAfterShow: function ($popup_window) {
 
 			if ($modal_windows) {
 				getFrame('main').onAfterOpenPopup($prefix_special, $event, $t);
 			}
 			else {
 				onAfterOpenPopup($prefix_special, $event, $t, $popup_window);
 			}
 
 			if ($onAfterOpenPopup !== undefined && $.isFunction($onAfterOpenPopup)) {
 				$onAfterOpenPopup($popup_window);
 			}
 		}
 	};
 
 	openwin('', $window_name, $window_size[0], $window_size[1], $options);
 }
 
 function onAfterOpenPopup($prefix_special, $event, $t, $popup_window) {
 	// this is always invoked from "main" frame
 	var $window_name = $t.replace(/(\/|-)/g, '_'); // replace "/" and "-" with "_"
 
 	$popup_window = onAfterWindowOpen($window_name, undefined, $popup_window);
 	if ($popup_window === false) {
 		// iframe onload happens on frame content change too -> don't react on it
 		return ;
 	}
 
 	var $opener = getWindowOpener($popup_window);
 	if ($opener === null) {
 		// we are already in main window
 		$opener = window;
 	}
 
 	$opener.document.getElementById($opener.$form_name).target = $window_name;
 
 	var $prev_opener = $opener.opener_action('p');
 	event_bak = $opener.get_hidden_field('events[' + $prefix_special + ']')
 	if (!event_bak) {
 		event_bak = '';
 	}
 
 	$opener.submit_event($prefix_special, $event, $t);
 
 	$opener.opener_action($prev_opener); // restore opener in parent window
 	$opener.set_hidden_field('events[' + $prefix_special + ']', event_bak); // restore event
 
 	// AJAX popup size respoce is received after std_edit_item/std_precreate_item function exit
 	$opener.set_hidden_field($prefix_special + '_mode', null);
 	$opener.submitted = false;
 
 	$opener.Application.processHooks($prefix_special + ':OnAfterOpenPopup');
 }
 
 
 function openSelector($prefix, $url, $dst_field, $window_size, $event)
 {
 	// get template name from url
 	var $regex = new RegExp('(.*)\?env=(' + document.getElementById('sid').value + ')?-(.*?):(m[^:]+)');
 	$regex = $regex.exec($url);
 
 	var $t = $regex[3];
 
 	// substitute form action with selector's url
 	var $kf = document.getElementById($form_name);
 	var $prev_action = $kf.action;
 
 	$kf.action = $url;
 
 	// check parameter values
 	if (!isset($event)) {
 		$event = '';
 	}
 
 	Application.processHooks($prefix + ':OnBeforeOpenSelector');
 
 	// set variables need for selector to work
 	set_hidden_field('main_prefix', $prefix);
 	set_hidden_field('dst_field', $dst_field);
 
 //	alert('openSelector(' + $prefix + ', ' + $event + ', ' + $t + ', ' + $window_size + ')');
 	open_popup(
 		$prefix, $event, $t, $window_size,
 		function() {
 			// restore form action back
 			$kf.action = $prev_action;
 		}
 	);
 }
 
-function translate_phrase($label, $template) {
+function translate_phrase($label, $template, $options) {
 	set_hidden_field('phrases_label', $label);
-	open_popup('phrases', 'OnNew', $template);
+
+	if ($options.simple_mode !== undefined) {
+		set_hidden_field('simple_mode', $options.simple_mode ? 1 : 0);
+	}
+
+	open_popup('phrases', $options.event === undefined ? 'OnNew' : $options.event, $template);
 }
 
 function direct_edit($prefix_special, $url) {
 	if (use_popups($prefix_special, '')) {
 		openSelector($prefix_special, $url);
 	}
 	else {
 		redirect($url);
 	}
 
 	return false;
 }
 
 function std_precreate_item(prefix_special, edit_template, $onAfterOpenPopup)
 {
 	set_hidden_field(prefix_special+'_mode', 't');
 	if (use_popups(prefix_special, 'OnPreCreate')) {
 		open_popup(prefix_special, 'OnPreCreate', edit_template, null, $onAfterOpenPopup);
 	}
 	else {
 		opener_action('d');
 	 	submit_event(prefix_special,'OnPreCreate', edit_template);
 	}
 //  set_hidden_field(prefix_special+'_mode', '');
 }
 
 function std_new_item(prefix_special, edit_template, $onAfterOpenPopup)
 {
 	if (use_popups(prefix_special, 'OnNew')) {
 		open_popup(prefix_special, 'OnNew', edit_template, null, $onAfterOpenPopup);
 	}
 	else {
 		opener_action('d');
 	  	submit_event(prefix_special,'OnNew', edit_template);
 	}
 }
 
 function std_edit_item(prefix_special, edit_template, $onAfterOpenPopup)
 {
 	set_hidden_field(prefix_special+'_mode', 't');
 	if (use_popups(prefix_special, 'OnEdit')) {
 		open_popup(prefix_special, 'OnEdit', edit_template, null, $onAfterOpenPopup);
 	}
 	else {
 		opener_action('d');
 		submit_event(prefix_special,'OnEdit',edit_template);
 	}
 //	set_hidden_field(prefix_special+'_mode', '');
 }
 
 function std_edit_temp_item(prefix_special, edit_template, $onAfterOpenPopup)
 {
 	if (use_popups(prefix_special, '')) {
 		open_popup(prefix_special, '', edit_template, null, $onAfterOpenPopup);
 	}
 	else {
 		opener_action('d');
 		submit_event(prefix_special,'',edit_template);
 	}
 }
 
 function std_delete_items(prefix_special, t, $ajax)
 {
 	var phrase = phrases['la_Delete_Confirm'] ? phrases['la_Delete_Confirm'] : 'Are you sure you want to delete selected items?';
 	if (inpConfirm(phrase)) {
   		submit_event(prefix_special, 'OnMassDelete', t, null, $ajax);
 	}
 }
 
 function std_csv_export(prefix_special, grid, template)
 {
 	set_hidden_field('PrefixSpecial', prefix_special);
 	set_hidden_field('grid', grid);
 
 	open_popup(prefix_special, '', template);
 }
 
 function std_csv_import(prefix_special, grid, template)
 {
 	set_hidden_field('PrefixSpecial', prefix_special);
 	set_hidden_field('grid', grid);
 	if (use_popups(prefix_special, '')) {
 		open_popup(prefix_special, '', template);
 	}
 	else {
 	 	submit_event(prefix_special, '', template);
  	}
 }
 
 // set current form base on ajax
 function set_form($prefix_special, $ajax)
 {
 	if ($ajax) {
 		$form_name = $Catalog.queryTabRegistry('prefix', $prefix_special, 'tab_id') + '_form';
 	}
 }
 
 // sets hidden field value
 // if the field does not exist - creates it
 function set_hidden_field($field_id, $value, $has_id)
 {
 	var $kf = document.getElementById($form_name);
 	var $field = $kf.elements[$field_id];
 
 	if ($value === null) {
 		if ($field) {
 //			alert('tag name on remove: ' + $field.parentNode.tagName);
 			$field.parentNode.removeChild($field); // bug: sometimes hidden fields are inside BODY tag in DOM model, why?
 		}
 		return true;
 	}
 
 	if ($field) {
 		$field.value = $value;
 		return true;
 	}
 
 	$field = document.createElement('INPUT');
 	$field.type = 'hidden';
 	$field.name = $field_id;
 	if (!isset($has_id) || $has_id) {
 		$field.id = $field_id;
 	}
 
 	$field.value = $value;
 	$kf.appendChild($field);
 	return false;
 }
 
 // sets hidden field value
 // if the field does not exist - creates it
 function setInnerHTML($field_id, $value) {
 	$( jq('#' + $field_id) ).html($value);
 }
 
 function get_hidden_field($field)
 {
 	var $kf = document.getElementById($form_name);
 	return $kf.elements[$field] ? $kf.elements[$field].value : false;
 }
 
 function search($prefix_special, $grid_name, $ajax)
 {
 	set_form($prefix_special, $ajax);
 	set_hidden_field('grid_name', $grid_name);
 	submit_event($prefix_special, 'OnSearch', null, null, $ajax);
 }
 
 function search_reset($prefix_special, $grid_name, $ajax)
 {
 	set_form($prefix_special, $ajax);
 	set_hidden_field('grid_name', $grid_name);
 	submit_event($prefix_special, 'OnSearchReset', null, null, $ajax);
 }
 
 function search_keydown($event, $prefix_special, $grid, $ajax)
 {
 	if ($prefix_special !== undefined) {
 		// if $prefix_special is passed, then keydown event was not assigned by jQuery
 		$event = $event ? $event : event;
 
 		if (window.event) {// IE
 			var $key_code = $event.keyCode;
 		}
 		else if($event.which) { // Netscape/Firefox/Opera
 			var $key_code = $event.which;
 		}
 	}
 	else {
 		// event bind with jQuery, so always use which
 		var $key_code = $event.which;
 
 		$prefix_special = $(this).attr('PrefixSpecial');
 		$grid = $(this).attr('Grid');
 		$ajax = $(this).attr('ajax');
 	}
 
 	switch ($key_code) {
 		case 13:
 			search($prefix_special, $grid, parseInt($ajax));
 			break;
 
 		case 27:
 			search_reset($prefix_special, $grid, parseInt($ajax));
 			break;
 	}
 }
 
 function getRealLeft(el)
 {
 	if (typeof(el) == 'string') {
 		el = document.getElementById(el);
 	}
 	xPos = el.offsetLeft;
 	tempEl = el.offsetParent;
 	while (tempEl != null)
 	{
 		xPos += tempEl.offsetLeft;
 		tempEl = tempEl.offsetParent;
 	}
 	//	if (obj.x) return obj.x;
 	return xPos;
 }
 
 function getRealTop(el)
 {
 	if (typeof(el) == 'string') {
 		el = document.getElementById(el);
 	}
 	yPos = el.offsetTop;
 	tempEl = el.offsetParent;
 	while (tempEl != null)
 	{
 		yPos += tempEl.offsetTop;
 		tempEl = tempEl.offsetParent;
 	}
 
 //	if (obj.y) return obj.y;
 	return yPos;
 }
 
 function show_viewmenu_old($toolbar, $button_id)
 {
 	var $img = $toolbar.GetButtonImage($button_id);
 	var $pos_x = getRealLeft($img) - ((document.all) ? 6 : -2);
 	var $pos_y = getRealTop($img) + 32;
 
 	var $prefix_special = '';
 	window.triedToWriteMenus = false;
 
 	if($ViewMenus.length == 1)
 	{
 		$prefix_special = $ViewMenus[$ViewMenus.length-1];
 		$fw_menus[$prefix_special+'_view_menu']();
 		$Menus[$prefix_special+'_view_menu'].writeMenus('MenuContainers['+$prefix_special+']');
 		window.FW_showMenu($Menus[$prefix_special+'_view_menu'], $pos_x, $pos_y);
 	}
 	else
 	{
 		// prepare menus
 		for(var $i in $ViewMenus)
 		{
 			$prefix_special = $ViewMenus[$i];
 			$fw_menus[$prefix_special+'_view_menu']();
 		}
 		$Menus['mixed'] = new Menu('ViewMenu_mixed');
 
 		// merge menus into new one
 		for(var $i in $ViewMenus)
 		{
 			$prefix_special = $ViewMenus[$i];
 			$Menus['mixed'].addMenuItem( $Menus[$prefix_special+'_view_menu'] );
 		}
 
 		$Menus['mixed'].writeMenus('MenuContainers[mixed]');
 		window.FW_showMenu($Menus['mixed'], $pos_x, $pos_y);
 	}
 }
 
 var nlsMenuRendered = false;
 function show_viewmenu($toolbar, $button_id)
 {
 	if($ViewMenus.length == 1) {
 		$prefix_special = $ViewMenus[$ViewMenus.length-1];
 		menu_to_show = $prefix_special+'_view_menu';
 	}
 	else
 	{
 		mixed_menu = menuMgr.createMenu(rs('mixed_menu'));
 		mixed_menu.applyBorder(false, false, false, false);
 		mixed_menu.dropShadow("none");
 		mixed_menu.showIcon = true;
 
 		// merge menus into new one
 		for(var $i in $ViewMenus)
 		{
 			$prefix_special = $ViewMenus[$i];
 			mixed_menu.addItem( rs($prefix_special+'.view.menu.mixed'),
 													$MenuNames[$prefix_special+'_view_menu'],
 													'javascript:void()', null, true, null,
 													rs($prefix_special+'.view.menu'),$MenuNames[$prefix_special+'_view_menu'] );
 		}
 
 		menu_to_show = 'mixed_menu';
 	}
 
 	renderMenus();
 
 	nls_showMenu(rs(menu_to_show), $toolbar.GetButtonImage($button_id))
 }
 
 function renderMenus()
 {
 	menuMgr.renderMenus('nlsMenuPlace');
 	nlsMenuRendered = true;
 }
 
 function set_window_title($title)
 {
 	var $window = window;
 
 	if ($window.name != 'main') {
 		// traverse through real popups
 		$window = getFrame('main');
 	}
 
 	$window.top.document.title = (main_title.length ? main_title + ' - ' : '') + $title;
 
 	if ($modal_windows) {
 		$window.TB.setWindowTitle('');
 	}
 }
 
 function set_filter($prefix_special, $filter_id, $filter_value, $ajax)
 {
 	set_form($prefix_special, $ajax);
 	set_hidden_field('filter_id', $filter_id);
 	set_hidden_field('filter_value', $filter_value);
 	submit_event($prefix_special, 'OnSetFilter', null, null, $ajax);
 }
 
 function filters_remove_all($prefix_special, $ajax)
 {
 	set_form($prefix_special, $ajax);
 	submit_event($prefix_special,'OnRemoveFilters', null, null, $ajax);
 }
 
 function filters_apply_all($prefix_special, $ajax)
 {
 	set_form($prefix_special, $ajax);
 	submit_event($prefix_special,'OnApplyFilters', null, null, $ajax);
 }
 
 function filter_toggle($row_id, $prefix) {
 //	var $row = $('#' + jq($row_id));
 
 	var $row = $('tr.to-range-filter');
 	var $hidden = $row.hasClass('hidden-filter');
 
 	if ($hidden) {
 		$('td', $row).show();
 
 		$row.removeClass('hidden-filter');
 	}
 	else {
 		$('td', $row).hide();
 
 		$row.addClass('hidden-filter');
 	}
 
 	// recalculate filter row heights/widths
 	var $grid = GridScrollers[$prefix];
 	$grid.UpdateColWidths();
 
 	if ($hidden && $grid.FiltersExpanded !== true) {
 		$grid.AdjustInputWidths();
 		$grid.FiltersExpanded = true;
 	}
 
 //	$grid.SetLeftHeights();
 //	$grid.UpdateTotalDimensions();
 //	$grid.SyncScroll();
 
 //	$grid.Resize( $grid.GetAutoSize() );
 }
 
 function RemoveTranslationLink($string, $escaped)
 {
 	if (!isset($escaped)) $escaped = true;
 
 	if ($escaped) {
 		return $string.replace(/&lt;a href=&quot;(.*?)&quot;&gt;(.*?)&lt;\/a&gt;/g, '$2');
 	}
 
 	return $string.replace(/<a href="(.*?)">(.*?)<\/a>/g, '$2');
 }
 
 function redirect($url)
 {
 	window.location.href = $url;
 }
 
 function update_checkbox_options($cb_mask, $hidden_id)
 {
 	var $kf = document.getElementById($form_name);
 	var $tmp = '';
 	for (var i = 0; i < $kf.elements.length; i++)
 	{
 		if ( $kf.elements[i].id.match($cb_mask) )
 		{
 			if ($kf.elements[i].checked) $tmp += '|'+$kf.elements[i].value;
 		}
 	}
 	if($tmp.length > 0) $tmp += '|';
 	document.getElementById($hidden_id).value = $tmp.replace(/,$/, '');
 }
 
 function update_multiple_options($hidden_id) {
 	var $select = document.getElementById($hidden_id + '_select');
 	var $result = '';
 
 	for (var $i = 0; $i < $select.options.length; $i++) {
 		if ($select.options[$i].selected) {
 			$result += $select.options[$i].value + '|';
 		}
 	}
 	document.getElementById($hidden_id).value = $result ? '|' + $result : '';
 }
 
 // related to lists operations (moving)
 
 	function move_selected($from_list, $to_list, $error_msg)
 	{
 		if (typeof($from_list) != 'object') $from_list = document.getElementById($from_list);
 		if (typeof($to_list) != 'object') $to_list = document.getElementById($to_list);
 
 		if (has_selected_options($from_list))
 		{
 			var $from_array = select_to_array($from_list);
 			var $to_array = select_to_array($to_list);
 			var $new_from = Array();
 			var $cur = null;
 
 			for (var $i = 0; $i < $from_array.length; $i++)
 			{
 				$cur = $from_array[$i];
 				if ($cur[2]) // If selected - add to To array
 				{
 					$to_array[$to_array.length] = $cur;
 				}
 				else //Else - keep in new From
 				{
 					$new_from[$new_from.length] = $cur;
 				}
 			}
 
 			$from_list = array_to_select($new_from, $from_list);
 			$to_list = array_to_select($to_array, $to_list);
 		}
 		else
 		{
 			alert(isset($error_msg) ? $error_msg : 'Please select items to perform moving!');
 		}
 	}
 
 	function select_to_array($aSelect)
 	{
 		var $an_array = new Array();
 		var $cur = null;
 
 		for (var $i = 0; $i < $aSelect.length; $i++)
 		{
 			$cur = $aSelect.options[$i];
 			$an_array[$an_array.length] = new Array($cur.text, $cur.value, $cur.selected);
 		}
 		return $an_array;
 	}
 
 	function array_to_select($anArray, $aSelect)
 	{
 		var $initial_length = $aSelect.length;
 		for (var $i = $initial_length - 1; $i >= 0; $i--)
 		{
 			$aSelect.options[$i] = null;
 		}
 
 		for (var $i = 0; $i < $anArray.length; $i++)
 		{
 			$cur = $anArray[$i];
 			$aSelect.options[$aSelect.length] = new Option($cur[0], $cur[1]);
 		}
 	}
 
 	function select_compare($a, $b)
 	{
 		if ($a[0] < $b[0])
 			return -1;
 		if ($a[0] > $b[0])
 			return 1;
 		return 0;
 	}
 
 	function select_to_string($aSelect)
 	{
 		var $result = '';
 		var $cur = null;
 
 		if (typeof($aSelect) != 'object') $aSelect = document.getElementById($aSelect);
 
 		for (var $i = 0; $i < $aSelect.length; $i++)
 		{
 			$result += $aSelect.options[$i].value + '|';
 		}
 
 		return $result.length ? '|' + $result : '';
 	}
 
 	function selected_to_string($aSelect)
 	{
 		var $result = '';
 		var $cur = null;
 
 		if (typeof($aSelect) != 'object') $aSelect = document.getElementById($aSelect);
 
 		for (var $i = 0; $i < $aSelect.length; $i++)
 		{
 			$cur = $aSelect.options[$i];
 			if ($cur.selected && $cur.value != '')
 			{
 				$result += $cur.value + '|';
 			}
 		}
 
 		return $result.length ? '|' + $result : '';
 	}
 
 	function string_to_selected($str, $aSelect)
 	{
 		var $cur = null;
 		for (var $i = 0; $i < $aSelect.length; $i++)
 		{
 			$cur = $aSelect.options[$i];
 			$aSelect.options[$i].selected = $str.match('\\|' + $cur.value + '\\|') ? true : false;
 		}
 	}
 
 	function set_selected($selected_options, $aSelect)
 	{
 		if (!$selected_options.length) return false;
 
 		for (var $i = 0; $i < $aSelect.length; $i++)
 		{
 			for (var $k = 0; $k < $selected_options.length; $k++)
 			{
 				if ($aSelect.options[$i].value == $selected_options[$k])
 				{
 					$aSelect.options[$i].selected = true;
 				}
 			}
 		}
 	}
 
 	function get_selected_count($theList)
 	{
 		var $count = 0;
 		var $cur = null;
 		for (var $i = 0; $i < $theList.length; $i++)
 		{
 			$cur = $theList.options[$i];
 			if ($cur.selected) $count++;
 		}
 		return $count;
 	}
 
 	function get_selected_index($aSelect, $typeIndex)
 	{
 		var $index = 0;
 		for (var $i = 0; $i < $aSelect.length; $i++)
 		{
 			if ($aSelect.options[$i].selected)
 			{
 				$index = $i;
 				if ($typeIndex == 'firstSelected') break;
 			}
 		}
 		return $index;
 	}
 
 	function has_selected_options($theList)
 	{
 		var $ret = false;
 		var $cur = null;
 
 		for (var $i = 0; $i < $theList.length; $i++)
 		{
 			$cur = $theList.options[$i];
 			if ($cur.selected) {
 				$ret = true;
 				break;
 			}
 		}
 		return $ret;
 	}
 
 	function select_sort($aSelect)
 	{
 		if (typeof($aSelect) != 'object') $aSelect = document.getElementById($aSelect);
 
 		var $to_array = select_to_array($aSelect);
 		$to_array.sort(select_compare);
 		array_to_select($to_array, $aSelect);
 	}
 
 	function move_options_up($aSelect, $interval)
 	{
 		if (typeof($aSelect) != 'object') $aSelect = document.getElementById($aSelect);
 
 		if (has_selected_options($aSelect))
 		{
 			var $selected_options = Array();
 			var $first_selected = get_selected_index($aSelect, 'firstSelected');
 
 			for (var $i = 0; $i < $aSelect.length; $i++)
 			{
 				if ($aSelect.options[$i].selected && ($first_selected > 0) )
 				{
 					swap_options($aSelect, $i, $i - $interval);
 					$selected_options[$selected_options.length] = $aSelect.options[$i - $interval].value;
 				}
 				else if ($first_selected == 0)
 				{
 					//alert('Begin of list');
 					break;
 				}
 			}
 			set_selected($selected_options, $aSelect);
 		}
 		else
 		{
 			//alert('Check items from moving');
 		}
 	}
 
 	function move_options_down($aSelect, $interval)
 	{
 		if (typeof($aSelect) != 'object') $aSelect = document.getElementById($aSelect);
 
 		if (has_selected_options($aSelect))
 		{
 			var $last_selected = get_selected_index($aSelect, 'lastSelected');
 			var $selected_options = Array();
 
 			for (var $i = $aSelect.length - 1; $i >= 0; $i--)
 			{
 				if ($aSelect.options[$i].selected && ($aSelect.length - ($last_selected + 1) > 0))
 				{
 					swap_options($aSelect, $i, $i + $interval);
 					$selected_options[$selected_options.length] = $aSelect.options[$i + $interval].value;
 				}
 				else if ($last_selected + 1 == $aSelect.length)
 				{
 					//alert('End of list');
 					break;
 				}
 			}
 			set_selected($selected_options, $aSelect);
 		}
 		else
 		{
 			//alert('Check items from moving');
 		}
 	}
 
 	function swap_options($aSelect, $src_num, $dst_num)
 	{
 		var $src_html = $aSelect.options[$src_num].innerHTML;
 		var $dst_html = $aSelect.options[$dst_num].innerHTML;
 		var $src_value = $aSelect.options[$src_num].value;
 		var $dst_value = $aSelect.options[$dst_num].value;
 
 		var $src_option = document.createElement('OPTION');
 		var $dst_option = document.createElement('OPTION');
 
 		$aSelect.remove($src_num);
 		$aSelect.options.add($dst_option, $src_num);
 		$dst_option.innerText = $dst_html;
 		$dst_option.value = $dst_value;
 		$dst_option.innerHTML = $dst_html;
 
 		$aSelect.remove($dst_num);
 		$aSelect.options.add($src_option, $dst_num);
 		$src_option.innerText = $src_html;
 		$src_option.value = $src_value;
 		$src_option.innerHTML = $src_html;
 	}
 
 	function getXMLHTTPObject(content_type)
     {
     	if (!isset(content_type)) content_type = 'text/plain';
     	var http_request = false;
         if (window.XMLHttpRequest) { // Mozilla, Safari,...
             http_request = new XMLHttpRequest();
             if (http_request.overrideMimeType) {
                 http_request.overrideMimeType(content_type);
                 // See note below about this line
             }
         } else if (window.ActiveXObject) { // IE
             try {
                 http_request = new ActiveXObject("Msxml2.XMLHTTP");
             } catch (e) {
                 try {
                     http_request = new ActiveXObject("Microsoft.XMLHTTP");
                 } catch (e) {}
             }
         }
         return http_request;
     }
 
   function str_repeat($symbol, $count)
 	{
 		var $i = 0;
 		var $ret = '';
 		while($i < $count) {
 			$ret += $symbol;
 			$i++;
 		}
 		return $ret;
 	}
 
 	function getDocumentFromXML(xml)
 	{
 		if (window.ActiveXObject) {
 			var doc = new ActiveXObject("Microsoft.XMLDOM");
 			doc.async=false;
 			doc.loadXML(xml);
 		}
 		else {
 			var parser = new DOMParser();
 			var doc = parser.parseFromString(xml,"text/xml");
 		}
 		return doc;
 	}
 
 	function set_persistant_var($var_name, $var_value, $t, $form_action)
 	{
 		set_hidden_field('field', $var_name);
 		set_hidden_field('value', $var_value);
 		submit_event('u', 'OnSetPersistantVariable', $t, $form_action);
 	}
 
 	function setCookie($Name, $Value)
 	{
 		// set cookie
 		if (getCookie($Name) != $Value) {
 			document.cookie = $Name+'='+escape($Value);
 		}
 	}
 
 	function getCookie($Name)
 	{
 		// get cookie
 
 		var $cookieString = document.cookie;
 		var $index = $cookieString.indexOf($Name+'=');
 		if ($index == -1) {
 			return null;
 		}
 
 		$index = $cookieString.indexOf('=',$index)+1;
 		var $endstr = $cookieString.indexOf(';',$index);
 		if($endstr == -1) $endstr = $cookieString.length;
 
 		return unescape($cookieString.substring($index, $endstr));
 	}
 
 	function deleteCookie($Name)
 	{
 		// deletes cookie
 		if (getCookie($Name)) {
 	    	var d = new Date();
 			document.cookie = $Name + '=;expires=' + d.toGMTString() + ';' + ';';
 	    }
 	}
 
 	function addElement($dst_element, $tag_name) {
 		var $new_element = document.createElement($tag_name.toUpperCase());
 		$dst_element.appendChild($new_element);
 		return $new_element;
 	}
 
 	Math.sum = function($array) {
 		var $i = 0;
 		var $total = 0;
 		while ($i < $array.length) {
 			$total += $array[$i];
 			$i++;
 		}
 		return $total;
 	}
 
 	Math.average = function($array) {
 		return Math.sum($array) / $array.length;
 	}
 
 	// remove spaces and underscores from a string, used for nls_menu
 	function rs(str, is_phrase)
 	{
 		if (isset(is_phrase) && is_phrase) {
 			str = RemoveTranslationLink(str, false);
 		}
 
 		return str.replace(/[ _\']+/g, '.');
 	}
 
 	function getFrame($name)
 	{
 		var $main_window = window;
 
 		// 1. cycle through popups to get main window
 		try {
 			// will be error, when other site is opened in parent window
 			var $i = 0;
 			var $opener;
 
 			do {
 				if ($i == 10) {
 					break;
 				}
 
 				// get popup opener
 				$opener = $main_window.opener;
 
 				if (!$opener) {
 					// when no opener found, then try parent window
 					$opener = $main_window.parent;
 				}
 
 				if ($opener) {
 					$main_window = $opener;
 				}
 
 				$i++;
 			} while ($opener);
 		}
 		catch (err) {
 			// catch Access/Permission Denied error
 //			alert('getFrame.Error: [' + err.description + ']');
 			return window;
 		}
 
 		var $frameset = $main_window.parent.frames;
 		for ($i = 0; $i < $frameset.length; $i++) {
 			if ($frameset[$i].name == $name) {
 	    		return $frameset[$i];
 	    	}
 		}
 		return $main_window.parent;
 	}
 
 	function ClearBrowserSelection()
 	{
 		if (window.getSelection) {
 			// removeAllRanges will be supported by Opera from v 9+, do nothing by now
 			var selection = window.getSelection();
 			if (selection.removeAllRanges) { // Mozilla & Opera 9+
 //				alert('clearing FF')
 				window.getSelection().removeAllRanges();
 			}
 	 	} else if (document.selection && !is.opera) { // IE
 //	 		alert('clearing IE')
 	 		document.selection.empty();
 	 	}
 	}
 
 	function reset_form(prefix, event, msg)
 	{
 		if (confirm(RemoveTranslationLink(msg, true))) {
 			submit_event(prefix, event)
 		}
 	}
 
 	function cancel_edit(prefix, cancel_ev, save_ev, msg)
 	{
 		if ((!Form || (Form && Form.HasChanged)) && confirm(RemoveTranslationLink(msg, true))) {
 			submit_event(prefix, save_ev)
 		}
 		else {
 			submit_event(prefix, cancel_ev)
 		}
 	}
 
 
 
 function execJS(node)
 {
   var bSaf = (navigator.userAgent.indexOf('Safari') != -1);
   var bOpera = (navigator.userAgent.indexOf('Opera') != -1);
   var bMoz = (navigator.appName == 'Netscape');
 
   if (!node) return;
 
   /* IE wants it uppercase */
   var st = node.getElementsByTagName('SCRIPT');
   var strExec;
 
   for(var i=0;i<st.length; i++)
   {
     if (bSaf) {
       strExec = st[i].innerHTML;
       st[i].innerHTML = "";
     } else if (bOpera) {
       strExec = st[i].text;
       st[i].text = "";
     } else if (bMoz) {
       strExec = st[i].textContent;
       st[i].textContent = "";
     } else {
       strExec = st[i].text;
       st[i].text = "";
     }
 
     try {
       var x = document.createElement("script");
       x.type = "text/javascript";
 
       /* In IE we must use .text! */
       if ((bSaf) || (bOpera) || (bMoz))
         x.innerHTML = strExec;
       else x.text = strExec;
 
       document.getElementsByTagName("head")[0].appendChild(x);
     } catch(e) {
       alert(e);
     }
   }
 };
 
 function NumberFormatter() {}
 
 NumberFormatter.ThousandsSep = '\'';
 NumberFormatter.DecimalSep = '.';
 
 NumberFormatter.Parse = function(num)
 {
 	if (num == '') return 0;
 	return parseFloat( num.toString().replace(this.ThousandsSep, '').replace(this.DecimalSep, '.') );
 }
 
 NumberFormatter.Format = function(num)
 {
 	num += '';
 	x = num.split('.');
 	x1 = x[0];
 	x2 = x.length > 1 ? this.DecimalSep + x[1] : '';
 	var rgx = /(\d+)(\d{3})/;
 	while (rgx.test(x1)) {
 		x1 = x1.replace(rgx, '$1' + this.ThousandsSep + '$2');
 	}
 	return x1 + x2;
 }
 
 function getDimensions(obj) {
 	var style
 	if (obj.currentStyle) {
 		style = obj.currentStyle;
 	}
 	else {
 		style = getComputedStyle(obj,'');
 	}
 	padding = [parseInt(style.paddingTop), parseInt(style.paddingRight), parseInt(style.paddingBottom), parseInt(style.paddingLeft)]
 	border = [parseInt(style.borderTopWidth), parseInt(style.borderRightWidth), parseInt(style.borderBottomWidth), parseInt(style.borderLeftWidth)]
 	for (var i = 0; i < padding.length; i++)  if ( isNaN( padding[i] ) ) padding[i] = 0
 	for (var i = 0; i < border.length; i++)  if ( isNaN( border[i] ) ) border[i] = 0
 
 	var result = new Object();
 	result.innerHeight = obj.clientHeight - padding[0] - padding[2];
 	result.innerWidth = obj.clientWidth - padding[1] - padding[3];
 	result.padding = padding;
 	result.borders = border;
 
 	result.outerHeight = obj.clientHeight + border[0] + border[2];
 	result.outerWidth = obj.clientHeight + border[1] + border[3];
 
 	return result;
 }
 
 function findPos(obj, with_scroll) {
 	/*var $offset = $(obj).offset();
 
 	return [$offset.left, $offset.top];*/
 
 	if (!with_scroll) var with_scroll = false;
 	var curleft = curtop = 0;
 
 	if (obj.offsetParent) {
 		curleft = obj.offsetLeft - (with_scroll ? obj.scrollLeft : 0)
 		curtop = obj.offsetTop - (with_scroll ? obj.scrollTop : 0)
 		while (obj = obj.offsetParent) {
 			curleft += obj.offsetLeft - (with_scroll ? obj.scrollLeft : 0)
 			curtop += obj.offsetTop - (with_scroll ? obj.scrollTop : 0)
 		}
 	}
 
 	return [curleft,curtop];
 }
 
 function scrollbarWidth() {
 	// Scrollbalken im Body ausschalten
 	var $overflow_backup = document.body.style.overflow;
 	document.body.style.overflow = 'hidden';
 
 	var width = document.body.clientWidth;
 
 	// Scrollbalken
 	document.body.style.overflow = 'scroll';
 	width -= document.body.clientWidth;
 
 	// Der IE im Standardmode
 	if (!width) {
 		width = document.body.offsetWidth - document.body.clientWidth;
 	}
 
 	// urspr?ngliche Einstellungen
 	document.body.style.overflow = $overflow_backup;
 
 	return width;
 }
 
 function maximizeElement($selector, $max_height) {
 	if ($max_height === undefined) {
 		$max_height = false;
 	}
 
 	var $element = $($selector);
 	if ($element.length == 0) {
 		return ;
 	}
 
 	$element.width('100%');
 
 	var $container_id = $element.attr('id') + '_container';
 	var $container = $( jq('#' + $container_id) );
 
 	if ($container.length == 0) {
 		// don't create same container twice
 
 		// all <script> tags will be executed again after wrap method is called, so remove them to prevent that
 		$('script', $element).remove();
 		$element.wrap('<div id="' + $container_id + '" style="position: relative; overflow: auto; width: 100%;"></div>');
 		$container = $( jq('#' + $container_id) );
 
 		$(window).resize(
 			function() {
 				maximizeElement($selector, $max_height);
 			}
 		);
 	}
 
 	var $offset_top = $container.offset().top;
 	var $window_height = $(window).height();
 
 	var $height_left = $window_height - $offset_top;
 
 	if (($max_height !== false) && ($max_height < $height_left)) {
 		$height_left = $max_height;
 	}
 
 	$height_left -= ($element.outerHeight() - $element.height());
 	$container.height($height_left);
 
 	var $element_width = $(window).width() - ($element.outerWidth() - $element.width());
 	if ( $height_left < $element.height() ) {
 		// needs vertical scrolling, so substract vertical scrollbar width
 		$element_width -= scrollbarWidth();
 	}
 
 	$element.width($element_width);
 }
 
 function addEvent(el, evname, func, traditional) {
 	if (traditional) {
 		eval('el.on'+evname+'='+func);
 		return;
 	}
 
 	if (evname.match(/mousedown|mousemove|mouseup/)) {
 		$(el)
 		.unbind(evname) // don't allow more then one
 		.bind(evname, func);
 		return ;
 	}
 
 	if (is.ie) {
 		el.attachEvent("on" + evname, func);
 	} else {
 		el.addEventListener(evname, func, true);
 	}
 };
 
 /*function removeEvent(el, evname, func) {
 	if (is.ie) {
 		el.detachEvent('on' + evname, func);
 	} else {
 		el.removeEventListener(evname, func, true);
 	}
 }*/
 
 function addLoadEvent(func, wnd)
 {
 	Application.setHook('m:OnAfterWindowLoad', func);
 }
 
 function replaceFireBug() {
 	if (window.console === undefined || !console.firebug) {
 	    var names = [
 	    	'log', 'debug', 'info', 'warn', 'error', 'assert', 'dir', 'dirxml',
 	    	'group', 'groupEnd', 'time', 'timeEnd', 'count', 'trace', 'profile', 'profileEnd'
 	    ];
 
 	    if (window.top.console !== undefined || window.top.firebug) {
 	    	// console is not defined in iframes, so define it here
 	    	window.console = window.top.console;
 	    	window._getFirebugConsoleElement = window.top._getFirebugConsoleElement;
 	    }
 	    else {
 	    	window.console = {};
 
 	    	for (var i = 0; i < names.length; ++i) {
 		        window.console[names[i]] = function($msg) {
 		        	alert('FireBug console object methods are not available outside Firefox!' + "\n" + $msg);
 		        }
 		    }
 	    }
 	}
 }
 function runOnChange(elId) {
 	var evt;
 	var el = typeof(elId) == 'string' ? document.getElementById(elId) : elId
 	if (document.createEvent) {
 		evt = document.createEvent("HTMLEvents");
 		evt.initEvent("change", true, false);
 		(evt) ? el.dispatchEvent(evt) : (el.onchange && el.onchange());
 		return;
 	}
 	if (el.fireEvent) {
 		el.fireEvent('onchange');
 	}
 }
 function WatchClosing(win, $url)
 {
 	window.setTimeout(function() {
 			if (win.closed) {
 				var req = Request.getRequest();
 				var $ajax_mark = ($url.indexOf('?') ? '&' : '?') + 'ajax=yes';
 				req.open('GET', $url + $ajax_mark, false); //!!!SYNCRONIOUS!!! REQUEST (3rd param = false!!!)
 				req.send(null);
 			}
 		},
 		2000
 	)
 }
 
 function IterateUploaders($method) {
 	if (typeof UploadsManager != 'undefined') {
 		UploadsManager.iterate($method);
 	}
 }
 
 String.prototype.trim = function () {
 	return this.replace(/\s*((\S+\s*)*)/, "$1").replace(/((\s*\S+)*)\s*/, "$1");
 }
 
 String.prototype.toNumeric = function () {
 	return parseInt( this.replace(/(auto|medium)/, '0px').replace(/[a-z]/gi,'') );
 }
 
 function jq($selector) {
 	return $selector.replace(/(\[|\]|\.)/g, '\\$1');
 }
 
 function setHelpLink($user_docs_url, $title_preset) {
 	if (!$user_docs_url) {
 		return ;
 	}
 
 	$('#help_link', getFrame('head').document).attr('href', $user_docs_url + '/' + $title_preset);
 }
 
 // window management functions:
 
 function getWindowOpener($window) {
 	// use this intead of "window.opener"
 	if (!$modal_windows) {
 		return $window.opener;
 	}
 
 	if ($window.name == 'main' || $window.name == 'main_frame') {
 		return null;
 	}
 
 	return getFrame('main').TB.findWindow($window.name, -1);
 }
 
 function window_close($close_callback) {
 	// use this instead of "window.close();"
 	if (!$modal_windows) {
 		if ($.isFunction($close_callback)) {
 			// use close callback, because iframe will be removed later in this method
 			$close_callback();
 		}
 
 		window.close();
 		return ;
 	}
 
 	if (window.name == 'main') {
 		return ;
 	}
 
 	if ($close_callback !== undefined) {
 		return getFrame('main').TB.remove(null, $close_callback);
 	}
 
 	return getFrame('main').TB.remove();
 }
 
 Array.prototype.each = function($callback) {
 	var $result = null;
 
 	for (var $i = 0; $i < this.length; $i++) {
 		$result = $callback.call(this[$i], $i);
 		if ($result === false) {
 			break;
 		}
 	}
 }
\ No newline at end of file
Index: branches/5.0.x/core/admin_templates/js/template_manager.js
===================================================================
--- branches/5.0.x/core/admin_templates/js/template_manager.js	(revision 12297)
+++ branches/5.0.x/core/admin_templates/js/template_manager.js	(revision 12298)
@@ -1,200 +1,313 @@
 function TemplateManager ($edit_url, $browse_url, $save_layout_url, $edting_mode) {
 	this._editUrl = $edit_url;
 	this.browseUrl = $browse_url;
 	this._saveLayoutUrl = $save_layout_url;
-	this.editingMode = $edting_mode; // from 1 to 4
+	this.editingMode = $edting_mode; // from {1 - browse, 2 - content, 3 - design}
 
 	this._blocks = {};
-
 	this._blockOrder = Array ();
+	this.inDrag = false; // don't process mouse over/out events while in drag mode
 
 	var $template_manager = this;
 
 	$(document).ready(
 		function() {
 			$template_manager.searchBlocks();
 
 			if (!$template_manager.editingMode) {
 				return ;
 			}
 
-			// show special toolbar when in any of 4 browse modes
+			// show special toolbar when in any of 3 browse modes
 			var $head_frame = getFrame('head');
 			var $extra_toolbar = $head_frame.$('div.front-extra-toolbar').clone(); // clone to keep original untouched
 
 			$('a', $extra_toolbar).each(
 				function() {
 					// cut from end, because IE7 adds base_href to beginning of href
 					var $editing_mode = $(this).attr('href');
 					$editing_mode = $editing_mode.substr($editing_mode.length - 1, 1);
 
 					$(this).attr('href', $template_manager.browseUrl.replace('#EDITING_MODE#', $editing_mode));
 
 					if ($editing_mode == $template_manager.editingMode) {
 						$(this).parents('td:first').addClass('button-active').prevAll('td:first').addClass('button-active');
 					}
 				}
 			);
 
 			$head_frame.$('#extra_toolbar').html( $extra_toolbar.html() );
 
 			if ($template_manager.editingMode == 2) {
-				// Layout Mode
+				// Content Mode
+
+				$('div.cms-edit-btn')
+				.mouseover(
+					function(e) {
+						$(this).css('opacity', 1);
+					}
+				)
+				.mouseout(
+					function(e) {
+						$(this).css('opacity', 0.5);
+					}
+				);
+
+				// make all spans with phrases clickable
+				$template_manager.setupEditTranslationButtons(document);
+			}
+
+			if ($template_manager.editingMode == 3) {
+				// Design Mode
 
 				$template_manager.renumberMovableElements();
 
 				$('div.movable-area').sortable(
 					{
 						placeholder: 'move-helper',
 						handle: '.movable-header',
 						items: 'div.movable-element',
 						connectWith: ['div.movable-area'],
 						tolerance: 'pointer',
 						start: function(e, ui) {
+							$template_manager.inDrag = true;
 							ui.placeholder.height( ui.item.height() );
+						},
+						stop: function(e, ui) {
+							$template_manager.inDrag = false;
+
+							// mouseout doesn't happen while in drag, so compensate it here
+							var $header = $('.movable-header', ui.item);
+							$('div.block-edit-block-btn-container', $header).mouseout();
+						},
+						change: function(e, ui) {
+							$('div.cms-layout-btn-container').show();
 						}
 					}
 				);
 			}
+		}
+	);
+}
+
+TemplateManager.prototype.setupEditTranslationButtons = function ($container) {
+	$("span[name='cms-translate-phrase']", $container).each(
+		function() {
+			var $me = $(this);
+			var $parent_link = $me.parents('a:first');
+
+			if ($parent_link.length == 0) {
+				// span in not inside "a" tag
 
-			$('div.cms-edit-btn')
+				$me.prepend('<div class="cms-edit-btn"><div class="cms-btn-text">Edit</div></div>');
+				$('div.cms-edit-btn:first', $me).click(TemplateManager.prototype.translatePhrase);
+				$me.dblclick(
+					function ($e) {
+						$('div.cms-edit-btn:first', this).click();
+						return false;
+					}
+				);
+
+				var $effect_element = $me;
+			}
+			else {
+				// span is inside "a" tag
+				var $clone = $me.clone();
+				$clone.empty().attr('title', '');
+
+				$parent_link.html( $me.html() ).wrap($clone);
+				$parent_link.before('<div class="cms-edit-btn" title="' + $me.attr('title') + '"><div class="cms-btn-text">Edit</div></div>');
+				$parent_link.prev('div.cms-edit-btn:first').click(TemplateManager.prototype.translatePhrase);
+
+				var $effect_element = $parent_link.parents("span[name='cms-translate-phrase']:first");
+			}
+
+			$effect_element
 			.mouseover(
-				function(e) {
-					$(this).css('opacity', 1);
+				function($e) {
+					$('div.cms-edit-btn', this).css('display', 'inline');
 				}
 			)
 			.mouseout(
-				function(e) {
-					$(this).css('opacity', 0.5);
+				function($e) {
+					$('div.cms-edit-btn', this).hide();
 				}
 			);
 		}
 	);
 }
 
+TemplateManager.prototype.translatePhrase = function ($e) {
+	var $translate_url = $(this).parents("span[name='cms-translate-phrase']:first").attr('href');
+
+	if ($translate_url.match(/javascript:(.*)/)) {
+		eval(RegExp.$1);
+	}
+	else {
+		window.location.href = RegExp.$1;
+	}
+
+	return false;
+}
+
 TemplateManager.prototype.renumberMovableElements = function () {
 	var $area_index = 0;
 	// 1. dynamically assign IDs to all movable elements
 	$('div.movable-area').each(
 		function() {
 			var $element_index = 0;
 			$('div.movable-element', this).each(
 				function() {
 					$(this).attr('id', 'target_order_a' + $area_index + 'e' + $element_index);
 					$element_index++;
 				}
 			);
 
 			$area_index++;
 		}
 	);
 }
 
 TemplateManager.prototype.saveLayout = function () {
 	// prepare order string
 	var $sort_order = [];
 	$('div.movable-area').each(
 		function($area_index) {
 			var $order = $(this).sortable('serialize').replace(/target_order\[\]/g, 'target_order[' + $area_index + '][]');
 			if ($order) {
 				$sort_order.push($order);
 			}
 		}
 	);
 	$sort_order = $sort_order.join('&');
 
 	// save order string
 	var $me = this;
 
 	var $settings = {
 		url: this._saveLayoutUrl + '&' + $sort_order + '&width=200&height=70&modal=true',
 		caption: 'Layout Saving Result',
 		onDataReceived: function ($data) {
 			var $message = '';
 
 			if ($data == 'OK') {
 				$message = 'New Layout Saved';
+				$('div.cms-layout-btn-container').hide();
 				$me.renumberMovableElements();
 			}
 			else {
 				$message = 'Failed to Save New Layout';
 			}
 
 			$data = '<div style="text-align: center;">' + $message + '<br/><br/><input type="button" class="button" value="OK" onclick="TB.remove();"/></div>';
 
 			return $data;
 		}
 	};
 
 	TB.setWindowTitle( window.top.document.title.replace(main_title + ' :: ', '') );
 	TB.show($settings);
 }
 
+TemplateManager.prototype.cancelLayout = function () {
+	window.location.href = window.location.href;
+}
+
 TemplateManager.prototype.onBtnClick = function ($e, $element) {
 	var $id = $element.id.replace(/_btn$/, '');
 	var $block_info = this._blocks[$id];
 	var $url = this._editUrl.replace('#BLOCK#', $block_info.block_name + ':' + $block_info.function_name).replace('#EVENT#', 'OnLoadBlock');
 
 	openSelector('theme-file', $url);
 
 	$e.stopPropagation();
 }
 
 TemplateManager.prototype.onMouseOver = function ($e, $element) {
-	$($element).addClass('block-edit-btn-container-over');
+	if (this.inDrag) {
+		return ;
+	}
+
+	$element = $($element);
+
+	if ($element.hasClass('block-edit-design-btn-container')) {
+		$($element).addClass('block-edit-design-btn-container-over');
+		$('div.cms-edit-design-btn:first', $element).show();
+	}
+	else {
+		$($element).addClass('block-edit-block-btn-container-over');
+		$('div.cms-edit-block-btn:first', $element).show();
+	}
+
 	$e.stopPropagation();
 }
 
 TemplateManager.prototype.onMouseOut = function ($e, $element) {
-	$($element).removeClass('block-edit-btn-container-over');
+	if (this.inDrag) {
+		return ;
+	}
+
+	$element = $($element);
+
+	if ($element.hasClass('block-edit-design-btn-container')) {
+		$($element).removeClass('block-edit-design-btn-container-over');
+		$('div.cms-edit-design-btn:first', $element).hide();
+	}
+	else {
+		$($element).removeClass('block-edit-block-btn-container-over');
+		$('div.cms-edit-block-btn:first', $element).hide();
+	}
+
 	$e.stopPropagation();
 }
 
 TemplateManager.prototype.searchBlocks = function () {
 	$('div').each (
 		function () {
 			var $id = $(this).attr('id');
 
 			if (!$id || $id.match(/parser_block\[.*\].*_btn$/) || !$id.match(/parser_block\[.*\]/)) {
 				// skip other divs
 				return true;
 			}
 
 			TemplateManager.prototype.registerBlock.call(aTemplateManager, this);
 		}
 	);
 }
 
 TemplateManager.prototype.registerBlock = function ($element) {
 	var $params = $element.getAttribute('params').split(':');
 
 	this._blocks[$element.id] = {
 		block_name: $params[0],
 		function_name: $params[1]
 	};
 
 	var $btn = document.getElementById($element.id + '_btn');
 
-	$($btn).bind(
-		'click',
+	$($btn).click(
 		function(ev) {
 			TemplateManager.prototype.onBtnClick.call(aTemplateManager, ev, this);
 		}
 	);
 
-	$($element).bind(
-		'mouseover',
+	$($element)
+	.dblclick(
+		function(ev) {
+			TemplateManager.prototype.onBtnClick.call(aTemplateManager, ev, this);
+		}
+	)
+	.mouseover(
 		function(ev) {
 			TemplateManager.prototype.onMouseOver.call(aTemplateManager, ev, this);
 		}
-	);
-
-	$($element).bind(
-		'mouseout',
+	)
+	.mouseout(
 		function(ev) {
 			TemplateManager.prototype.onMouseOut.call(aTemplateManager, ev, this);
 		}
 	);
 
 	this._blockOrder.push($element.id);
 }
\ No newline at end of file
Index: branches/5.0.x/core/admin_templates/incs/cms.css
===================================================================
--- branches/5.0.x/core/admin_templates/incs/cms.css	(revision 12297)
+++ branches/5.0.x/core/admin_templates/incs/cms.css	(revision 12298)
@@ -1,89 +1,156 @@
 /* === Common styles for "Section Properties" and "Edit" buttons === */
 div.cms-btn-image {
 	float: left;
 	height: 15px;
 	vertical-align: middle;
 }
 
 div.cms-btn-text {
 	margin-left: 3px;
 	float: left;
 	white-space: nowrap;
 	vertical-align: middle;
 }
 
 div.cms-btn-content {
 	padding: 5px;
 }
 
-div.cms-section-properties-btn, div.cms-edit-btn, div.cms-save-layout-btn {
+div.cms-section-properties-btn, div.cms-edit-btn, div.cms-edit-block-btn, div.cms-edit-design-btn {
 	padding: 2px 5px;
 	font-family: Arial, Verdana;
 	font-size: 13px;
 	font-weight: normal;
 	width: auto;
 	position: absolute;
 	color: black;
 	cursor: pointer;
 	-moz-border-radius: 10px;
 
 	margin-top: -10px;
 	z-index: 99;
 }
 
 /* === Styles for "Section Properties" button === */
 div.cms-section-properties-btn {
 	float: right;
 	position: relative;
 
 	margin-right: -10px;
 	border: 2px solid #A1D0A1;
 	background-color: #CCFF00;
 }
 
 div.cms-section-properties-btn-container {
 	border: 1px dashed #A1D0A1;
 	margin: 10px;
 }
 
 /* === Styles for "Edit" button === */
 div.cms-edit-btn-container {
 	border: 1px dashed #FF6E00;
 }
 
 div.cms-edit-btn {
 	margin-left: -10px;
 	border: 2px solid #FF6E00;
 	background-color: #FFCC00;
 	opacity: 0.5;
 	filter: alpha(opacity=50);
 }
 
-/* === Styles for "Save Layout" button === */
-div.cms-save-layout-btn {
-	float: left;
-	position: absolute;
+div.cms-edit-block-btn {
+	margin-left: -10px;
+	border: 2px solid #FF6E00;
+	background-color: #FFCC00;
+	display: none;
+}
 
+div.cms-edit-design-btn {
+	margin-left: -10px;
+	border: 2px solid #006E00;
+	background-color: #00CC00;
+	/*opacity: 0.5;
+	filter: alpha(opacity=50);*/
+	display: none;
+}
+
+/* === Styles for "Save" and "Cancel" buttons (for layout) === */
+div.cms-layout-btn-container {
+	position: absolute;
+	margin-top: -10px;
 	margin-left: -10px;
+	display: none;
+	z-index: 99;
+}
+
+div.cms-save-layout-btn, div.cms-cancel-layout-btn {
+	float: left;
+	padding: 2px 5px;
+	font-family: Arial, Verdana;
+	font-size: 13px;
+	font-weight: normal;
+	width: auto;
+	color: black;
+	cursor: pointer;
+	-moz-border-radius: 10px;
+}
+
+div.cms-save-layout-btn {
 	border: 2px solid #A1D0A1;
 	background-color: #CCFF00;
 }
 
+div.cms-cancel-layout-btn {
+	border: 2px solid #FF0000;
+	background-color: #FF6A5D;
+}
+
+div.cms-cancel-layout-btn {
+	margin-left: 4px;
+}
+
 /* === Styles for Template Editor === */
-div.block-edit-btn-container {
+div.block-edit-block-btn-container, div.block-edit-design-btn-container {
 	border: 1px dashed transparent;
 }
 
-div.block-edit-btn-container-over {
+div.block-edit-block-btn-container-over {
 	border-color: #FF6E00;
 }
 
+div.block-edit-design-btn-container-over {
+	border-color: #006E00;
+}
+
 /* === Styles for element moving/sorting in theme === */
 div.movable-area {
 	min-height: 200px;
 }
 
 .move-helper {
 	border: 3px dashed #666;
 	/*width: auto !important;*/
+}
+
+/* === Styles for phrase translation links === */
+span[name='cms-translate-phrase'] {
+	text-decoration: none;
+	border: 1px dashed transparent;
+	padding: 3px;
+
+}
+
+span[name='cms-translate-phrase']:hover {
+	border-color: #FF6E00;
+}
+
+span[name='cms-translate-phrase'] .cms-btn-text {
+	font-size: 9px;
+}
+
+span[name='cms-translate-phrase'] .cms-edit-btn {
+	display: none;
+	opacity: 1;
+	filter: alpha(opacity=0);
 }
\ No newline at end of file
Index: branches/5.0.x/core/admin_templates/regional/phrases_edit.tpl
===================================================================
--- branches/5.0.x/core/admin_templates/regional/phrases_edit.tpl	(revision 12297)
+++ branches/5.0.x/core/admin_templates/regional/phrases_edit.tpl	(revision 12298)
@@ -1,86 +1,108 @@
 <inp2:adm_SetPopupSize width="888" height="415"/>
-
 <inp2:m_include t="incs/header"/>
 <inp2:m_RenderElement name="combined_header" prefix="lang" section="in-portal:configure_lang" title_preset="phrase_edit"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 							submit_event('phrases','<inp2:phrases_SaveEvent/>');
 						}
 					) );
-				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
-						submit_event('phrases','OnCancel');
+
+				a_toolbar.AddButton(
+					new ToolBarButton(
+						'cancel',
+						'<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>',
+						function() {
+							<inp2:m_if check="m_Get" name="simple_mode">
+								window_close();
+							<inp2:m_else/>
+								cancel_edit('phrases', 'OnCancelEdit', '<inp2:phrases_SaveEvent/>', '<inp2:m_Phrase label="la_FormCancelConfirmation" js_escape="1"/>');
+							</inp2:m_if>
 						}
-				 ) );
+					)
+				);
 
 				a_toolbar.AddButton( new ToolBarButton('reset_edit', '<inp2:m_phrase label="la_ToolTip_Reset" escape="1"/>', function() {
 						reset_form('phrases', 'OnReset', '<inp2:m_Phrase label="la_FormResetConfirmation" escape="1"/>');
 					}
 			 	) );
 
 			 	<inp2:m_if check="phrases_IsTopmostPrefix">
 					<inp2:m_if check="phrases_IsSingle" inverse="inverse">
 						a_toolbar.AddButton( new ToolBarSeparator('sep1') );
 					</inp2:m_if>
 
 					a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
 								go_to_id('phrases', '<inp2:phrases_PrevId/>');
 							}
 					 ) );
 					a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
 								go_to_id('phrases', '<inp2:phrases_NextId/>');
 							}
 					 ) );
 				</inp2:m_if>
 
 				a_toolbar.Render();
 
 				<inp2:m_RenderElement name="edit_navigation" prefix="phrases"/>
 			</script>
 		</td>
 	</tr>
 </tbody>
 </table>
 
 <inp2:phrases_SaveWarning name="grid_save_warning"/>
 <inp2:phrases_ErrorWarning name="form_error_warning"/>
 
+<input type="hidden" name="simple_mode" value="<inp2:m_Get name='simple_mode'/>"/>
+<input type="hidden" id="phrases_label" name="phrases_label" value="<inp2:m_Get name='phrases_label'/>"/>
+
+<inp2:m_if check="phrases_ShowHiddenLanguage">
+	<inp2:m_RenderElement name="inp_edit_hidden" prefix="phrases" field="LanguageId" db="db"/>
+</inp2:m_if>
+
+<inp2:m_if check="m_Get" name="simple_mode">
+	<inp2:m_RenderElement name="inp_edit_hidden" prefix="phrases" field="Phrase"/>
+</inp2:m_if>
+
+<inp2:m_DefineElement name="phrase_element">
+	<inp2:m_if check="m_Get" name="simple_mode">
+		<inp2:m_RenderElement name="inp_label" prefix="phrases" field="PrimaryTranslation" title="!la_fld_PrimaryTranslation!"/>
+		<inp2:m_RenderElement name="inp_edit_textarea" prefix="phrases" field="Translation" title="!la_fld_Translation!" rows="7" cols="50" allow_html="0"/>
+	<inp2:m_else/>
+		<tr class="subsectiontitle">
+			<td colspan="3"><inp2:phrases_Field name="Phrase"/></td>
+		</tr>
+
+		<inp2:m_if check="m_Get" name="phrases_label">
+			<inp2:m_RenderElement name="inp_edit_options" prefix="phrases" field="LanguageId" title="la_fld_LanguageId" has_empty="1"/>
+		</inp2:m_if>
+
+		<inp2:m_RenderElement name="inp_label" prefix="phrases" field="PrimaryTranslation" title="!la_fld_PrimaryTranslation!"/>
+		<inp2:m_RenderElement name="inp_edit_box" prefix="phrases" field="Phrase" title="!la_fld_Phrase!" size="60"/>
+		<inp2:m_RenderElement name="inp_edit_textarea" prefix="phrases" field="Translation" title="!la_fld_Translation!" rows="7" cols="50" allow_html="0"/>
+
+		<inp2:m_RenderElement name="inp_edit_radio" prefix="phrases" field="PhraseType" title="!la_fld_PhraseType!"/>
+		<inp2:m_RenderElement name="inp_edit_options" prefix="phrases" field="Module" title="!la_fld_Module!"/>
+	</inp2:m_if>
+</inp2:m_DefineElement>
+
 <div id="scroll_container">
 	<table class="edit-form">
-		<input type="hidden" id="phrases_label" name="phrases_label" value="<inp2:m_get name="phrases_label"/>">
-		<inp2:m_DefineElement name="phrase_element">
-			<tr class="subsectiontitle">
-				<td colspan="3"><inp2:phrases_Field name="Phrase"/></td>
-			</tr>
-
-			<inp2:m_if check="m_Get" name="phrases_label">
-				<inp2:m_RenderElement name="inp_edit_options" prefix="phrases" field="LanguageId" title="la_fld_LanguageId" has_empty="1"/>
-			<inp2:m_else/>
-				<inp2:m_RenderElement name="inp_edit_hidden" prefix="phrases" field="LanguageId"/>
-			</inp2:m_if>
-
-			<inp2:m_RenderElement name="inp_label" prefix="phrases" field="PrimaryTranslation" title="!la_fld_PrimaryTranslation!"/>
-			<inp2:m_RenderElement name="inp_edit_box" prefix="phrases" field="Phrase" title="!la_fld_Phrase!" size="60"/>
-			<inp2:m_RenderElement name="inp_edit_textarea" prefix="phrases" field="Translation" title="!la_fld_Translation!" rows="7" cols="50" allow_html="0"/>
-
-			<inp2:m_RenderElement name="inp_edit_radio" prefix="phrases" field="PhraseType" title="!la_fld_PhraseType!"/>
-			<inp2:m_RenderElement name="inp_edit_options" prefix="phrases" field="Module" title="!la_fld_Module!"/>
-		</inp2:m_DefineElement>
-
-		<inp2:m_if check="m_GetEquals" name="phrases_label" value="ALEX, FIX IT!">
+		<!--##<inp2:m_if check="m_GetEquals" name="phrases_label" value="ALEX, FIX IT!">
 			<inp2:phrases_MultipleEditing render_as="phrase_element"/>
-		<inp2:m_else/>
+		<inp2:m_else/>##-->
 			<inp2:m_RenderElement name="phrase_element"/>
-		</inp2:m_if>
+		<!--##</inp2:m_if>##-->
 
 		<inp2:m_RenderElement name="inp_edit_filler"/>
 	</table>
 </div>
 
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: branches/5.0.x/core/admin_templates/languages/phrase_edit.tpl
===================================================================
--- branches/5.0.x/core/admin_templates/languages/phrase_edit.tpl	(revision 12297)
+++ branches/5.0.x/core/admin_templates/languages/phrase_edit.tpl	(revision 12298)
@@ -1,79 +1,108 @@
 <inp2:adm_SetPopupSize width="888" height="415"/>
 <inp2:m_include t="incs/header"/>
 <inp2:m_RenderElement name="combined_header" section="in-portal:phrases" prefix="phrases" title_preset="phrase_edit_single"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 							submit_event('phrases','<inp2:phrases_SaveEvent/>');
 						}
 					) );
-				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
-							cancel_edit('phrases','OnCancelEdit','<inp2:phrases_SaveEvent/>','<inp2:m_Phrase label="la_FormCancelConfirmation" escape="1"/>');
+
+				a_toolbar.AddButton(
+					new ToolBarButton(
+						'cancel',
+						'<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>',
+						function() {
+							<inp2:m_if check="m_Get" name="simple_mode">
+								window_close();
+							<inp2:m_else/>
+								cancel_edit('phrases', 'OnCancelEdit', '<inp2:phrases_SaveEvent/>', '<inp2:m_Phrase label="la_FormCancelConfirmation" js_escape="1"/>');
+							</inp2:m_if>
 						}
-				 ) );
+					)
+				);
 
 				 a_toolbar.AddButton( new ToolBarButton('reset_edit', '<inp2:m_phrase label="la_ToolTip_Reset" escape="1"/>', function() {
 						reset_form('phrases', 'OnReset', '<inp2:m_Phrase label="la_FormResetConfirmation" escape="1"/>');
 					}
 			 	) );
 
 				<inp2:m_if check="phrases_IsTopmostPrefix">
 					<inp2:m_if check="phrases_IsSingle" inverse="inverse">
 						a_toolbar.AddButton( new ToolBarSeparator('sep1') );
 					</inp2:m_if>
 
 					a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
 								go_to_id('phrases', '<inp2:phrases_PrevId/>');
 							}
 					 ) );
 					a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
 								go_to_id('phrases', '<inp2:phrases_NextId/>');
 							}
 					 ) );
 				</inp2:m_if>
 
 				a_toolbar.Render();
 
 				<inp2:m_RenderElement name="edit_navigation" prefix="phrases"/>
 			</script>
 		</td>
 	</tr>
 </tbody>
 </table>
 
 <inp2:phrases_SaveWarning name="grid_save_warning"/>
 <inp2:phrases_ErrorWarning name="form_error_warning"/>
 
+<input type="hidden" name="simple_mode" value="<inp2:m_Get name='simple_mode'/>"/>
+<input type="hidden" id="phrases_label" name="phrases_label" value="<inp2:m_Get name='phrases_label'/>"/>
+
+<inp2:m_if check="phrases_ShowHiddenLanguage">
+	<inp2:m_RenderElement name="inp_edit_hidden" prefix="phrases" field="LanguageId" db="db"/>
+</inp2:m_if>
+
+<inp2:m_if check="m_Get" name="simple_mode">
+	<inp2:m_RenderElement name="inp_edit_hidden" prefix="phrases" field="Phrase"/>
+</inp2:m_if>
+
+<inp2:m_DefineElement name="phrase_element">
+	<inp2:m_if check="m_Get" name="simple_mode">
+		<inp2:m_RenderElement name="inp_label" prefix="phrases" field="PrimaryTranslation" title="!la_fld_PrimaryTranslation!"/>
+		<inp2:m_RenderElement name="inp_edit_textarea" prefix="phrases" field="Translation" title="!la_fld_Translation!" rows="7" cols="50" allow_html="0"/>
+	<inp2:m_else/>
+		<tr class="subsectiontitle">
+			<td colspan="3"><inp2:phrases_Field name="Phrase"/></td>
+		</tr>
+
+		<inp2:m_if check="m_Get" name="phrases_label">
+			<inp2:m_RenderElement name="inp_edit_options" prefix="phrases" field="LanguageId" title="la_fld_LanguageId" has_empty="1"/>
+		</inp2:m_if>
+
+		<inp2:m_RenderElement name="inp_label" prefix="phrases" field="PrimaryTranslation" title="!la_fld_PrimaryTranslation!"/>
+		<inp2:m_RenderElement name="inp_edit_box" prefix="phrases" field="Phrase" title="!la_fld_Phrase!" size="60"/>
+		<inp2:m_RenderElement name="inp_edit_textarea" prefix="phrases" field="Translation" title="!la_fld_Translation!" rows="7" cols="50" allow_html="0"/>
+
+		<inp2:m_RenderElement name="inp_edit_radio" prefix="phrases" field="PhraseType" title="!la_fld_PhraseType!"/>
+		<inp2:m_RenderElement name="inp_edit_options" prefix="phrases" field="Module" title="!la_fld_Module!"/>
+	</inp2:m_if>
+</inp2:m_DefineElement>
+
 <div id="scroll_container">
 	<table class="edit-form">
-		<input type="hidden" id="phrases_label" name="phrases_label" value="<inp2:m_get name="phrases_label"/>">
-		<inp2:m_DefineElement name="phrase_element">
-			<tr class="subsectiontitle">
-				<td colspan="4"><inp2:phrases_Field name="Phrase"/></td>
-			</tr>
-
-			<inp2:m_RenderElement name="inp_edit_hidden" prefix="phrases" field="LanguageId"/>
-			<inp2:m_RenderElement name="inp_label" prefix="phrases" field="PrimaryTranslation" title="!la_fld_PrimaryTranslation!"/>
-			<inp2:m_RenderElement name="inp_edit_box" prefix="phrases" field="Phrase" title="!la_fld_Phrase!" size="60"/>
-			<inp2:m_RenderElement name="inp_edit_textarea" prefix="phrases" field="Translation" title="!la_fld_Translation!" rows="7" cols="50" allow_html="0"/>
-
-			<inp2:m_RenderElement name="inp_edit_radio" prefix="phrases" field="PhraseType" title="!la_fld_PhraseType!"/>
-			<inp2:m_RenderElement name="inp_edit_options" prefix="phrases" field="Module" title="!la_fld_Module!"/>
-		</inp2:m_DefineElement>
-
-		<inp2:m_if check="m_GetEquals" name="phrases_label" value="ALEX, FIX IT!">
+		<!--##<inp2:m_if check="m_GetEquals" name="phrases_label" value="ALEX, FIX IT!">
 			<inp2:phrases_MultipleEditing render_as="phrase_element"/>
-		<inp2:m_else/>
+		<inp2:m_else/>##-->
 			<inp2:m_RenderElement name="phrase_element"/>
-		</inp2:m_if>
+		<!--##</inp2:m_if>##-->
 
 		<inp2:m_RenderElement name="inp_edit_filler"/>
 	</table>
 </div>
+
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file