Merge branch 'master' of git://github.com/WoltLab/WCF into enhancement/cleanup
authorMatthias Schmidt <gravatronics@live.com>
Sun, 14 Oct 2012 07:02:36 +0000 (09:02 +0200)
committerMatthias Schmidt <gravatronics@live.com>
Sun, 14 Oct 2012 07:02:36 +0000 (09:02 +0200)
Conflicts:
wcfsetup/install/files/js/WCF.js
wcfsetup/install/files/lib/system/package/plugin/ACPMenuPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/ACPSearchProviderPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/ACPTemplatePackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/CoreObjectPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/CronjobPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/EventListenerPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/TemplateListenerPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/UserGroupOptionPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/UserOptionPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/template/plugin/DatediffModifierTemplatePlugin.class.php

50 files changed:
1  2 
wcfsetup/install/files/acp/js/WCF.ACP.js
wcfsetup/install/files/js/WCF.js
wcfsetup/install/files/lib/action/AJAXProxyAction.class.php
wcfsetup/install/files/lib/action/ClipboardAction.class.php
wcfsetup/install/files/lib/data/AbstractDatabaseObjectAction.class.php
wcfsetup/install/files/lib/data/DatabaseObject.class.php
wcfsetup/install/files/lib/data/DatabaseObjectDecorator.class.php
wcfsetup/install/files/lib/data/IStorableObject.class.php
wcfsetup/install/files/lib/data/category/CategoryAction.class.php
wcfsetup/install/files/lib/data/cronjob/CronjobAction.class.php
wcfsetup/install/files/lib/data/language/LanguageEditor.class.php
wcfsetup/install/files/lib/data/option/OptionEditor.class.php
wcfsetup/install/files/lib/data/package/update/server/PackageUpdateServerAction.class.php
wcfsetup/install/files/lib/data/style/Style.class.php
wcfsetup/install/files/lib/data/style/StyleAction.class.php
wcfsetup/install/files/lib/data/user/User.class.php
wcfsetup/install/files/lib/data/user/UserAction.class.php
wcfsetup/install/files/lib/system/cache/builder/StyleCacheBuilder.class.php
wcfsetup/install/files/lib/system/category/AbstractCategoryType.class.php
wcfsetup/install/files/lib/system/image/adapter/GDImageAdapter.class.php
wcfsetup/install/files/lib/system/image/adapter/ImageAdapter.class.php
wcfsetup/install/files/lib/system/language/I18nHandler.class.php
wcfsetup/install/files/lib/system/package/PackageInstallationDispatcher.class.php
wcfsetup/install/files/lib/system/package/plugin/ACPMenuPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/ACPSearchProviderPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/ACPTemplatePackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/AbstractXMLPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/ClipboardActionPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/CoreObjectPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/CronjobPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/EventListenerPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/ObjectTypeDefinitionPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/ObjectTypePackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/OptionPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/PIPPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/PageMenuPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/SitemapPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/StylePackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/TemplateListenerPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/UserGroupOptionPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/package/plugin/UserOptionPackageInstallationPlugin.class.php
wcfsetup/install/files/lib/system/request/RouteHandler.class.php
wcfsetup/install/files/lib/system/style/StyleHandler.class.php
wcfsetup/install/files/lib/system/template/plugin/DatediffModifierTemplatePlugin.class.php
wcfsetup/install/files/lib/util/DateUtil.class.php
wcfsetup/install/files/lib/util/StringUtil.class.php
wcfsetup/install/files/style/dialog.less
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml
wcfsetup/setup/db/install.sql

index 42124d39f691e317bd9eb3f39733ac3b84403200,d20ea2863aa51b4c47342350faa6406cf8d48293..ba5e86f6c169bb73cf41f45738003cee5dfc7470
@@@ -876,14 -890,7 +887,7 @@@ WCF.ACP.Category.Collapsible = WCF.Coll
                
                this._super(className);
        },
 -
 +      
-       /**
-        * @see WCF.Collapsible.Remote._getAdditionalParameters()
-        */
-       _getAdditionalParameters: function(containerID) {
-               return {objectTypeID : this._objectTypeID};
-       },
-       
        /**
         * @see WCF.Collapsible.Remote._getButtonContainer()
         */
