Index: branches/5.2.x/core/units/configuration/configuration_event_handler.php =================================================================== --- branches/5.2.x/core/units/configuration/configuration_event_handler.php (revision 15524) +++ branches/5.2.x/core/units/configuration/configuration_event_handler.php (revision 15525) @@ -1,562 +1,567 @@ <?php /** * @version $Id$ * @package In-Portal * @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved. * @license GNU/GPL * In-Portal is Open Source software. * This means that this software may have been modified pursuant * the GNU General Public License, and as distributed it includes * or is derivative of works licensed under the GNU General Public License * or other free or open source software licenses. * See http://www.in-portal.org/license for copyright notices and details. */ defined('FULL_PATH') or die('restricted access!'); class ConfigurationEventHandler extends kDBEventHandler { /** * Allows to override standard permission mapping * * @return void * @access protected * @see kEventHandler::$permMapping */ protected function mapPermissions() { parent::mapPermissions(); $permissions = Array ( 'OnGenerateMaintenancePage' => Array ('self' => 'add|edit'), ); $this->permMapping = array_merge($this->permMapping, $permissions); } /** * Changes permission section to one from REQUEST, not from config * * @param kEvent $event * @return bool * @access public */ public function CheckPermission(kEvent $event) { $event->setEventParam('PermSection', $this->Application->GetVar('section')); return parent::CheckPermission($event); } /** * Apply any custom changes to list's sql query * * @param kEvent $event * @return void * @access protected * @see kDBEventHandler::OnListBuild() */ protected function SetCustomQuery(kEvent $event) { parent::SetCustomQuery($event); $object = $event->getObject(); /* @var $object kDBList */ $module = $this->Application->GetVar('module'); $section = $this->Application->GetVar('section'); $object->addFilter('module_filter', '%1$s.ModuleOwner = ' . $this->Conn->qstr($module)); $object->addFilter('section_filter', '%1$s.Section = ' . $this->Conn->qstr($section)); $can_change = $this->Application->ConfigValue('AllowAdminConsoleInterfaceChange'); if ( !$can_change && !$this->Application->isDebugMode() ) { $object->addFilter('interface_change_filter', '%1$s.VariableName NOT IN ("AdminConsoleInterface", "AllowAdminConsoleInterfaceChange")'); } if ( defined('IS_INSTALL') && IS_INSTALL ) { $object->addFilter('install_filter', '%1$s.Install = 1'); } $object->addFilter('visible_filter', '%1$s.Heading <> ""'); } /** * Presets new system setting fields * * @param kEvent $event * @return void * @access protected */ protected function OnPreCreate(kEvent $event) { parent::OnPreCreate($event); $object = $event->getObject(); /* @var $object kDBItem */ $object->SetDBField('Section', $this->Application->GetVar('section')); $object->SetDBField('ModuleOwner', $this->Application->GetVar('module')); } /** * Sets custom validation * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemLoad(kEvent $event) { static $default_field_options = null; parent::OnAfterItemLoad($event); $object = $event->getObject(); /* @var $object kDBItem */ // ability to validate each configuration variable separately if ( !isset($default_field_options) ) { $default_field_options = $object->GetFieldOptions('VariableValue'); } $new_field_options = $default_field_options; $validation = $object->GetDBField('Validation'); if ( $validation ) { $new_field_options = array_merge($new_field_options, unserialize($validation)); } $object->SetFieldOptions('VariableValue', $new_field_options); } /** * Performs custom validation * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemValidate(kEvent $event) { parent::OnBeforeItemValidate($event); $object = $event->getObject(); /* @var $object kDBItem */ // if password field is empty, then don't update if ( $object->GetDBField('ElementType') == 'password' ) { if ( trim($object->GetDBField('VariableValue')) != '' ) { $password_formatter = $this->Application->recallObject('kPasswordFormatter'); /* @var $password_formatter kPasswordFormatter */ $object->SetDBField('VariableValue', $password_formatter->EncryptPassword($object->GetDBField('VariableValue'), 'b38')); } } $this->_processCountryState($event); $variable_name = $object->GetDBField('VariableName'); $new_value = $object->GetDBField('VariableValue'); if ( $variable_name == 'AdminConsoleInterface' ) { $can_change = $this->Application->ConfigValue('AllowAdminConsoleInterfaceChange'); if ( ($new_value != $object->GetOriginalField('VariableValue')) && !$can_change ) { $object->SetError('VariableValue', 'not_allowed', 'la_error_OperationNotAllowed'); } } elseif ( $variable_name == 'HardMaintenanceTemplate' ) { $compile = $event->MasterEvent->getEventParam('compile_maintenance_template'); $compile = $compile || $new_value != $object->GetOriginalField('VariableValue'); if ( $compile && !$this->_generateMaintenancePage($new_value) ) { $object->SetError('VariableValue', 'template_file_missing', 'la_error_TemplateFileMissing'); } } elseif ( $variable_name == 'DefaultEmailRecipients' ) { $email_event_data = $this->Application->GetVar('emailevents_' . $event->Prefix); $object->SetDBField('VariableValue', $email_event_data[0]['Recipients']); } $sections_helper = $this->Application->recallObject('SectionsHelper'); /* @var $sections_helper kSectionsHelper */ $section = $object->GetDBField('Section'); if ( $section && !$sections_helper->getSectionData($section) ) { $object->SetError('Section', 'unknown_section'); } } /** * Checks, that state belongs to selected country * * @param kEvent $event * @access protected */ protected function _processCountryState(kEvent $event) { $object = $event->getObject(); /* @var $object kDBItem */ $country_iso = $this->_getCountryByState($event); $state_name = $object->GetDBField('VariableValue'); if ( !$country_iso || !$state_name ) { return; } $cs_helper = $this->Application->recallObject('CountryStatesHelper'); /* @var $cs_helper kCountryStatesHelper */ $state_iso = $cs_helper->getStateIso($state_name, $country_iso); if ( $state_iso !== false ) { $object->SetDBField('VariableValue', $state_iso); } else { // selected state doesn't belong to selected country $object->SetError('VariableValue', 'invalid_state', 'la_InvalidState'); } } /** * Returns country iso code, that matches current state variable name * * @param kEvent $event * @return bool * @access protected */ protected function _getCountryByState(kEvent $event) { $object = $event->getObject(); /* @var $object kDBItem */ $variable_name = $object->GetDBField('VariableName'); $state_country_hash = Array ( 'Comm_State' => 'Comm_Country', 'Comm_Shipping_State' => 'Comm_Shipping_Country' ); if ( !array_key_exists($variable_name, $state_country_hash) ) { return false; } $field_values = $this->Application->GetVar($event->getPrefixSpecial(true)); $sql = 'SELECT VariableId FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . ' WHERE VariableName = ' . $this->Conn->qstr($state_country_hash[$variable_name]); $country_variable_id = $this->Conn->GetOne($sql); return $field_values[$country_variable_id]['VariableValue']; } /** * Does custom password setting processong * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemUpdate(kEvent $event) { parent::OnBeforeItemUpdate($event); $object = $event->getObject(); /* @var $object kDBItem */ // if password field is empty, then don't update if ( $object->GetDBField('ElementType') == 'password' && trim($object->GetDBField('VariableValue')) == '' ) { $object->SetFieldOption('VariableValue', 'skip_empty', 1); } } /** * Occurs after updating item * * @param kEvent $event * @return void * @access protected */ protected function OnAfterItemUpdate(kEvent $event) { static $skin_deleted = false; parent::OnAfterItemUpdate($event); $object = $event->getObject(); /* @var $object kDBItem */ if ( $object->GetDBField('ElementType') == 'password' && trim($object->GetDBField('VariableValue')) == '' ) { $object->SetFieldOption('VariableValue', 'skip_empty', 0); } // allows to check if variable's value was changed now $variable_name = $object->GetDBField('VariableName'); $changed = $this->Application->GetVar($event->getPrefixSpecial() . '_changed', Array ()); if ( $object->GetDBField('VariableValue') != $object->GetOriginalField('VariableValue') ) { $changed[] = $variable_name; $this->Application->SetVar($event->getPrefixSpecial() . '_changed', $changed); // update value in cache, so other code (during this script run) would use new value $this->Application->SetConfigValue($variable_name, $object->GetDBField('VariableValue'), true); } if ( $variable_name == 'Require_AdminSSL' || $variable_name == 'AdminSSL_URL' ) { // when administrative console is moved to SSL mode, then delete skin if ( in_array($variable_name, $changed) && !$skin_deleted ) { $skin_helper = $this->Application->recallObject('SkinHelper'); /* @var $skin_helper SkinHelper */ $skin_file = $skin_helper->getSkinPath(); if ( file_exists($skin_file) ) { unlink($skin_file); } $skin_deleted = true; } } - - $this->Application->StoreVar('config_was_updated', 1); } /** * Updates kDBItem * * @param kEvent $event * @return void * @access protected */ protected function OnUpdate(kEvent $event) { if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) { $event->status = kEvent::erFAIL; return; } $items_info = $this->Application->GetVar($event->getPrefixSpecial(true)); // 1. save user selected module root category $new_category_id = getArrayValue($items_info, 'ModuleRootCategory', 'VariableValue'); if ( $new_category_id !== false ) { unset($items_info['ModuleRootCategory']); } $object = $event->getObject( Array('skip_autoload' => true) ); /* @var $object kDBItem */ if ( $items_info ) { $has_error = false; foreach ($items_info as $id => $field_values) { $object->Clear(); // clear validation errors from previous variable $object->Load($id); $object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values)); if ( !$object->Update($id) ) { // don't stop when error found ! $has_error = true; } } $event->status = $has_error ? kEvent::erFAIL : kEvent::erSUCCESS; } if ( $event->status == kEvent::erSUCCESS ) { + $event->SetRedirectParam('action_completed', 1); + if ( $new_category_id !== false ) { // root category was submitted $module = $this->Application->GetVar('module'); $root_category_id = $this->Application->findModule('Name', $module, 'RootCat'); if ( $root_category_id != $new_category_id ) { // root category differs from one in db $fields_hash = Array ('RootCat' => $new_category_id); $this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'Modules', 'Name = ' . $this->Conn->qstr($module)); } } // reset cache $changed = $this->Application->GetVar($event->getPrefixSpecial() . '_changed', Array ()); $require_refresh = Array ('AdvancedUserManagement', 'Site_Name', 'AdminConsoleInterface', 'UsePopups'); $refresh_sections = array_intersect($require_refresh, $changed); $require_full_refresh = Array ('Site_Name', 'AdminConsoleInterface'); if ( array_intersect($require_full_refresh, $changed) ) { $event->SetRedirectParam('refresh_all', 1); } elseif ( $refresh_sections ) { $event->SetRedirectParam('refresh_tree', 1); } if ( $refresh_sections ) { // reset sections too, because of AdvancedUserManagement $this->Application->DeleteSectionCache(); } $this->Application->DeleteUnitCache($changed); } - elseif ( $this->Application->GetVar('errors_' . $event->getPrefixSpecial()) ) { - // because we have list out there, and this is item - $this->Application->removeObject($event->getPrefixSpecial()); + else{ + $errors = $this->Application->GetVar('errors_' . $event->getPrefixSpecial()); + + if ( $errors ) { + // because we have list out there, and this is item + $this->Application->SetVar('first_error', key($errors)); + $this->Application->removeObject($event->getPrefixSpecial()); + } } // keeps module and section in REQUEST to ensure, that last admin template will work $event->SetRedirectParam('module', $this->Application->GetVar('module')); $event->SetRedirectParam('section', $this->Application->GetVar('section')); } /** * Process items from selector (selected_ids var, key - prefix, value - comma separated ids) * * @param kEvent $event */ function OnProcessSelected($event) { $selected_ids = $this->Application->GetVar('selected_ids'); $this->Application->StoreVar('ModuleRootCategory', $selected_ids['c']); $event->SetRedirectParam('opener', 'u'); } /** * Generates maintenance page * * @param kEvent $event * @return void * @access protected */ protected function OnGenerateMaintenancePage(kEvent $event) { $event->setEventParam('compile_maintenance_template', 1); $event->CallSubEvent('OnUpdate'); } /** * Generates HTML version of hard maintenance template * * @param string $template * @return bool * @access protected */ protected function _generateMaintenancePage($template = null) { if ( !isset($template) ) { $template = $this->Application->ConfigValue('HardMaintenanceTemplate'); } $curl_helper = $this->Application->recallObject('CurlHelper'); /* @var $curl_helper kCurlHelper */ $html = $curl_helper->Send($this->Application->BaseURL() . '?t=' . $template); if ( $curl_helper->isGoodResponseCode() ) { file_put_contents(WRITEABLE . DIRECTORY_SEPARATOR . 'maintenance.html', $html); return true; } return false; } /** * Returns auto-complete values for ajax-dropdown * * @param kEvent $event * @return void * @access protected */ protected function OnSuggestValues(kEvent $event) { if ( !$this->Application->isAdminUser ) { // very careful here, because this event allows to // view every object field -> limit only to logged-in admins return; } $event->status = kEvent::erSTOP; $field = $this->Application->GetVar('field'); $cur_value = $this->Application->GetVar('cur_value'); $object = $event->getObject(); /* @var $object kDBItem */ if ( !$field || !$cur_value || !$object->isField($field) ) { return; } $limit = $this->Application->GetVar('limit'); if ( !$limit ) { $limit = 20; } $sql = 'SELECT DISTINCT ' . $field . ', ModuleOwner FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . ' WHERE ' . $field . ' LIKE ' . $this->Conn->qstr('%' . $cur_value . '%') . ' ORDER BY ' . $field . ' ASC'; $raw_suggestions = $this->Conn->Query($sql); $suggestions = Array (); $this->Application->XMLHeader(); foreach ($raw_suggestions as $raw_suggestion) { $suggestion = $raw_suggestion[$field]; if ( !isset($suggestions[$suggestion]) ) { $suggestions[$suggestion] = Array (); } $suggestions[$suggestion][] = $raw_suggestion['ModuleOwner']; } array_splice($suggestions, $limit); echo '<suggestions>'; $of_label = $this->Application->Phrase('la_From', false); foreach ($suggestions as $suggestion_value => $suggestion_modules) { $suggestion_module = in_array('In-Portal', $suggestion_modules) ? 'In-Portal' : implode(', ', $suggestion_modules); $suggestion_title = $suggestion_value . ' <em style="color: grey;">' . $of_label . ' ' . $suggestion_module . '</em>'; echo '<item value="' . htmlspecialchars($suggestion_value) . '">' . htmlspecialchars($suggestion_title) . '</item>'; } echo '</suggestions>'; } /** * Prefills module dropdown * * @param kEvent $event * @return void * @access protected */ protected function OnAfterConfigRead(kEvent $event) { parent::OnAfterConfigRead($event); $options = Array (); foreach ($this->Application->ModuleInfo as $module_name => $module_info) { if ( $module_name == 'Core' ) { continue; } $options[$module_name] = $module_name; if ( $module_name == 'In-Portal' ) { $options['In-Portal:Users'] = 'In-Portal:Users'; } } $fields = $this->Application->getUnitOption($event->Prefix, 'Fields'); $fields['ModuleOwner']['options'] = $options; $this->Application->setUnitOption($event->Prefix, 'Fields', $fields); } } \ No newline at end of file Index: branches/5.2.x/core/admin_templates/incs/config_blocks.tpl =================================================================== --- branches/5.2.x/core/admin_templates/incs/config_blocks.tpl (revision 15524) +++ branches/5.2.x/core/admin_templates/incs/config_blocks.tpl (revision 15525) @@ -1,132 +1,131 @@ <inp2:m_DefineElement name="config_edit_text"> <input type="text" tabindex="<inp2:m_get param='tab_index'/>" name="<inp2:InputName field='$field'/>" id="<inp2:InputName field='$field'/>" value="<inp2:Field field='$field' />"<inp2:m_if check="m_Param" name="field_params"> <inp2:m_Param name="field_params"/><inp2:m_else/> style="width:100%"</inp2:m_if>/> </inp2:m_DefineElement> <inp2:m_DefineElement name="config_edit_password"> <input type="password" autocomplete="off" tabindex="<inp2:m_get param='tab_index'/>" primarytype="password" name="<inp2:InputName field='$field'/>" id="<inp2:InputName field='$field'/>" value="" /> <inp2:m_Inc param="tab_index" by="1"/> <input type="password" autocomplete="off" tabindex="<inp2:m_get param='tab_index'/>" name="verify_<inp2:InputName field='$field'/>" id="verify_<inp2:InputName field='$field'/>" value="" /> <span class="error" id="error_<inp2:InputName field="$field"/>"></span> <script type="text/javascript"> $(document).ready( function() { // fixes Firefox 2.0+ bug will password autocomplete document.getElementById('<inp2:InputName field="$field"/>').value = ''; document.getElementById('verify_<inp2:InputName field="$field"/>').value = ''; } ); </script> </inp2:m_DefineElement> <inp2:m_DefineElement name="config_edit_option"> <option value="<inp2:m_param name='key'/>"<inp2:m_param name="selected"/>><inp2:m_param name="option"/></option> </inp2:m_DefineElement> <inp2:m_DefineElement name="config_edit_select"> <select name="<inp2:InputName field='$field'/>" id="<inp2:InputName field='$field'/>" tabindex="<inp2:m_get param='tab_index'/>"> <inp2:PredefinedOptions field="$field" block="config_edit_option" selected="selected"/> </select> </inp2:m_DefineElement> <inp2:m_DefineElement name="config_edit_multiselect"> <select id="<inp2:InputName field='$field'/>_select" onchange="update_multiple_options('<inp2:InputName field='$field'/>');" tabindex="<inp2:m_get param='tab_index'/>" multiple> <inp2:PredefinedOptions field="$field" block="config_edit_option" selected="selected"/> </select> <input type="hidden" id="<inp2:InputName field='$field'/>" name="<inp2:InputName field='$field'/>" value="<inp2:Field field='$field'/>"/> </inp2:m_DefineElement> <inp2:m_DefineElement name="config_edit_checkbox" field_class=""> <input type="hidden" id="<inp2:InputName field='$field'/>" name="<inp2:InputName field='$field'/>" value="<inp2:Field field='$field' db='db'/>"> <input tabindex="<inp2:m_get param='tab_index'/>" type="checkbox" id="_cb_<inp2:InputName field='$field'/>" name="_cb_<inp2:InputName field='$field'/>" <inp2:Field field="$field" checked="checked" db="db"/> class="<inp2:m_param name="field_class"/>" onclick="update_checkbox(this, document.getElementById('<inp2:InputName field="$field"/>'))"> </inp2:m_DefineElement> <inp2:m_DefineElement name="config_edit_textarea"> <textarea tabindex="<inp2:m_get param='tab_index'/>" name="<inp2:InputName field='$field'/>" id="<inp2:InputName field='$field'/>" <inp2:m_param name="field_params" />><inp2:Field field="$field" /></textarea> </inp2:m_DefineElement> <inp2:m_DefineElement name="config_radio_item"> <input type="radio" <inp2:m_param name="checked"/> name="<inp2:InputName field="$field"/>" id="<inp2:InputName field="$field"/>_<inp2:m_param name="key"/>" value="<inp2:m_param name="key"/>"><label for="<inp2:InputName field="$field"/>_<inp2:m_param name="key"/>"><inp2:m_param name="option"/></label> </inp2:m_DefineElement> <inp2:m_DefineElement name="config_edit_radio"> <inp2:PredefinedOptions field="$field" block="config_radio_item" selected="checked"/> </inp2:m_DefineElement> <inp2:m_DefineElement name="cf_default_value"> <inp2:ConfigFormElement PrefixSpecial="$PrefixSpecial" field="VariableValue" blocks_prefix="config_edit_" element_type_field="ElementType" value_list_field="ValueList"/> </inp2:m_DefineElement> <inp2:m_DefineElement name="cf_default_caption"> <td style="width: 500px;"> <inp2:Field name="VariableName" result_to_var="error_field"/> <span class="<inp2:m_if check='HasError' field='$error_field' id_field='VariableName'>error-cell</inp2:m_if>"> <inp2:Field field="Prompt" as_label="1" /></span><inp2:m_if check="IsRequired" field="VariableValue"><span class="field-required"> *</span></inp2:m_if>:<inp2:m_if check="Field" name="HintLabel"><span> <img src="<inp2:m_TemplatesBase/>/img/hint_icon.png" width="12" height="13" title="<inp2:Field name='HintLabel' as_label='1' html_escape='1'/>" alt="<inp2:Field name='HintLabel' as_label='1' html_escape='1'/>"/></inp2:m_if> <inp2:m_if check="m_IsDebugMode"> <br/><small style="color: gray;">[<inp2:Field field="DisplayOrder"/>] <inp2:Field field="VariableName"/> [<a href="<inp2:ItemEditLink template='config/config_edit'/>" onclick="return direct_edit('<inp2:m_param name="PrefixSpecial"/>', this.href);"><inp2:m_Phrase name="la_btn_Edit"/></a>]</small> </inp2:m_if> </td> </inp2:m_DefineElement> <inp2:m_DefineElement name="config_block"> <inp2:m_inc param="tab_index" by="1"/> <inp2:m_if check="m_ParamEquals" name="show_heading" value="1"> <tr class="subsectiontitle"> <td colspan="2"> <inp2:Field name="Heading" as_label="1"/> </td> <td align="right"> <a class="config-header" href="javascript:toggle_section('<inp2:Field name="Heading"/>');" id="toggle_mark[<inp2:Field name="Heading"/>]" title="Collapse/Expand Section">[-]</a> </td> </tr> </inp2:m_if> <tr class="<inp2:m_odd_even odd='table-color1' even='table-color2'/>" id="<inp2:m_param name="PrefixSpecial"/>_<inp2:field field="$IdField"/>" header_label="<inp2:Field name="Heading"/>"> <inp2:m_RenderElement name="cf_default_caption" pass_params="1"/> <td> <inp2:m_RenderElement name="$value_render_as" pass_params="1"/> </td> - <td class="error"><inp2:Error id_field="VariableName"/> </td> + <td class="field-<inp2:Field name='VariableName'/> error"><inp2:Error id_field="VariableName"/> </td> </tr> </inp2:m_DefineElement> <inp2:m_DefineElement name="config_block1"> <inp2:m_inc param="tab_index" by="1"/> <inp2:m_if check="m_ParamEquals" name="show_heading" value="1"> <tr class="subsectiontitle"> <td colspan="2"> <inp2:Field name="Heading" as_label="1"/> </td> <td align="right"> <a class="config-header" href="javascript:toggle_section('<inp2:Field name="Heading"/>');" id="toggle_mark[<inp2:Field name="Heading"/>]" title="Collapse/Expand Section">[-]</a> </td> </tr> </inp2:m_if> <tr class="<inp2:m_odd_even odd='table-color1' even='table-color2'/>" id="<inp2:m_param name="PrefixSpecial"/>_<inp2:Field field="$IdField"/>" header_label="<inp2:Field name="Heading"/>"> <inp2:m_RenderElement name="cf_default_caption" pass_params="1"/> <td> <nobr><inp2:m_RenderElement name="$value_render_as" pass_params="1"/> </inp2:m_DefineElement> <inp2:m_DefineElement name="config_block2"> <inp2:m_RenderElement name="$value_render_as" pass_params="1"/></nobr> </td> - <td class="error"><inp2:Error id_field="VariableName"/> </td> + <td class="field-<inp2:Field name='VariableName'/> error"><inp2:Error id_field="VariableName"/> </td> </tr> </inp2:m_DefineElement> <inp2:m_ModuleInclude template="config/custom_variables"/> <inp2:m_DefineElement name="config_updated_notice"> - <inp2:m_if check="m_Recall" var="config_was_updated"> + <inp2:m_if check="m_Get" var="action_completed"> <inp2:m_RenderElement design="form_message" type="notice"> <inp2:m_Phrase name="la_msg_YourChangesWereSuccessfullySaved"/><br/> </inp2:m_RenderElement> - <inp2:m_RemoveVar name="config_was_updated" /> </inp2:m_if> </inp2:m_DefineElement> Index: branches/5.2.x/core/admin_templates/config/config_general.tpl =================================================================== --- branches/5.2.x/core/admin_templates/config/config_general.tpl (revision 15524) +++ branches/5.2.x/core/admin_templates/config/config_general.tpl (revision 15525) @@ -1,170 +1,180 @@ <inp2:m_include t="incs/header"/> <inp2:m_Get name="section" result_to_var="section"/> <inp2:m_RenderElement name="combined_header" prefix="conf" section="$section" perm_event="conf:OnLoad" title_preset="config_list_general"/> <!-- ToolBar --> <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td> <script type="text/javascript"> function validate_password_fields() { var $validated = true; $("input[primarytype='password']", '#' + $form_name).each( function ($e) { if ( !validate_password_field(this.id) ) { $validated = false; } } ); return $validated; } function validate_password_field($field_id) { var password_field = document.getElementById($field_id), password_verify_field = document.getElementById('verify_' + $field_id); if ( password_field && password_verify_field && password_field.value == password_verify_field.value ) { return true; } else { var password_error_cell = document.getElementById('error_' + $field_id); if ( password_error_cell ) { $(window).scrollTop($(password_field).position().top - 15); password_error_cell.innerHTML = '<inp2:m_Phrase name="la_error_PasswordMatch"/>'; } return false; } } function toggle_section($label) { var $table = document.getElementById('config_table'); var $row = null; var $is_visible = false; for (var $i = 0; $i < $table.rows.length; $i++) { $row = $table.rows[$i]; if ( $row.getAttribute('header_label') != $label ) { continue; } if ( !$row.style.display ) { $row.style.display = document.all ? 'block' : 'table-row'; } $is_visible = !($row.style.display == 'none'); $row.style.display = $is_visible ? 'none' : (document.all ? 'block' : 'table-row'); document.getElementById('toggle_mark[' + $label + ']').innerHTML = '[' + ($is_visible ? '+' : '-') + ']'; } } var a_toolbar = new ToolBar(); a_toolbar.AddButton( new ToolBarButton( 'select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() { submit_event('conf','<inp2:conf_SaveEvent/>'); } ) ); a_toolbar.AddButton( new ToolBarButton( 'cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() { submit_event('conf','OnCancel'); } ) ); <inp2:m_if check="m_IsDebugMode"> a_toolbar.AddButton( new ToolBarSeparator('sep1') ); a_toolbar.AddButton( new ToolBarButton( 'new_item', '<inp2:m_phrase label="la_ToolTip_NewSystemSetting" escape="1"/>::<inp2:m_phrase label="la_ToolTip_Add" escape="1"/>', function() { std_precreate_item('conf', 'config/config_edit'); } ) ); </inp2:m_if> <inp2:m_ModuleInclude template = "config/custom_toolbar"/> a_toolbar.Render(); </script> </td> </tr> </tbody> </table> <inp2:m_include t="incs/config_blocks"/> <inp2:m_RenderElement name="config_updated_notice"/> <inp2:conf_SaveWarning name="grid_save_warning"/> <table width="100%" border="0" cellspacing="0" cellpadding="4" class="bordered" id="config_table"> <!-- module root category selector: begin --> <tr class="subsectiontitle"> <td colspan="2"> <inp2:m_phrase name="la_Text_RootCategory" /> </td> <td align="right"> <a class="config-header" href="javascript:toggle_section('la_Text_RootCategory');" id="toggle_mark[la_Text_RootCategory]" title="Collapse/Expand Section">[-]</a> </td> </tr> <tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>" header_label="la_Text_RootCategory"> <td> <span class="text"><inp2:m_phrase name="la_prompt_RootCategory" /></span> </td> <td> <inp2:m_DefineElement name="category_caption"> <inp2:m_ifnot check="m_Param" name="is_first"> <inp2:m_param name="separator"/> </inp2:m_ifnot> <inp2:m_param name="cat_name"/> </inp2:m_DefineElement> <b><inp2:conf_CategoryPath separator=" > " render_as="category_caption" /></b> <input type="hidden" name="conf[ModuleRootCategory][VariableValue]" value="<inp2:conf_ModuleRootCategory/>"/> <a href="<inp2:adm_SelectorLink prefix='conf' selection_mode='single' tab_prefixes='none'/>" onclick="openSelector('conf', this.href, 'ModuleRootCategory', '950x600'); return false;"><img src="img/icons/icon24_cat.gif" border="0" align="absmiddle" /></a> </td> <td class="error"> </td> </tr> <!-- module root category selector: end --> <inp2:conf_PrintList block="config_block" per_page="-1" full_block="config_block" half_block1="config_block1" half_block2="config_block2" value_render_as="cf_default_value"/> </table> <script type="text/javascript"> <inp2:m_if check="m_Get" name="refresh_tree"> getFrame('menu').location.reload(); </inp2:m_if> <inp2:m_if check="m_Get" name="refresh_all"> var $menu_frame = getFrame('menu'); $menu_frame.parent.location.href = $menu_frame.parent.location.href; </inp2:m_if> Application.setHook( 'conf:*', function ($event) { $event.status = $event.Name == 'OnCancel' ? true : validate_password_fields(); } ); + + <inp2:m_if check="m_Get" name="first_error"> + $(document).ready(function () { + var $error_cell = $('.field-<inp2:m_Get name="first_error"/>.error'); + + if ( $error_cell.length ) { + $(window).scrollTop($error_cell.position().top - 15); + } + }); + </inp2:m_if> </script> <inp2:m_include t="incs/footer"/> \ No newline at end of file Index: branches/5.2.x/core/admin_templates/config/config_universal.tpl =================================================================== --- branches/5.2.x/core/admin_templates/config/config_universal.tpl (revision 15524) +++ branches/5.2.x/core/admin_templates/config/config_universal.tpl (revision 15525) @@ -1,141 +1,151 @@ <inp2:m_include t="incs/header"/> <inp2:conf_InitList name="Default" per_page="-1"/> <inp2:m_Get name="section" result_to_var="section"/> <inp2:m_RenderElement name="combined_header" prefix="conf" section="$section" title_preset="section_label" perm_event="conf:OnLoad"/> <!-- ToolBar --> <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td> <script type="text/javascript"> function validate_password_fields() { var $validated = true; $("input[primarytype='password']", '#' + $form_name).each( function ($e) { if ( !validate_password_field(this.id) ) { $validated = false; } } ); return $validated; } function validate_password_field($field_id) { var password_field = document.getElementById($field_id), password_verify_field = document.getElementById('verify_' + $field_id); if ( password_field && password_verify_field && password_field.value == password_verify_field.value ) { return true; } else { var password_error_cell = document.getElementById('error_' + $field_id); if ( password_error_cell ) { $(window).scrollTop($(password_field).position().top - 15); password_error_cell.innerHTML = '<inp2:m_Phrase name="la_error_PasswordMatch"/>'; } return false; } } function toggle_section($label) { var $row = null, $is_visible = false, $table = document.getElementById('config_table'); for (var $i = 0; $i < $table.rows.length; $i++) { $row = $table.rows[$i]; if ( $row.getAttribute('header_label') != $label ) { continue; } if ( !$row.style.display ) { $row.style.display = document.all ? 'block' : 'table-row'; } $is_visible = !($row.style.display == 'none'); $row.style.display = $is_visible ? 'none' : (document.all ? 'block' : 'table-row'); document.getElementById('toggle_mark[' + $label + ']').innerHTML = '[' + ($is_visible ? '+' : '-') + ']'; } } var a_toolbar = new ToolBar(); a_toolbar.AddButton( new ToolBarButton( 'select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function () { submit_event('conf', '<inp2:conf_SaveEvent/>'); } ) ); a_toolbar.AddButton( new ToolBarButton( 'cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function () { submit_event('conf', 'OnCancel'); } ) ); <inp2:m_if check="m_IsDebugMode"> a_toolbar.AddButton( new ToolBarSeparator('sep1') ); a_toolbar.AddButton( new ToolBarButton( 'new_item', '<inp2:m_phrase label="la_ToolTip_NewSystemSetting" escape="1"/>::<inp2:m_phrase label="la_ToolTip_Add" escape="1"/>', function() { std_precreate_item('conf', 'config/config_edit'); } ) ); </inp2:m_if> <inp2:m_ModuleInclude template = "config/custom_toolbar"/> a_toolbar.Render(); </script> </td> </tr> </tbody> </table> <inp2:m_include t="incs/config_blocks"/> <inp2:m_RenderElement name="config_updated_notice"/> <inp2:conf_SaveWarning name="grid_save_warning"/> <table width="100%" border="0" cellspacing="0" cellpadding="4" class="bordered" id="config_table"> <inp2:conf_PrintList list_name="default" block="config_block" full_block="config_block" half_block1="config_block1" half_block2="config_block2" value_render_as="cf_default_value"/> </table> <script type="text/javascript"> <inp2:m_if check="m_Get" name="refresh_tree"> getFrame('menu').location.reload(); </inp2:m_if> <inp2:m_if check="m_Get" name="refresh_all"> var $menu_frame = getFrame('menu'); $menu_frame.parent.location.href = $menu_frame.parent.location.href; </inp2:m_if> Application.setHook( 'conf:*', function ($event) { $event.status = $event.Name == 'OnCancel' ? true : validate_password_fields(); } ); + + <inp2:m_if check="m_Get" name="first_error"> + $(document).ready(function () { + var $error_cell = $('.field-<inp2:m_Get name="first_error"/>.error'); + + if ( $error_cell.length ) { + $(window).scrollTop($error_cell.position().top - 15); + } + }); + </inp2:m_if> </script> <inp2:m_include t="incs/footer"/> \ No newline at end of file