User-options now working again.
authorAlexander Ebert <ebert@woltlab.com>
Thu, 17 Nov 2011 19:54:38 +0000 (20:54 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Thu, 17 Nov 2011 19:54:38 +0000 (20:54 +0100)
wcfsetup/install/files/acp/templates/userAdd.tpl
wcfsetup/install/files/lib/acp/form/AbstractOptionListForm.class.php
wcfsetup/install/files/lib/acp/form/UserAddForm.class.php
wcfsetup/install/files/lib/acp/form/UserEditForm.class.php
wcfsetup/install/files/lib/acp/form/UserOptionListForm.class.php
wcfsetup/install/files/lib/acp/page/UserListPage.class.php
wcfsetup/install/files/lib/data/user/UserAction.class.php
wcfsetup/install/files/lib/data/user/option/UserOption.class.php
wcfsetup/install/files/lib/system/option/IOptionHandler.class.php
wcfsetup/install/files/lib/system/option/OptionHandler.class.php
wcfsetup/install/files/lib/system/option/user/UserOptionHandler.class.php [new file with mode: 0644]

index 0b80f93a3418f62100dd11ff7154e7239e5dab63..7660d4c22b8596134241bd78e349c06d1c349a9b 100644 (file)
@@ -1,52 +1,10 @@
 {include file='header'}
 
-<script type="text/javascript" src="{@RELATIVE_WCF_DIR}js/TabMenu.class.js"></script>
-{if $userID|isset}
-       <script type="text/javascript" src="{@RELATIVE_WCF_DIR}js/AjaxRequest.class.js"></script>
-       <script type="text/javascript" src="{@RELATIVE_WCF_DIR}js/InlineListEdit.class.js"></script>
-       <script type="text/javascript" src="{@RELATIVE_WCF_DIR}acp/js/UserListEdit.class.js"></script>
-{/if}
 <script type="text/javascript">
        //<![CDATA[
-       var tabMenu = new TabMenu();
-       {if $optionTree|count}onloadEvents.push(function() { tabMenu.showSubTabMenu('{@$options[0][object]->categoryName}') });{/if}
-       
-       {if $userID|isset}
-               var userData = new Hash();
-               userData.set({@$userID}, {
-                       'isMarked': {@$user->isMarked()}
-               });
-               
-               var url = '{@$url|encodeJS}';
-               
-               // language
-               var language = new Object();
-               language['wcf.global.button.mark']              = '{lang}wcf.global.button.mark{/lang}';
-               language['wcf.global.button.unmark']            = '{lang}wcf.global.button.unmark{/lang}';
-               language['wcf.global.button.delete']            = '{lang}wcf.global.button.delete{/lang}';
-               language['wcf.acp.user.button.sendMail']        = '{lang}wcf.acp.user.button.sendMail{/lang}';
-               language['wcf.acp.user.button.exportMail']      = '{lang}wcf.acp.user.button.exportMail{/lang}';
-               language['wcf.acp.user.button.assignGroup']     = '{lang}wcf.acp.user.button.assignGroup{/lang}';
-               language['wcf.acp.user.deleteMarked.sure']      = '{lang}wcf.acp.user.deleteMarked.sure{/lang}';
-               language['wcf.acp.user.delete.sure']            = '{lang}wcf.acp.user.delete.sure{/lang}';
-               language['wcf.acp.user.markedUsers']            = '{lang}wcf.acp.user.markedUsers{/lang}';
-               
-               // additional options
-               var additionalOptions = new Array();
-               var additionalUserOptions = new Array();
-               {if $additionalUserOptions|isset}{@$additionalUserOptions}{/if}
-               {if $additionalMarkedOptions|isset}{@$additionalMarkedOptions}{/if}
-               
-               // permissions
-               var permissions = new Object();
-               permissions['canEditUser'] = {if $__wcf->session->getPermission('admin.user.canEditUser')}1{else}0{/if};
-               permissions['canDeleteUser'] = {if $__wcf->session->getPermission('admin.user.canDeleteUser')}1{else}0{/if};
-               permissions['canMailUser'] = {if $__wcf->session->getPermission('admin.user.canMailUser')}1{else}0{/if};
-               permissions['canEditMailAddress'] = {if $__wcf->session->getPermission('admin.user.canEditMailAddress')}1{else}0{/if};
-               permissions['canEditPassword'] = {if $__wcf->session->getPermission('admin.user.canEditPassword')}1{else}0{/if};
-               
-               onloadEvents.push(function() { userListEdit = new UserListEdit(userData, {@$markedUsers}, additionalUserOptions, additionalOptions); });
-       {/if}
+       $(function() {
+               WCF.TabMenu.init();
+       });
        //]]>
 </script>
 
                {if $additionalFields|isset}{@$additionalFields}{/if}
                
                {if $optionTree|count || $additionalTabs|isset}
-                       <nav>
-                               <div class="tabMenu">
+                       <div class="tabMenuContainer">
+                               <nav class="tabMenu">
                                        <ul>
                                                {foreach from=$optionTree item=categoryLevel1}
-                                                       <li id="{@$categoryLevel1[object]->categoryName}"><a onclick="tabMenu.showSubTabMenu('{@$categoryLevel1[object]->categoryName}');"><span>{lang}wcf.user.option.category.{@$categoryLevel1[object]->categoryName}{/lang}</span></a></li>
+                                                       <li><a href="#{@$categoryLevel1[object]->categoryName}">{lang}wcf.user.option.category.{@$categoryLevel1[object]->categoryName}{/lang}</a></li>
                                                {/foreach}
                                                
-                                               {if $additionalTabs|isset}{@$additionalTabs}{/if}
+                                               {event name='tabMenuTabs'}
                                        </ul>
-                               </div>
-                       <nav>
-                       <div class="menu">
-                               <div class="containerHead"><div> </div></div>
-                       </div>
+                               </nav>
                        
-                       {foreach from=$optionTree item=categoryLevel1}
-                               <div id="{@$categoryLevel1[object]->categoryName}-content" class="border tabMenuContent hidden">
-                                       <hgroup class="subHeading">
-                                               <h1>{lang}wcf.user.option.category.{@$categoryLevel1[object]->categoryName}{/lang}</h1>
-                                       </hgroup>
+                               {foreach from=$optionTree item=categoryLevel1}
+                                       <div id="{@$categoryLevel1[object]->categoryName}" class="border tabMenuContent">
+                                               <hgroup class="subHeading">
+                                                       <h1>{lang}wcf.user.option.category.{@$categoryLevel1[object]->categoryName}{/lang}</h1>
+                                               </hgroup>
                                        
-                                       {foreach from=$categoryLevel1[categories] item=categoryLevel2}
-                                               <fieldset>
-                                                       <legend>{lang}wcf.user.option.category.{@$categoryLevel2[object]->categoryName}{/lang}</legend>
+                                               {foreach from=$categoryLevel1[categories] item=categoryLevel2}
+                                                       <fieldset>
+                                                               <legend>{lang}wcf.user.option.category.{@$categoryLevel2[object]->categoryName}{/lang}</legend>
                                                        
-                                                       {if $categoryLevel2[object]->categoryName == 'settings.general' && $availableLanguages|count > 1}
-                                                               <dl>
-                                                                       <dt><label for="languageID">{lang}wcf.user.language{/lang}</label></dt>
-                                                                       <dd>
-                                                                               {htmlOptions options=$availableLanguages selected=$languageID name=languageID id=languageID disableEncoding=true}
-                                                                       </dd>
-                                                               </dl>
-                                                                       
-                                                               {if $availableContentLanguages|count > 1}
+                                                               {if $categoryLevel2[object]->categoryName == 'settings.general' && $availableLanguages|count > 1}
                                                                        <dl>
-                                                                               <dt>
-                                                                                       {lang}wcf.user.visibleLanguages{/lang}
-                                                                               </dt>
+                                                                               <dt><label for="languageID">{lang}wcf.user.language{/lang}</label></dt>
                                                                                <dd>
-                                                                                       <fieldset>
-                                                                                               <legend>{lang}wcf.user.visibleLanguages{/lang}</legend>
-                                                                                               <dl>
-                                                                                                       <dd>
-                                                                                                               {foreach from=$availableContentLanguages key=availableLanguageID item=availableLanguage}
-                                                                                                                       <label><input type="checkbox" name="visibleLanguages[]" value="{@$availableLanguageID}"{if $availableLanguageID|in_array:$visibleLanguages} checked="checked"{/if} /> {@$availableLanguage}</label>
-                                                                                                               {/foreach}
-                                                                                                       </dd>
-                                                                                               </dl>
-                                                                                       </fieldset>
+                                                                                       {htmlOptions options=$availableLanguages selected=$languageID name=languageID id=languageID disableEncoding=true}
                                                                                </dd>
                                                                        </dl>
+                                                                       
+                                                                       {if $availableContentLanguages|count > 1}
+                                                                               <dl>
+                                                                                       <dt>
+                                                                                               {lang}wcf.user.visibleLanguages{/lang}
+                                                                                       </dt>
+                                                                                       <dd>
+                                                                                               <fieldset>
+                                                                                                       <legend>{lang}wcf.user.visibleLanguages{/lang}</legend>
+                                                                                                       <dl>
+                                                                                                               <dd>
+                                                                                                                       {foreach from=$availableContentLanguages key=availableLanguageID item=availableLanguage}
+                                                                                                                               <label><input type="checkbox" name="visibleLanguages[]" value="{@$availableLanguageID}"{if $availableLanguageID|in_array:$visibleLanguages} checked="checked"{/if} /> {@$availableLanguage}</label>
+                                                                                                                       {/foreach}
+                                                                                                               </dd>
+                                                                                                       </dl>
+                                                                                               </fieldset>
+                                                                                       </dd>
+                                                                               </dl>
+                                                                       {/if}
                                                                {/if}
-                                                       {/if}
                                                        
-                                                       {include file='optionFieldList' options=$categoryLevel2[options] langPrefix='wcf.user.option.'}
-                                               </fieldset>
-                                       {/foreach}
-                               </div>
-                       {/foreach}
+                                                               {include file='optionFieldList' options=$categoryLevel2[options] langPrefix='wcf.user.option.'}
+                                                       </fieldset>
+                                               {/foreach}
+                                       </div>
+                               {/foreach}
+
+                               {event name='tabMenuContent'}
+                       </div>
                {/if}
-               
-               {if $additionalTabContents|isset}{@$additionalTabContents}{/if}
        </div>
        
        <div class="formSubmit">
index 84fed98c797214413b12d45e4081eccc63b48bb7..c15b5eafa6c1d8d5c6bc20ee97b0fb4e71f466ee 100755 (executable)
@@ -61,13 +61,19 @@ abstract class AbstractOptionListForm extends AbstractForm {
         */
        public $optionHandlerClassName = 'wcf\system\option\OptionHandler';
        
+       /**
+        * true if option supports i18n
+        * @var boolean
+        */
+       public $supportI18n = true;
+       
        /**
         * @see wcf\page\Page::readParameters()
         */
        public function readParameters() {
                parent::readParameters();
                
-               $this->optionHandler = new $this->optionHandlerClassName($this->cacheName, $this->cacheClass, $this->languageItemPattern, $this->categoryName);
+               $this->optionHandler = new $this->optionHandlerClassName($this->cacheName, $this->cacheClass, $this->supportI18n, $this->languageItemPattern, $this->categoryName);
        }
        
        /**
index 758199587b25fd90ae7d915646de510acb0a7216..f2a880c52de7ec1ab6ec5bcf39ac91081e11f4e6 100644 (file)
@@ -184,10 +184,7 @@ class UserAddForm extends UserOptionListForm {
                AbstractForm::save();
                
                // create
-               $saveOptions = array();
-               foreach ($this->options as $option) {
-                       $saveOptions[$option->optionID] = $this->optionValues[$option->optionName];
-               }
+               $saveOptions = $this->optionHandler->save();
                $this->additionalFields['languageID'] = $this->languageID;
                $data = array(
                        'data' => array_merge($this->additionalFields, array(
@@ -286,7 +283,14 @@ class UserAddForm extends UserOptionListForm {
        public function readData() {
                parent::readData();
                
-               $this->optionTree = $this->getOptionTree();
+               $this->readOptionTree();
+       }
+       
+       /**
+        * Reads option tree on page init.
+        */
+       protected function readOptionTree() {
+               $this->optionTree = $this->optionHandler->getOptionTree();
        }
        
        /**
@@ -322,9 +326,6 @@ class UserAddForm extends UserOptionListForm {
                // get the default langauge id
                $this->languageID = $this->getDefaultFormLanguageID();
                
-               // get user options and categories from cache
-               $this->readCache();
-               
                // show form
                parent::show();
        }
@@ -332,9 +333,10 @@ class UserAddForm extends UserOptionListForm {
        /**
         * @see wcf\acp\form\AbstractOptionListForm::checkOption()
         */
+       /*
        protected static function checkOption(Option $option) {
                if (!parent::checkOption($option)) return false;
                
                return ($option->editable != 1 && $option->editable != 4 && !$option->disabled);
-       }
+       }*/
 }
index 0d086b1383e20e5b0262a660df45a662d01392f1..2efbfae6eb9ee9e9e954585099dd5248b98da5df 100755 (executable)
@@ -87,6 +87,17 @@ class UserEditForm extends UserAddForm {
                parent::readData();
        }
        
+       /**
+        * @see wcf\acp\form\UserAddForm::readOptionTree()
+        */
+       protected function readOptionTree() {
+               if (empty($_POST)) {
+                       $this->optionHandler->setUser($this->user->getDecoratedObject());
+               }
+               
+               parent::readOptionTree();
+       }
+       
        /**
         * Gets the selected languages.
         */
@@ -102,13 +113,6 @@ class UserEditForm extends UserAddForm {
                $this->email = $this->confirmEmail = $this->user->email;
                $this->groupIDs = $this->user->getGroupIDs();
                $this->languageID = $this->user->languageID;
-               
-               foreach ($this->options as $option) {
-                       $value = $this->user->{'userOption'.$option->optionID};
-                       if ($value !== null) {
-                               $this->optionValues[$option->optionName] = $value;
-                       }
-               }
        }
        
        /**
@@ -143,10 +147,7 @@ class UserEditForm extends UserAddForm {
                $this->groupIDs = array_unique($this->groupIDs);
                
                // save user
-               $saveOptions = array();
-               foreach ($this->options as $option) {
-                       $saveOptions[$option->optionID] = $this->optionValues[$option->optionName];
-               }
+               $saveOptions = $this->optionHandler->save();
                $this->additionalFields['languageID'] = $this->languageID;
                $data = array(
                        'data' => array_merge($this->additionalFields, array(
index 8685a4b3a94656133600755ae34fd25014979036..2e4a31d0dcf5258f7dd1b6143e5fe1b96e1052ec 100644 (file)
@@ -21,7 +21,17 @@ abstract class UserOptionListForm extends AbstractOptionListForm {
        /**
         * @see wcf\acp\form\AbstractOptionListForm::$cacheName
         */
-       public $cacheName = 'user-option-';
+       public $cacheName = 'user-option';
+       
+       /**
+        * @see wcf\acp\form\AbstractOptionListForm::$supportI18n
+        */
+       public $supportI18n = false;
+       
+       /**
+        * @see wcf\acp\form\AbstractOptionListForm::$optionHandlerClassName
+        */
+       public $optionHandlerClassName = 'wcf\system\option\user\UserOptionHandler';
        
        /**
         * Returns a list of all available user groups.
@@ -40,15 +50,4 @@ abstract class UserOptionListForm extends AbstractOptionListForm {
        protected function getDefaultFormLanguageID() {
                return LanguageFactory::getInstance()->getDefaultLanguageID();
        }
-       
-       /**
-        * @see wcf\acp\form\AbstractOptionListForm::validateOption()
-        */
-       protected function validateOption(Option $option) {
-               parent::validateOption($option);
-
-               if ($option->required && empty($this->optionValues[$option->optionName])) {
-                       throw new UserInputException($option->optionName);
-               }
-       }
 }