index 3e14f954d1f25683067fd7881c1f9f3ddf29248a,21ea2d31907c666ffe38316e7a3a2533facaf155..6af8e1743e88992ed0eedba898b1fcb732948ce9
@@@ -6629,14 -6657,17 +6659,17 @@@ $.widget('ui.wcfDialog', 
         */
        _initDialog: function(data) {
                // insert template
-               data.ignoreTemplate = true;
-               var $template = this._getResponseValue(data, 'template');
-               if ($template !== null) {
-                       this._content.children().html($template);
+               if (this._getResponseValue(data, 'template')) {
+                       this._content.children().html(this._getResponseValue(data, 'template'));
                        this.render();
                }
+               
+               // set title
+               if (this._getResponseValue(data, 'title')) {
+                       this._setOption('title', this._getResponseValue(data, 'title'));
+               }
        },
 -
 +      
        /**
         * Returns a response value, taking care of different object
         * structure returned by AJAXProxy.
                        
                        // store new dimensions
                        this._contentDimensions = $contentDimensions;
 -
 +                      
                        // move container
+                       this._isRendering = true;
                        this._container.animate({
                                left: $leftOffset + 'px',
                                top: $topOffset + 'px'
                if (this.options.onShow !== null) {
                        this.options.onShow();
                }
-               
-               this._isRendering = true;
        },
 -
 +      
        /**
         * Returns calculated content dimensions.
         * 
index c7dd115948b2e79f5b4fff4b5e41dc2169ca67dd,21682082e7f13a283f643a388c123b1ebba24487..2a912feda5e8dd5767bced481c62335480435767
@@@ -16,9 -16,9 +16,9 @@@ use wcf\util\StringUtil
   * @license   GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
   * @package   com.woltlab.wcf
   * @subpackage        data
 - * @category  Community Framework
 + * @category  Community Framework
   */
- abstract class AbstractDatabaseObjectAction implements IDatabaseObjectAction {
+ abstract class AbstractDatabaseObjectAction implements IDatabaseObjectAction, IDeleteAction {
        /**
         * pending action
         * @var string
index 08ab47a278d25dee282e2d794a38a2371099181a,b61c297ada545f5f7720bb5d32dd48361e7f9f70..35d3bbbcac9de51c05dfad7aa47da47b06d7ced0
@@@ -10,9 -10,9 +10,9 @@@ use wcf\system\exception\SystemExceptio
   * @license   GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
   * @package   com.woltlab.wcf
   * @subpackage        data
 - * @category  Community Framework
 + * @category  Community Framework
   */
- abstract class DatabaseObjectDecorator extends DatabaseObject {
+ abstract class DatabaseObjectDecorator extends DatabaseObject implements IDatabaseObjectProcessor {
        /**
         * name of the base class
         * @var string
index 94d326ee63fc288d628c913c1cbd598c1550ef94,ccc019054641e8f16698be586fb2e9b6844b602e..8fe18a12662118aa2645886770b3974c397a4ebd
@@@ -15,9 -19,9 +19,9 @@@ use wcf\system\WCF
   * @license   GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
   * @package   com.woltlab.wcf
   * @subpackage        data.category
 - * @category  Community Framework
 + * @category  Community Framework
   */
- class CategoryAction extends AbstractDatabaseObjectAction {
+ class CategoryAction extends AbstractDatabaseObjectAction implements ICollapsibleContainerAction, IPositionAction, IToggleAction {
        /**
         * categorized object type
         * @var wcf\data\object\type\ObjectType
index c12aafff48793dd620f0fd78c203fa5af8f1168a,aba93de57c477edf6e68398939244ac33ab87976..a191ae9964c1cb50cd7f89210b5ef32e3d53014f
@@@ -15,11 -16,11 +16,11 @@@ use wcf\util\DateUtil
   * @license   GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
   * @package   com.woltlab.wcf
   * @subpackage        data.cronjob
 - * @category  Community Framework
 + * @category  Community Framework
   */
- class CronjobAction extends AbstractDatabaseObjectAction {
+ class CronjobAction extends AbstractDatabaseObjectAction implements IToggleAction {
        /**
 -       * @see wcf\data\AbstractDatabaseObjectAction::$className
 +       * @see wcf\data\AbstractDatabaseObjectAction::$className
         */
        protected $className = 'wcf\data\cronjob\CronjobEditor';
        
index 5d482e66aacabf8e1f0c744516e7315f29036f2b,c100f245d1d9174e3f4276a00a8fc645f57b0b8d..9861a3a43e4fa14028c85f32b72b83b7bfcaf61c
@@@ -25,9 -26,9 +26,9 @@@ use wcf\util\XML
   * @license   GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
   * @package   com.woltlab.wcf
   * @subpackage        data.language
 - * @category  Community Framework
 + * @category  Community Framework
   */
- class LanguageEditor extends DatabaseObjectEditor {
+ class LanguageEditor extends DatabaseObjectEditor implements IEditableCachedObject {
        /**
         * @see wcf\data\DatabaseObjectDecorator::$baseClass
         */
index 3a924e5ac6b03827a4a16c3d42b87fbdc9e72abc,68166df0b6301f6e714c7b93ce5bee9e4e2aba7a..2d36da98f04adef68446f55a2e9d11796280d230
@@@ -10,11 -11,11 +11,11 @@@ use wcf\data\IToggleAction
   * @license   GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
   * @package   com.woltlab.wcf
   * @subpackage        data.package.update.server
 - * @category  Community Framework
 + * @category  Community Framework
   */
- class PackageUpdateServerAction extends AbstractDatabaseObjectAction {
+ class PackageUpdateServerAction extends AbstractDatabaseObjectAction implements IToggleAction {
        /**
 -       * @see wcf\data\AbstractDatabaseObjectAction::$className
 +       * @see wcf\data\AbstractDatabaseObjectAction::$className
         */
        protected $className = 'wcf\data\package\update\server\PackageUpdateServerEditor';
        
index a86f7aac61106f65465c5908a4ce2cf46b92f427,c3b9baff01db00ae8e72ed5d1541e12972ead400..41e110349017ffb2ba765d7ce0962eef7d717a7c
@@@ -14,7 -26,430 +26,430 @@@ use wcf\util\StringUtil
   */
  class StyleAction extends AbstractDatabaseObjectAction {
        /**
 -       * @see wcf\data\AbstractDatabaseObjectAction::$className
 +       * @see wcf\data\AbstractDatabaseObjectAction::$className
         */
        protected $className = 'wcf\data\style\StyleEditor';
+       
+       /**
+        * @see wcf\data\AbstractDatabaseObjectAction::$permissionsDelete
+        */
+       protected $permissionsDelete = array('admin.style.canDeleteStyle');
+       
+       /**
+        * @see wcf\data\AbstractDatabaseObjectAction::$permissionsUpdate
+        */
+       protected $permissionsUpdate = array('admin.style.canEditStyle');
+       
+       /**
+        * @see wcf\data\AbstractDatabaseObjectAction::create()
+        */
+       public function create() {
+               $style = parent::create();
+               
+               // add variables
+               $this->updateVariables($style);
+               
+               // handle style preview image
+               $this->updateStylePreviewImage($style);
+               
+               return $style;
+       }
+       
+       /**
+        * @see wcf\data\AbstractDatabaseObjectAction::update()
+        */
+       public function update() {
+               parent::update();
+               
+               foreach ($this->objects as $style) {
+                       // update variables
+                       $this->updateVariables($style->getDecoratedObject(), true);
+                       
+                       // handle style preview image
+                       $this->updateStylePreviewImage($style->getDecoratedObject());
+                       
+                       // reset stylesheet
+                       StyleHandler::getInstance()->resetStylesheet($style->getDecoratedObject());
+               }
+       }
+       
+       /**
+        * @see wcf\data\AbstractDatabaseObjectAction::delete()
+        */
+       public function delete() {
+               $count = parent::delete();
+               
+               foreach ($this->objects as $style) {
+                       // remove custom icons
+                       if ($style->iconPath && $style->iconPath != 'icon/') {
+                               $this->removeDirectory($style->iconPath);
+                       }
+                       
+                       // remove custom images
+                       if ($style->imagePath && $style->imagePath != 'images/') {
+                               $this->removeDirectory($style->imagePath);
+                       }
+                       
+                       // remove preview image
+                       $previewImage = WCF_DIR.'images/'.$style->image;
+                       if (file_exists($previewImage)) {
+                               @unlink($previewImage);
+                       }
+                       
+                       // remove stylesheet
+                       StyleHandler::getInstance()->resetStylesheet($style->getDecoratedObject());
+               }
+               
+               return $count;
+       }
+       
+       /**
+        * Recursively removes a directory and all it's contents.
+        * 
+        * @param       string          $pathComponent
+        */
+       protected function removeDirectory($pathComponent) {
+               $dir = WCF_DIR.$pathComponent;
+               if (is_dir($dir)) {
+                       $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir), \RecursiveIteratorIterator::CHILD_FIRST);
+                       foreach ($iterator as $path) {
+                               if ($path->isDir()) {
+                                       @rmdir($path->__toString());
+                               }
+                               else {
+                                       @unlink($path->__toString());
+                               }
+                       }
+                       
+                       @rmdir($dir);
+               }
+       }
+       
+       /**
+        * Updates style variables for given style.
+        * 
+        * @param       wcf\data\style\Style    $style
+        * @param       boolean                 $removePreviousVariables
+        */
+       protected function updateVariables(Style $style, $removePreviousVariables = false) {
+               if (!isset($this->parameters['variables']) || !is_array($this->parameters['variables'])) {
+                       return;
+               }
+               
+               $sql = "SELECT  variableID, variableName, defaultValue
+                       FROM    wcf".WCF_N."_style_variable";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute();
+               $variables = array();
+               while ($row = $statement->fetchArray()) {
+                       $variableName = $row['variableName'];
+                               
+                       // ignore variables with identical value
+                       if (isset($this->parameters['variables'][$variableName])) {
+                               if ($this->parameters['variables'][$variableName] == $row['defaultValue']) {
+                                       continue;
+                               }
+                               else {
+                                       $variables[$row['variableID']] = $this->parameters['variables'][$variableName];
+                               }
+                       }
+               }
+                       
+               // remove previously set variables
+               if ($removePreviousVariables) {
+                       $sql = "DELETE FROM     wcf".WCF_N."_style_variable_value
+                               WHERE           styleID = ?";
+                       $statement = WCF::getDB()->prepareStatement($sql);
+                       $statement->execute(array($style->styleID));
+               }
+                       
+               // insert variables that differ from default values
+               if (!empty($variables)) {
+                       $sql = "INSERT INTO     wcf".WCF_N."_style_variable_value
+                                               (styleID, variableID, variableValue)
+                               VALUES          (?, ?, ?)";
+                       $statement = WCF::getDB()->prepareStatement($sql);
+                               
+                       WCF::getDB()->beginTransaction();
+                       foreach ($variables as $variableID => $variableValue) {
+                               $statement->execute(array(
+                                       $style->styleID,
+                                       $variableID,
+                                       $variableValue
+                               ));
+                       }
+                       WCF::getDB()->commitTransaction();
+               }
+       }
+       
+       /**
+        * Updates style preview image.
+        * 
+        * @param       wcf\data\style\Style    $style
+        */
+       protected function updateStylePreviewImage(Style $style) {
+               if (!isset($this->parameters['tmpHash'])) {
+                       return;
+               }
+               
+               $fileExtension = WCF::getSession()->getVar('stylePreview-'.$this->parameters['tmpHash']);
+               if ($fileExtension !== null) {
+                       $oldFilename = WCF_DIR.'images/stylePreview-'.$this->parameters['tmpHash'].'.'.$fileExtension;
+                       if (file_exists($oldFilename)) {
+                               $filename = 'stylePreview-'.$style->styleID.'.'.$fileExtension;
+                               if (@rename($oldFilename, WCF_DIR.'images/'.$filename)) {
+                                       // delete old file if it has a different file extension
+                                       if ($style->image != $filename) {
+                                               @unlink(WCF_DIR.'images/'.$style->image);
+                                               
+                                               // update filename in database
+                                               $sql = "UPDATE  wcf".WCF_N."_style
+                                                       SET     image = ?
+                                                       WHERE   styleID = ?";
+                                               $statement = WCF::getDB()->prepareStatement($sql);
+                                               $statement->execute(array(
+                                                       $filename,
+                                                       $style->styleID
+                                               ));
+                                       }
+                               }
+                               else {
+                                       // remove temp file
+                                       @unlink($oldFilename);
+                               }
+                       }
+               }
+       }
+       
+       /**
+        * Validates the upload action.
+        */
+       public function validateUpload() {
+               // check upload permissions
+               if (!WCF::getSession()->getPermission('admin.style.canAddStyle')) {
+                       throw new PermissionDeniedException();
+               }
+               
+               if (!isset($this->parameters['tmpHash']) || empty($this->parameters['tmpHash'])) {
+                       throw new UserInputException('tmpHash');
+               }
+               
+               if (count($this->parameters['__files']->getFiles()) != 1) {
+                       throw new IllegalLinkException();
+               }
+               
+               // check max filesize, allowed file extensions etc.
+               $this->parameters['__files']->validateFiles(new DefaultUploadFileValidationStrategy(PHP_INT_MAX, array('jpg', 'jpeg', 'png')));
+       }
+       
+       /**
+        * Handles uploaded preview images.
+        * 
+        * @return      array<string>
+        */
+       public function upload() {
+               // save files
+               $files = $this->parameters['__files']->getFiles();
+               $file = $files[0];
+               
+               try {
+                       if (!$file->getValidationErrorType()) {
+                               // shrink avatar if necessary
+                               $fileLocation = $file->getLocation();
+                               $imageData = getimagesize($fileLocation);
+                               if ($imageData[0] > Style::PREVIEW_IMAGE_MAX_WIDTH || $imageData[1] > Style::PREVIEW_IMAGE_MAX_HEIGHT) {
+                                       try {
+                                               $adapter = ImageHandler::getInstance()->getAdapter();
+                                               $adapter->loadFile($fileLocation);
+                                               $fileLocation = FileUtil::getTemporaryFilename();
+                                               $thumbnail = $adapter->createThumbnail(Style::PREVIEW_IMAGE_MAX_WIDTH, Style::PREVIEW_IMAGE_MAX_HEIGHT, false);
+                                               $adapter->writeImage($thumbnail, $fileLocation);
+                                               $imageData = getimagesize($fileLocation);
+                                       }
+                                       catch (SystemException $e) {
+                                               throw new UserInputException('image');
+                                       }
+                               }
+                               
+                               // move uploaded file
+                               if (@copy($fileLocation, WCF_DIR.'images/stylePreview-'.$this->parameters['tmpHash'].'.'.$file->getFileExtension())) {
+                                       @unlink($fileLocation);
+                                       
+                                       // store extension within session variables
+                                       WCF::getSession()->register('stylePreview-'.$this->parameters['tmpHash'], $file->getFileExtension());
+                                       
+                                       // return result
+                                       return array(
+                                               'errorType' => '',
+                                               'url' => WCF::getPath().'images/stylePreview-'.$this->parameters['tmpHash'].'.'.$file->getFileExtension()
+                                       );
+                               }
+                               else {
+                                       throw new UserInputException('image', 'uploadFailed');
+                               }
+                       }
+               }
+               catch (UserInputException $e) {
+                       $file->setValidationErrorType($e->getType());
+               }
+               
+               return array('errorType' => $file->getValidationErrorType());
+       }
+       
+       /**
+        * Validates parameters to assign a new default style.
+        */
+       public function validateSetAsDefault() {
+               if (!WCF::getSession()->getPermission('admin.style.canEditStyle')) {
+                       throw new PermissionDeniedException();
+               }
+               
+               if (empty($this->objects)) {
+                       $this->readObjects();
+                       if (empty($this->objects)) {
+                               throw new UserInputException('objectIDs');
+                       }
+               }
+               
+               if (count($this->objects) > 1) {
+                       throw new UserInputException('objectIDs');
+               }
+       }
+       
+       /**
+        * Sets a style as new default style.
+        */
+       public function setAsDefault() {
+               $styleEditor = current($this->objects);
+               $styleEditor->setAsDefault();
+       }
+       
+       /**
+        * Validates parameters to copy a style.
+        */
+       public function validateCopy() {
+               if (!WCF::getSession()->getPermission('admin.style.canAddStyle')) {
+                       throw new PermissionDeniedException();
+               }
+               
+               if (empty($this->objects)) {
+                       $this->readObjects();
+                       if (empty($this->objects)) {
+                               throw new UserInputException('objectIDs');
+                       }
+               }
+               
+               if (count($this->objects) > 1) {
+                       throw new UserInputException('objectIDs');
+               }
+       }
+       
+       /**
+        * Copies a style.
+        * 
+        * @return      array<string>
+        */
+       public function copy() {
+               $style = current($this->objects);
+               
+               // get unique style name
+               $sql = "SELECT  styleName
+                       FROM    wcf".WCF_N."_style
+                       WHERE   styleName LIKE ?
+                               AND styleID <> ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute(array(
+                       $style->styleName.'%',
+                       $style->styleID
+               ));
+               $numbers = array();
+               $regEx = new Regex('\((\d+)\)$');
+               while ($row = $statement->fetchArray()) {
+                       $styleName = $row['styleName'];
+                       
+                       if ($regEx->match($styleName)) {
+                               $matches = $regEx->getMatches();
+                               
+                               // check if name matches the pattern 'styleName (x)'
+                               if ($styleName == $style->styleName . ' ('.$matches[1].')') {
+                                       $numbers[] = $matches[1];
+                               }
+                       }
+               }
+               
+               $number = (count($numbers)) ? max($numbers) + 1 : 2;
+               $styleName = $style->styleName . ' ('.$number.')';
+               
+               // create the new style
+               $newStyle = StyleEditor::create(array(
+                       'packageID' => PACKAGE_ID,
+                       'styleName' => $styleName,
+                       'templateGroupID' => $style->templateGroupID,
+                       'disabled' => 1, // newly created styles are disabled by default
+                       'styleDescription' => $style->styleDescription,
+                       'styleVersion' => $style->styleVersion,
+                       'styleDate' => $style->styleDate,
+                       'copyright' => $style->copyright,
+                       'license' => $style->license,
+                       'authorName' => $style->authorName,
+                       'authorURL' => $style->authorURL,
+                       'iconPath' => $style->iconPath,
+                       'imagePath' => $style->imagePath
+               ));
+               
+               // copy style variables
+               $sql = "INSERT INTO     wcf".WCF_N."_style_variable_value
+                                       (styleID, variableID, variableValue)
+                       SELECT          ".$newStyle->styleID." AS styleID, value.variableID, value.variableValue
+                       FROM            wcf".WCF_N."_style_variable_value value
+                       WHERE           value.styleID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute(array($style->styleID));
+               
+               // copy preview image
+               if ($style->image) {
+                       // get extension
+                       $fileExtension = StringUtil::substring($style->image, StringUtil::lastIndexOf($style->image, '.'));
+                       
+                       // copy existing preview image
+                       if (@copy(WCF_DIR.'images/'.$style->image, WCF_DIR.'images/stylePreview-'.$newStyle->styleID.$fileExtension)) {
+                               // bypass StyleEditor::update() to avoid scaling of already fitting image
+                               $sql = "UPDATE  wcf".WCF_N."_style
+                                       SET     image = ?
+                                       WHERE   styleID = ?";
+                               $statement = WCF::getDB()->prepareStatement($sql);
+                               $statement->execute(array(
+                                       'stylePreview-'.$newStyle->styleID.$fileExtension,
+                                       $newStyle->styleID
+                               ));
+                       }
+               }
+               
+               return array(
+                       'redirectURL' => LinkHandler::getInstance()->getLink('StyleEdit', array('id' => $newStyle->styleID))
+               );
+       }
+       
+       /**
+        * Validates parameters to enable/disable styles.
+        */
+       public function validateToggle() {
+               parent::validateUpdate();
+               
+               foreach ($this->objects as $style) {
+                       if ($style->isDefault) {
+                               throw new UserInputException('objectIDs');
+                       } 
+               }
+       }
+       
+       /**
+        * Enables/disables styles.
+        */
+       public function toggle() {
+               foreach ($this->objects as $style) {
+                       $disabled = ($style->disabled) ? 0 : 1;
+                       $style->update(array('disabled' => $disabled));
+               }
+       }
  }
index 6089679dc2a986eba2314393f70ad521279a81ec,75ccd723a8ac11bf7765085dd81230e38e85a69d..6dc67cc98971ff2f66c9fc8a6345b558a80827a1
@@@ -16,9 -17,9 +17,9 @@@ use wcf\util\StringUtil
   * @license   GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
   * @package   com.woltlab.wcf
   * @subpackage        data.user
 - * @category  Community Framework
 + * @category  Community Framework
   */
- class UserAction extends AbstractDatabaseObjectAction {
+ class UserAction extends AbstractDatabaseObjectAction implements ISearchAction {
        /**
         * @see wcf\data\AbstractDatabaseObjectAction::$className
         */
index 4df2d94c5d730e4296c7e1a19e8d11b4d04e1131,c514e8a954fa28fae3502c9e9fe922c71745fba0..326b33f25915792857e11d0b918e51d5c8cb0a67
@@@ -24,14 -24,9 +24,9 @@@ class ClipboardActionPackageInstallatio
         */
        protected $pages = array();
        
-       /**
-        * @see wcf\system\package\plugin\AbstractPackageInstallationPlugin::$tableName
-        */
-       public $tableName = 'clipboard_action';
-       
        /**
         * @see wcf\system\package\plugin\AbstractXMLPackageInstallationPlugin::$tagName
 -       */     
 +       */
        public $tagName = 'action';
        
        /**
index 484ce71a8b80950331d58b9898d5412af78decd8,ab0834e0085b138f5e618f73e01e05aebf0bdbf0..7826184fbfb7f9357f5b4974d8af00086a3cbdf3
@@@ -19,16 -19,6 +19,11 @@@ class EventListenerPackageInstallationP
         */
        public $className = 'wcf\data\event\listener\EventListenerEditor';
        
-       /**
-        * @see wcf\system\package\plugin\AbstractPackageInstallationPlugin::$tableName
-        */
-       public $tableName = 'event_listener';
-       
 +      /**
 +       * @see wcf\system\package\plugin\AbstractXMLPackageInstallationPlugin::$tagName
 +       */
 +      public $tagName = 'eventlistener';
 +      
        /**
         * @see wcf\system\package\plugin\AbstractXMLPackageInstallationPlugin::handleDelete()
         */
index 29af11056d8fa414efce07cbc1edd2efdad46431,478ebe1a97e02efc3000e7aa8b8c39615e23fff2..59c35db8cf236d4aa092bb68f916bcac6c2238f9
@@@ -18,14 -18,9 +18,9 @@@ class ObjectTypeDefinitionPackageInstal
         */
        public $className = 'wcf\data\object\type\definition\ObjectTypeDefinitionEditor';
        
-       /**
-        * @see wcf\system\package\plugin\AbstractPackageInstallationPlugin::$tableName
-        */
-       public $tableName = 'object_type_definition';
-       
        /**
         * @see wcf\system\package\plugin\AbstractXMLPackageInstallationPlugin::$tagName
 -       */     
 +       */
        public $tagName = 'definition';
        
        /**
index d834849d97b9ac5e576995e07750eab26f76daa9,28e2093d831c9d685ce9890206d20329c2c54202..045d14e863adb51802e1405361ad2e9810d489fe
@@@ -19,14 -19,9 +19,9 @@@ class ObjectTypePackageInstallationPlug
         */
        public $className = 'wcf\data\object\type\ObjectTypeEditor';
        
-       /**
-        * @see wcf\system\package\plugin\AbstractPackageInstallationPlugin::$tableName
-        */
-       public $tableName = 'object_type';
-       
        /**
         * @see wcf\system\package\plugin\AbstractXMLPackageInstallationPlugin::$tagName
 -       */     
 +       */
        public $tagName = 'type';
        
        /**
index 3a3320dfae64ea0cc434530e1d111a3610d488c9,2d82a0e488a49713f09f474f4eb984247f4cc5e6..8c7a93fd6cad8e56abfb6c4390d99b78d5db5551
@@@ -19,9 -19,13 +19,13 @@@ use wcf\util\StringUtil
  class OptionPackageInstallationPlugin extends AbstractOptionPackageInstallationPlugin {
        /**
         * @see wcf\system\package\plugin\AbstractPackageInstallationPlugin::$tableName
 -       */     
 +       */
        public $tableName = 'option';
  
+       /**
+        * list of names of tags which aren't considered as additional data
+        * @var array<string>
+        */
        public static $reservedTags = array('name', 'optiontype', 'defaultvalue', 'validationpattern', 'enableoptions', 'showorder', 'hidden', 'selectoptions', 'categoryname', 'permissions', 'options', 'attrs', 'cdata', 'supporti18n');
        
        /**
index 53c8f0e7b1eb075ab4bc15640eee0961ae43d7c7,e03d716ba0a6ff86064efeb29efc8daabb741708..5721c95c95e58d56a497f798786bfe94e2766664
@@@ -4,9 -4,9 +4,9 @@@ use wcf\system\WCF
  
  /**
   * This PIP installs, updates or deletes package installation plugins.
 - *
 + * 
   * @author    Marcel Werk
-  * @copyright 2001-2011 WoltLab GmbH
+  * @copyright 2001-2012 WoltLab GmbH
   * @license   GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
   * @package   com.woltlab.wcf
   * @subpackage        system.package.plugin
index 92738b643b4f385a21a2a0e223ad472af9c0b113,27843a86a7eda717b73f3d2b25a100b65cd85b0c..132a977180bc5edef291564a8bfd7f54dc592293
@@@ -22,26 -22,12 +22,12 @@@ class UserGroupOptionPackageInstallatio
         * @see wcf\system\package\plugin\AbstractPackageInstallationPlugin::$tableName
         */     
        public $tableName = 'user_group_option';
 -
 +      
-       public static $reservedTags = array('name', 'optiontype', 'defaultvalue', 'admindefaultvalue', 'validationpattern', 'showorder', 'categoryname', 'selectoptions', 'enableoptions', 'permissions', 'options', 'attrs', 'cdata');
-       
        /**
-        * Deletes group-option-categories and/or group-options which where installed by the package.
+        * list of names of tags which aren't considered as additional data
+        * @var array<string>
         */
-       public function uninstall() {
-               // Delete value-entries using categories or options
-               // which will be deleted.
-               $sql = "DELETE FROM     wcf".WCF_N."_user_group_option_value
-                       WHERE           optionID IN (
-                                               SELECT  optionID
-                                               FROM    wcf".WCF_N."_user_group_option
-                                               WHERE   packageID = ?
-                                       )";
-               $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute(array($this->installation->getPackageID()));
-                       
-               parent::uninstall();
-       }
+       public static $reservedTags = array('name', 'optiontype', 'defaultvalue', 'admindefaultvalue', 'validationpattern', 'showorder', 'categoryname', 'selectoptions', 'enableoptions', 'permissions', 'options', 'attrs', 'cdata');
        
        /**
         * @see wcf\system\package\plugin\AbstractOptionPackageInstallationPlugin::saveOption()
index 58d24c8f8b02481859583e13040ad824de0cbaa8,1f08b8acbfd5dcc64bd8a18a0ad358c78a8ed0fb..8c8a4127c44fb310631a18ccd3399762e9a31a49
@@@ -21,9 -21,13 +21,13 @@@ use wcf\util\StringUtil
  class UserOptionPackageInstallationPlugin extends AbstractOptionPackageInstallationPlugin {
        /**
         * @see wcf\system\package\plugin\AbstractPackageInstallationPlugin::$tableName
 -       */     
 +       */
        public $tableName = 'user_option';
        
+       /**
+        * list of names of tags which aren't considered as additional data
+        * @var array<string>
+        */
        public static $reservedTags = array('name', 'optiontype', 'defaultvalue', 'validationpattern', 'required', 'editable', 'visible', 'searchable', 'showorder', 'outputclass', 'selectoptions', 'enableoptions', 'disabled', 'categoryname', 'permissions', 'options', 'attrs', 'cdata');
        
        /**
index 8265de9777a3e8cea6d042230a27b90de9721d79,0000000000000000000000000000000000000000..c3ac5dc9b587d0a652eb10850a0115a12c6c1892
mode 100644,000000..100644
--- /dev/null
@@@ -1,34 -1,0 +1,41 @@@
-  * The 'datediff' modifier calculates the difference between two unix timestamps.
 +<?php
 +namespace wcf\system\template\plugin;
 +use wcf\system\template\TemplateEngine;
 +use wcf\util\DateUtil;
 +
 +/**
-  *    {$timestamp|datediff}
-  *    {"123456789"|datediff:$timestamp}
++ * The 'dateDiff' modifier calculates the difference between two unix timestamps
++ * and returns it as a textual date interval. The second parameter $fullInterval
++ * indicates if the full difference is returned or just a rounded difference.
 + * 
 + * Usage:
-  * @author    Marcel Werk
++ * {$timestamp|dateDiff}
++ * {"123456789"|dateDiff:$timestamp:$fullInverval}
 + *
-  * @category  Community Framework
++ * @author    Matthias Schmidt, Marcel Werk
 + * @copyright 2001-2012 WoltLab GmbH
 + * @license   GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 + * @package   com.woltlab.wcf
 + * @subpackage        system.template.plugin
- class DatediffModifierTemplatePlugin implements IModifierTemplatePlugin {
++ * @category  Community Framework
 + */
-               // get timestamps
-               if (!isset($tagArgs[1])) $tagArgs[1] = TIME_NOW;
-               $start = min($tagArgs[0], $tagArgs[1]);
-               $end = max($tagArgs[0], $tagArgs[1]);
++class DateDiffModifierTemplatePlugin implements IModifierTemplatePlugin {
 +      /**
 +       * @see wcf\system\template\IModifierTemplatePlugin::execute()
 +       */
 +      public function execute($tagArgs, TemplateEngine $tplObj) {
-               // TODO: method doesn't exists anymore
-               // return DateUtil::diff($start, $end, 'string');
-               return '';
++              if (!isset($tagArgs[1])) {
++                      $tagArgs[1] = TIME_NOW;
++              }
 +              
++              $fullInterval = false;
++              if (isset($tagArgs[2])) {
++                      $fullInterval = $tagArgs[2];
++              }
++              
++              $startTime = DateUtil::getDateTimeByTimestamp(min($tagArgs[0], $tagArgs[1]));
++              $endTime = DateUtil::getDateTimeByTimestamp(max($tagArgs[0], $tagArgs[1]));
++              
++              return DateUtil::formatInterval($endTime->diff($startTime), $fullInterval);
 +      }
 +}
Simple merge
Simple merge
Simple merge