index 0e56a0914aa17b8f6179845bce702b80d10b7adb..972976cc9b1bbc5e1477da7ca0e202e15fc8b353 100755 (executable)
@@ -8,7 +8,9 @@ use wcf\system\cache\CacheHandler;
 use wcf\system\clipboard\ClipboardHandler;
 use wcf\system\database\util\PreparedStatementConditionBuilder;
 use wcf\system\event\EventHandler;
+use wcf\system\exception\SystemException;
 use wcf\system\request\LinkHandler;
+use wcf\system\user\option\UserOptions;
 use wcf\system\WCF;
 use wcf\util\DateUtil;
 use wcf\util\StringUtil;
@@ -61,7 +63,6 @@ class UserListPage extends SortablePage {
        public $users = array();
        public $url = '';
        public $columns = array('email', 'registrationDate');
-       public $outputObjects = array();
        public $options = array();
        public $columnValues = array();
        public $columnHeads = array();
@@ -217,8 +218,8 @@ class UserListPage extends SortablePage {
                        foreach ($this->users as $key => $user) {
                                foreach ($this->columns as $column) {
                                        if (isset($this->options[$column])) {
-                                               if ($this->options[$column]['outputClass']) {
-                                                       $outputObj = $this->getOutputObject($this->options[$column]['outputClass']);
+                                               if ($this->options[$column]->outputClass) {
+                                                       $outputObj = UserOptions::getInstance()->getOutputObject($this->options[$column]->outputClass);
                                                        $this->columnValues[$user->userID][$column] = $outputObj->getOutput($user, $this->options[$column], $user->{$column});
                                                }
                                                else {
@@ -295,31 +296,6 @@ class UserListPage extends SortablePage {
                }
        }
        
-       /**
-        * Returns an object of the requested option output type.
-        * 
-        * @param       string                  $type
-        * @return      UserOptionOutput
-        */
-       protected function getOutputObject($className) {
-               if (!isset($this->outputObjects[$className])) {
-                       // include class file
-                       $classPath = WCF_DIR.'lib/data/user/option/'.$className.'.class.php';
-                       if (!file_exists($classPath)) {
-                               throw new SystemException("unable to find class file '".$classPath."'");
-                       }
-                       require_once($classPath);
-                       
-                       // create instance
-                       if (!class_exists($className)) {
-                               throw new SystemException("unable to find class '".$className."'");
-                       }
-                       $this->outputObjects[$className] = new $className();
-               }
-               
-               return $this->outputObjects[$className];
-       }
-
        /**
         * @see wcf\page\MultipleLinkPage::initObjectList()
         */             
index 23708e0568d7da61069ed30566fd5f91fd1d7801..14c8454b1d0606cd60c6e0694228b94221a162a2 100644 (file)
@@ -125,15 +125,20 @@ class UserAction extends AbstractDatabaseObjectAction {
                
                $groupIDs = (isset($this->parameters['groups'])) ? $this->parameters['groups'] : array();
                $removeGroups = (isset($this->parameters['removeGroups'])) ? $this->parameters['removeGroups'] : array();
+               $userOptions = (isset($this->parameters['options'])) ? $this->parameters['options'] : array();
                
                foreach ($this->objects as $userEditor) {
-                       if (count($groupIDs)) {
+                       if (!empty($groupIDs)) {
                                $userEditor->addToGroups($groupIDs);
                        }
                        
-                       if (count($removeGroups)) {
+                       if (!empty($removeGroups)) {
                                $userEditor->removeFromGroups($removeGroups);
                        }
+                       
+                       if (!empty($userOptions)) {
+                               $userEditor->updateUserOptions($userOptions);
+                       }
                }
        }
 }
index 4802f4a36ac2563974696ef08c0f4f1d39605eff..5f1cb023b5ece25363dcc560c5cdf36bbc28c2bd 100644 (file)
@@ -34,4 +34,46 @@ class UserOption extends Option {
         * @var array
         */
        public $outputData = array();
+       
+       /**
+        * @see wcf\data\option\Option::isVisible()
+        */
+       public function isVisible() {
+               $bitmask = $this->options[$optionName]->visible;
+               // check if option is hidden
+               if ($bitmask & Option::VISIBILITY_NONE) {
+                       $visible = false;
+               }
+               // proceed if option is visible for all
+               else if ($bitmask & Option::VISIBILITY_OTHER) {
+                       $visible = true;
+               }
+               else {
+                       $isAdmin = $isOwner = $visible = false;
+                       // check admin permissions
+                       if ($bitmask & Option::VISIBILITY_ADMINISTRATOR) {
+                               if (WCF::getSession()->getPermission('admin.general.canViewPrivateUserOptions')) {
+                                       $isAdmin = true;
+                               }
+                       }
+                       
+                       // check owner state
+                       if ($bitmask & Option::VISIBILITY_OWNER) {
+                               if ($user->userID == WCF::getUser()->userID) {
+                                       $isOwner = true;
+                               }
+                       }
+                       
+                       if ($isAdmin) {
+                               $visible = true;
+                       }
+                       else if ($isOwner) {
+                               $visible = true;
+                       }
+               }
+               
+               if (!$visible || $this->disabled) return false;
+               
+               return true;
+       }
 }
index ef6bdf6086fc28be630b51f7676fdf0272290e6d..ddabfe6bb1996d6ba0a40b267f618560fe3f5d23 100644 (file)
@@ -17,10 +17,11 @@ interface IOptionHandler {
         * 
         * @param       string          $cacheName
         * @param       string          $cacheClass
+        * @param       boolean         $supportI18n
         * @param       string          $languageItemPattern
         * @param       string          $categoryName
         */
-       public function __construct($cacheName, $cacheClass, $languageItemPattern = '', $categoryName = '');
+       public function __construct($cacheName, $cacheClass, $supportI18n, $languageItemPattern = '', $categoryName = '');
        
        /**
         * Reads user input from given source array.
@@ -66,5 +67,5 @@ interface IOptionHandler {
         * @param       string          $optionPrefix
         * @return      array
         */
-       public function save($categoryName, $optionPrefix);
+       public function save($categoryName = null, $optionPrefix = null);
 }
index 170802a72e6bd3e96c9148868711f201173aec7a..652fb3beb40f3c74ac1316b2282da9999f6b22c2 100644 (file)
@@ -3,6 +3,7 @@ namespace wcf\system\option;
 use wcf\data\option\category\OptionCategory;
 use wcf\data\option\Option;
 use wcf\system\cache\CacheHandler;
+use wcf\system\exception\SystemException;
 use wcf\system\exception\UserInputException;
 use wcf\system\language\I18nHandler;
 use wcf\util\ClassUtil;
@@ -91,14 +92,21 @@ class OptionHandler implements IOptionHandler {
         */
        public $rawValues = array();
        
+       /**
+        * true, if options support i18n
+        * @var boolean
+        */
+       public $supportI18n = false;
+       
        /**
         * @see wcf\system\option\IOptionHandler::__construct()
         */
-       public function __construct($cacheName, $cacheClass, $languageItemPattern = '', $categoryName = '') {
+       public function __construct($cacheName, $cacheClass, $supportI18n, $languageItemPattern = '', $categoryName = '') {
                $this->cacheName = $cacheName;
                $this->cacheClass = $cacheClass;
                $this->categoryName = $categoryName;
                $this->languageItemPattern = $languageItemPattern;
+               $this->supportI18n = $supportI18n;
                
                // load cache on init
                $this->readCache();
@@ -110,13 +118,15 @@ class OptionHandler implements IOptionHandler {
        public function readUserInput(array &$source) {
                if (isset($source['values']) && is_array($source['values'])) $this->rawValues = $source['values'];
                
-               foreach ($this->options as $option) {
-                       if ($option->supportI18n) {
-                               I18nHandler::getInstance()->register($option->optionName);
-                               I18nHandler::getInstance()->setOptions($option->optionName, $option->packageID, $option->optionValue, $this->languageItemPattern);
+               if ($this->supportI18n) {
+                       foreach ($this->options as $option) {
+                               if ($option->supportI18n) {
+                                       I18nHandler::getInstance()->register($option->optionName);
+                                       I18nHandler::getInstance()->setOptions($option->optionName, $option->packageID, $option->optionValue, $this->languageItemPattern);
+                               }
                        }
+                       I18nHandler::getInstance()->readValues();
                }
-               I18nHandler::getInstance()->readValues();
        }
        
        /**
@@ -153,7 +163,7 @@ class OptionHandler implements IOptionHandler {
                                        'options' => array()
                                );
                                
-                               if (static::checkCategory($superCategoryObject)) {
+                               if ($this->checkCategory($superCategoryObject)) {
                                        if ($level <= 1) {
                                                $superCategory['categories'] = $this->getOptionTree($superCategoryName, $level + 1);
                                        }
@@ -189,25 +199,11 @@ class OptionHandler implements IOptionHandler {
                
                // get options
                if (isset($this->cachedOptionToCategories[$categoryName])) {
-                       $i = 0;
-                       $last = count($this->cachedOptionToCategories[$categoryName]) - 1;
                        foreach ($this->cachedOptionToCategories[$categoryName] as $optionName) {
                                if (!isset($this->options[$optionName]) || !$this->checkOption($this->options[$optionName])) continue;
                                
-                               // get option object
-                               $option = $this->options[$optionName];
-                               
-                               // get form element html
-                               $html = $this->getFormElement($option->optionType, $option);
-                               
                                // add option to list
-                               $children[] = array(
-                                       'object' => $option,
-                                       'html' => $html,
-                                       'cssClassName' => $this->getTypeObject($option->optionType)->getCSSClassName()
-                               );
-                               
-                               $i++;
+                               $children[] = $this->getOption($optionName);
                        }
                }
                
@@ -219,7 +215,7 @@ class OptionHandler implements IOptionHandler {
         */
        public function readData() {
                foreach ($this->options as $option) {
-                       if ($option->supportI18n) {
+                       if ($this->supportI18n && $option->supportI18n) {
                                I18nHandler::getInstance()->register($option->optionName);
                                I18nHandler::getInstance()->setOptions($option->optionName, $option->packageID, $option->optionValue, $this->languageItemPattern);
                        }
@@ -231,12 +227,16 @@ class OptionHandler implements IOptionHandler {
        /**
         * @see wcf\system\option\IOptionHandler::save()
         */
-       public function save($categoryName, $optionPrefix) {
+       public function save($categoryName = null, $optionPrefix = null) {
                $saveOptions = array();
                
+               if ($this->supportI18n && ($categoryName === null || $optionPrefix === null)) {
+                       throw new SystemException("category name or option prefix missing");
+               }
+               
                foreach ($this->options as $option) {
                        // handle i18n support
-                       if ($option->supportI18n) {
+                       if ($this->supportI18n && $option->supportI18n) {
                                if (I18nHandler::getInstance()->isPlainValue($option->optionName)) {
                                        I18nHandler::getInstance()->remove($optionPrefix . $option->optionID, $option->packageID);
                                        $saveOptions[$option->optionID] = I18nHandler::getInstance()->getValue($option->optionName);
@@ -254,6 +254,26 @@ class OptionHandler implements IOptionHandler {
                return $saveOptions;
        }
        
+       /**
+        * Returns a parsed option.
+        * 
+        * @param       string          $optionName
+        * @return      array
+        */
+       protected function getOption($optionName) {
+               // get option object
+               $option = $this->options[$optionName];
+               
+               // get form element html
+               $html = $this->getFormElement($option->optionType, $option);
+               
+               return array(
+                       'object' => $option,
+                       'html' => $html,
+                       'cssClassName' => $this->getTypeObject($option->optionType)->getCSSClassName()
+               );
+       }
+       
        /**
         * Validates an option.
         * 
diff --git a/wcfsetup/install/files/lib/system/option/user/UserOptionHandler.class.php b/wcfsetup/install/files/lib/system/option/user/UserOptionHandler.class.php
new file mode 100644 (file)
index 0000000..1b474ea
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+namespace wcf\system\option\user;
+use wcf\data\option\category\OptionCategory;
+use wcf\data\option\Option;
+use wcf\data\user\User;
+use wcf\system\exception\UserInputException;
+use wcf\system\option\OptionHandler;
+
+/**
+ * Default implementation for user option lists.
+ *
+ * @author     Alexander Ebert
+ * @copyright  2001-2011 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage system.option
+ * @category   Community Framework
+ */
+class UserOptionHandler extends OptionHandler {
+       public function setUser(User $user) {
+               $this->optionValues = array();
+               
+               foreach ($this->options as $option) {
+                       $userOption = 'userOption' . $option->optionID;
+                       $this->optionValues[$option->optionName] = $user->{$userOption};
+               }
+       }
+       
+       /**
+        * @see wcf\system\option\OptionHandler::validateOption()
+        */
+       protected function validateOption(Option $option) {
+               parent::validateOption($option);
+               
+               if ($option->required && empty($this->optionValues[$option->optionName])) {
+                       throw new UserInputException($option->optionName);
+               }
+       }
+       
+       /**
+        * @see wcf\system\option\OptionHandler::checkCategory()
+        */
+       protected function checkCategory(OptionCategory $category) {
+               if ($category->categoryName == 'hidden') {
+                       return false;
+               }
+               
+               return parent::checkCategory($category);
+       }
+}