Merged com.woltlab.wcf.acp.style
authorAlexander Ebert <ebert@woltlab.com>
Wed, 2 Jan 2013 00:01:31 +0000 (01:01 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Wed, 2 Jan 2013 00:01:31 +0000 (01:01 +0100)
16 files changed:
com.woltlab.wcf/acpMenu.xml
com.woltlab.wcf/userGroupOption.xml
wcfsetup/install/files/acp/js/WCF.ACP.Style.js [new file with mode: 0644]
wcfsetup/install/files/acp/templates/styleAdd.tpl [new file with mode: 0644]
wcfsetup/install/files/acp/templates/styleExport.tpl [new file with mode: 0644]
wcfsetup/install/files/acp/templates/styleImport.tpl [new file with mode: 0644]
wcfsetup/install/files/acp/templates/styleList.tpl [new file with mode: 0644]
wcfsetup/install/files/acp/templates/styleVariableColor.tpl [new file with mode: 0644]
wcfsetup/install/files/acp/templates/styleVariableUnit.tpl [new file with mode: 0644]
wcfsetup/install/files/lib/acp/form/StyleAddForm.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/acp/form/StyleEditForm.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/acp/form/StyleExportForm.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/acp/form/StyleImportForm.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/acp/page/StyleListPage.class.php [new file with mode: 0644]
wcfsetup/install/files/style/styleEditor.less [new file with mode: 0644]
wcfsetup/install/lang/de.xml

index e54538c9855f1d09fc7e8134b5bed31aff90daff..1a8f1ba5c4d63247657a4cf63f27e1b5c7df801e 100644 (file)
                        <showorder>3</showorder>
                </acpmenuitem>
                
-               <!-- language management -->
+               <!-- page menu -->
+               <acpmenuitem name="wcf.acp.menu.link.pageMenu">
+                       <parent>wcf.acp.menu.link.display</parent>
+               </acpmenuitem>
+               
+               <acpmenuitem name="wcf.acp.menu.link.pageMenu.list">
+                       <controller><![CDATA[wcf\acp\page\PageMenuItemListPage]]></controller>
+                       <parent>wcf.acp.menu.link.pageMenu</parent>
+                       <permissions>admin.display.canManagePageMenu</permissions>
+                       <showorder>1</showorder>
+               </acpmenuitem>
+               
+               <acpmenuitem name="wcf.acp.menu.link.pageMenu.add">
+                       <controller><![CDATA[wcf\acp\form\PageMenuItemAddForm]]></controller>
+                       <parent>wcf.acp.menu.link.pageMenu</parent>
+                       <permissions>admin.display.canManagePageMenu</permissions>
+                       <showorder>2</showorder>
+               </acpmenuitem>
+               <!-- /page menu -->
+               
+               <!-- style -->
+               <acpmenuitem name="wcf.acp.menu.link.style">
+                       <parent>wcf.acp.menu.link.display</parent>
+                       <showorder>1</showorder>
+               </acpmenuitem>
+               
+               <acpmenuitem name="wcf.acp.menu.link.style.list">
+                       <controller><![CDATA[wcf\acp\page\StyleListPage]]></controller>
+                       <parent>wcf.acp.menu.link.style</parent>
+                       <permissions>admin.style.canEditStyle,admin.style.canDeleteStyle</permissions>
+                       <showorder>1</showorder>
+               </acpmenuitem>
+               
+               <acpmenuitem name="wcf.acp.menu.link.style.add">
+                       <controller><![CDATA[wcf\acp\form\StyleAddForm]]></controller>
+                       <parent>wcf.acp.menu.link.style</parent>
+                       <permissions>admin.style.canAddStyle</permissions>
+                       <showorder>2</showorder>
+               </acpmenuitem>
+               
+               <acpmenuitem name="wcf.acp.menu.link.style.import">
+                       <controller><![CDATA[wcf\acp\form\StyleImportForm]]></controller>
+                       <parent>wcf.acp.menu.link.style</parent>
+                       <permissions>admin.style.canAddStyle</permissions>
+                       <showorder>3</showorder>
+               </acpmenuitem>
+               <!-- /style -->
+               
+               <!-- language -->
                <acpmenuitem name="wcf.acp.menu.link.language">
                        <parent>wcf.acp.menu.link.display</parent>
                </acpmenuitem>
                        <parent>wcf.acp.menu.link.language.server</parent>
                        <permissions>admin.language.canAddServer</permissions>
                </acpmenuitem>
-               <!-- /language management -->
-               
-               <!-- page menu -->
-               <acpmenuitem name="wcf.acp.menu.link.pageMenu">
-                       <parent>wcf.acp.menu.link.display</parent>
-               </acpmenuitem>
-               
-               <acpmenuitem name="wcf.acp.menu.link.pageMenu.list">
-                       <controller><![CDATA[wcf\acp\page\PageMenuItemListPage]]></controller>
-                       <parent>wcf.acp.menu.link.pageMenu</parent>
-                       <permissions>admin.display.canManagePageMenu</permissions>
-                       <showorder>1</showorder>
-               </acpmenuitem>
-               
-               <acpmenuitem name="wcf.acp.menu.link.pageMenu.add">
-                       <controller><![CDATA[wcf\acp\form\PageMenuItemAddForm]]></controller>
-                       <parent>wcf.acp.menu.link.pageMenu</parent>
-                       <permissions>admin.display.canManagePageMenu</permissions>
-                       <showorder>2</showorder>
-               </acpmenuitem>
-               <!-- /page menu -->
+               <!-- /language -->
                
                <acpmenuitem name="wcf.acp.menu.link.content">
                        <showorder>4</showorder>
index d1069f6033a96caa8988ea08a99bc420e7824afb..70782701b05f319ce25adc4650a6f34295dc3f47 100644 (file)
                                <defaultvalue>0</defaultvalue>
                                <admindefaultvalue>1</admindefaultvalue>
                        </option>
+                       <option name="admin.style.canAddStyle">
+                               <categoryname>admin.style</categoryname>
+                               <optiontype>boolean</optiontype>
+                               <defaultvalue>0</defaultvalue>
+                               <admindefaultvalue>1</admindefaultvalue>
+                               <showorder>1</showorder>
+                       </option>
+                       <option name="admin.style.canEditStyle">
+                               <categoryname>admin.style</categoryname>
+                               <optiontype>boolean</optiontype>
+                               <defaultvalue>0</defaultvalue>
+                               <admindefaultvalue>1</admindefaultvalue>
+                               <showorder>2</showorder>
+                       </option>
+                       <option name="admin.style.canDeleteStyle">
+                               <categoryname>admin.style</categoryname>
+                               <optiontype>boolean</optiontype>
+                               <defaultvalue>0</defaultvalue>
+                               <admindefaultvalue>1</admindefaultvalue>
+                               <showorder>3</showorder>
+                       </option>
                        <option name="admin.style.canUseDisabledStyle">
                                <categoryname>admin.style</categoryname>
                                <optiontype>boolean</optiontype>
diff --git a/wcfsetup/install/files/acp/js/WCF.ACP.Style.js b/wcfsetup/install/files/acp/js/WCF.ACP.Style.js
new file mode 100644 (file)
index 0000000..a920152
--- /dev/null
@@ -0,0 +1,240 @@
+/**
+ * ACP Style related classes.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2012 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ */
+WCF.ACP.Style = { };
+
+/**
+ * Handles style duplicating.
+ * 
+ * @param      integer         styleID
+ */
+WCF.ACP.Style.CopyStyle = Class.extend({
+       /**
+        * style id
+        * @var integer
+        */
+       _styleID: 0,
+       
+       /**
+        * Initializes the WCF.ACP.Style.CopyStyle class.
+        * 
+        * @param       integer         styleID
+        */
+       init: function(styleID) {
+               this._styleID = styleID;
+               
+               var self = this;
+               $('.jsCopyStyle').click(function() {
+                       WCF.System.Confirmation.show(WCF.Language.get('wcf.acp.style.copyStyle.confirmMessage'), $.proxy(self._copy, self));
+               });
+       },
+       
+       /**
+        * Invokes the style duplicating process.
+        * 
+        * @param       string          action
+        */
+       _copy: function(action) {
+               if (action === 'confirm') {
+                       new WCF.Action.Proxy({
+                               autoSend: true,
+                               data: {
+                                       actionName: 'copy',
+                                       className: 'wcf\\data\\style\\StyleAction',
+                                       objectIDs: [ this._styleID ]
+                               },
+                               success: $.proxy(this._success, this)
+                       });
+               }
+       },
+       
+       /**
+        * Redirects to newly created style.
+        * 
+        * @param       object          data
+        * @param       string          textStatus
+        * @param       jQuery          jqXHR
+        */
+       _success: function(data, textStatus, jqXHR) {
+               window.location = data.returnValues.redirectURL;
+       }
+});
+
+/**
+ * Handles the preview image upload.
+ * 
+ * @param      integer         styleID
+ * @param      string          tmpHash
+ */
+WCF.ACP.Style.ImageUpload = WCF.Upload.extend({
+       /**
+        * upload button
+        * @var jQuery
+        */
+       _button: null,
+       
+       /**
+        * preview image
+        * @var jQuery
+        */
+       _image: null,
+       
+       /**
+        * style id
+        * @var integer
+        */
+       _styleID: 0,
+       
+       /**
+        * tmp hash
+        * @var string
+        */
+       _tmpHash: '',
+       
+       /**
+        * @see WCF.Upload.init()
+        */
+       init: function(styleID, tmpHash) {
+               this._styleID = parseInt(styleID) || 0;
+               this._tmpHash = tmpHash;
+               
+               this._button = $('#uploadImage');
+               this._image = $('#styleImage');
+               
+               this._super(this._button, undefined, 'wcf\\data\\style\\StyleAction');
+       },
+       
+       /**
+        * @see WCF.Upload._initFile()
+        */
+       _initFile: function(file) {
+               return this._image;
+       },
+       
+       /**
+        * @see WCF.Upload._getParameters()
+        */
+       _getParameters: function() {
+               return {
+                       styleID: this._styleID,
+                       tmpHash: this._tmpHash
+               };
+       },
+       
+       /**
+        * @see WCF.Upload._success()
+        */
+       _success: function(uploadID, data) {
+               if (data.returnValues.url) {
+                       // show image
+                       this._image.attr('src', data.returnValues.url);
+                       
+                       // hide error
+                       this._button.next('.innerError').remove();
+                       
+                       // show success message
+                       var $notification = new WCF.System.Notification(WCF.Language.get('wcf.acp.style.image.success'));
+                       $notification.show();
+               }
+               else if (data.returnValues.errorType) {
+                       // show error
+                       this._getInnerErrorElement().text(WCF.Language.get('wcf.acp.style.image.error.' + data.returnValues.errorType));
+               }
+       },
+       
+       /**
+        * Returns error display element.
+        * 
+        * @return      jQuery
+        */
+       _getInnerErrorElement: function() {
+               var $span = this._button.next('.innerError');
+               if (!$span.length) {
+                       $span = $('<small class="innerError" />').insertAfter(this._button);
+               }
+               
+               return $span;
+       }
+});
+
+/**
+ * Handles style list management buttons.
+ */
+WCF.ACP.Style.List = Class.extend({
+       /**
+        * action proxy
+        * @var WCF.Action.Proxy
+        */
+       _proxy: null,
+       
+       /**
+        * Initializes the WCF.ACP.Style.List class.
+        */
+       init: function() {
+               this._proxy = new WCF.Action.Proxy({
+                       success: $.proxy(this._success, this)
+               });
+               
+               $('.styleList .buttonList').each($.proxy(function(index, list) {
+                       var $list = $(list);
+                       var $styleID = $list.data('styleID');
+                       
+                       var self = this;
+                       $list.find('.jsSetAsDefault').click(function() { self._click('setAsDefault', $styleID); });
+                       $list.find('.jsDelete').click(function(event) { self._delete(event, $styleID); });
+               }, this));
+       },
+       
+       /**
+        * Executes actions.
+        * 
+        * @param       string          actionName
+        * @param       integer         styleID
+        */
+       _click: function(actionName, styleID) {
+               this._proxy.setOption('data', {
+                       actionName: actionName,
+                       className: 'wcf\\data\\style\\StyleAction',
+                       objectIDs: [ styleID ]
+               });
+               this._proxy.sendRequest();
+       },
+       
+       /**
+        * Prepares to delete a style.
+        * 
+        * @param       object          event
+        * @param       integer         styleID
+        */
+       _delete: function(event, styleID) {
+               var $confirmMessage = $(event.currentTarget).data('confirmMessage');
+               if ($confirmMessage) {
+                       var self = this;
+                       WCF.System.Confirmation.show($confirmMessage, function(action) {
+                               if (action === 'confirm') {
+                                       self._click('delete', styleID);
+                               }
+                       });
+               }
+               else {
+                       // invoke action directly
+                       this._click('delete', styleID);
+               }
+       },
+       
+       /**
+        * Reloads the page after an action was executed successfully.
+        * 
+        * @param       object          data
+        * @param       string          textStatus
+        * @param       jQuery          jqXHR
+        */
+       _success: function (data, textStatus, jqXHR) {
+               // reload page
+               window.location.reload();
+       }
+});
diff --git a/wcfsetup/install/files/acp/templates/styleAdd.tpl b/wcfsetup/install/files/acp/templates/styleAdd.tpl
new file mode 100644 (file)
index 0000000..6d93482
--- /dev/null
@@ -0,0 +1,502 @@
+{include file='header' pageTitle='wcf.acp.style.'|concat:$action}
+
+<script type="text/javascript" src="{@$__wcf->getPath()}acp/js/WCF.ACP.Style.js"></script>
+<script type="text/javascript" src="{@$__wcf->getPath()}js/WCF.ColorPicker.js"></script>
+<script type="text/javascript">
+       //<![CDATA[
+       $(function() {
+               new WCF.ColorPicker('.jsColorPicker');
+               WCF.TabMenu.init();
+               
+               var $useFluidLayout = $('#useFluidLayout');
+               var $fluidLayoutVariables = $('#fluidLayoutVariables');
+               var $fixedLayoutVariables = $('#fixedLayoutVariables');
+               function useFluidLayout() {
+                       if ($useFluidLayout.is(':checked')) {
+                               $fluidLayoutVariables.show();
+                               $fixedLayoutVariables.hide();
+                       }
+                       else {
+                               $fluidLayoutVariables.hide();
+                               $fixedLayoutVariables.show();
+                       }
+               }
+               $useFluidLayout.change(useFluidLayout);
+               useFluidLayout();
+               
+               WCF.Language.addObject({
+                       'wcf.global.button.upload': '{lang}wcf.global.button.upload{/lang}'
+               });
+               new WCF.ACP.Style.ImageUpload(0, '{$tmpHash}');
+               
+               {if $action == 'edit' && $__wcf->getSession()->getPermission('admin.style.canAddStyle')}
+                       new WCF.ACP.Style.CopyStyle({@$style->styleID});
+                       
+                       WCF.Language.addObject({
+                               'wcf.acp.style.copyStyle.confirmMessage': '{lang}wcf.acp.style.copyStyle.confirmMessage{/lang}'
+                       });
+               {/if}
+       });
+       //]]>
+</script>
+<header class="boxHeadline">
+       <hgroup>
+               <h1>{lang}wcf.acp.style.{$action}{/lang}</h1>
+       </hgroup>
+</header>
+
+{if $errorField}
+       <p class="error">{lang}wcf.global.form.error{/lang}</p>
+{/if}
+
+{if $success|isset}
+       <p class="success">{lang}wcf.global.form.{$action}.success{/lang}</p>   
+{/if}
+
+{hascontent}
+       <div class="contentNavigation">
+               <nav>
+                       <ul>
+                               {content}
+                                       {if $action == 'edit'}
+                                               <li><a href="{link controller='StyleExport' id=$style->styleID}{/link}" class="button"><img src="{@$__wcf->getPath()}icon/download.svg" alt="" class="icon24" /> <span>{lang}wcf.acp.style.exportStyle{/lang}</span></a></li>
+                                               {if $__wcf->getSession()->getPermission('admin.style.canAddStyle')}<li><a class="jsCopyStyle button"><img src="{@$__wcf->getPath()}icon/add.svg" alt="" class="icon24" /> <span>{lang}wcf.acp.style.copyStyle{/lang}</span></a></li>{/if}
+                                       {/if}
+                                       
+                                       {if $__wcf->session->getPermission('admin.style.canDeleteStyle') || $__wcf->session->getPermission('admin.style.canEditStyle')}
+                                               <li><a href="{link controller='StyleList'}{/link}" title="{lang}wcf.acp.menu.link.style.list{/lang}" class="button"><img src="{@$__wcf->getPath()}icon/list.svg" alt="" class="icon24" /> <span>{lang}wcf.acp.menu.link.style.list{/lang}</span></a></li>
+                                       {/if}
+                               {/content}
+                       </ul>
+               </nav>
+       </div>
+{/hascontent}
+
+<form method="post" action="{if $action == 'add'}{link controller='StyleAdd'}{/link}{else}{link controller='StyleEdit' id=$styleID}{/link}{/if}">
+       <div class="tabMenuContainer" data-active="{$activeTabMenuItem}" data-store="activeTabMenuItem">
+               <nav class="tabMenu">
+                       <ul>
+                               <li><a href="{@$__wcf->getAnchor('general')}">{lang}wcf.acp.style.general{/lang}</a></li>
+                               <li><a href="{@$__wcf->getAnchor('globals')}">{lang}wcf.acp.style.globals{/lang}</a></li>
+                               <li><a href="{@$__wcf->getAnchor('colors')}">{lang}wcf.acp.style.colors{/lang}</a></li>
+                               <li><a href="{@$__wcf->getAnchor('advanced')}">{lang}wcf.acp.style.advanced{/lang}</a></li>
+                       </ul>
+               </nav>
+               
+               {* general *}
+               <div id="general" class="container containerPadding tabMenuContainer tabMenuContent">
+                       <fieldset>
+                               <legend>{lang}wcf.acp.style.general.data{/lang}</legend>
+                               
+                               <dl{if $errorField == 'styleName'} class="formError"{/if}>
+                                       <dt><label for="styleName">{lang}wcf.acp.style.styleName{/lang}</label></dt>
+                                       <dd>
+                                               <input type="text" name="styleName" id="styleName" value="{$styleName}" class="long" />
+                                               {if $errorField == 'styleName'}
+                                                       <small class="innerError">
+                                                               {if $errorType == 'empty'}
+                                                                       {lang}wcf.global.form.error.empty{/lang}
+                                                               {else}
+                                                                       {lang}wcf.acp.style.error.styleName.{$errorType}{/lang}
+                                                               {/if}
+                                                       </small>
+                                               {/if}
+                                       </dd>
+                               </dl>
+                               <dl{if $errorField == 'authorName'} class="formError"{/if}>
+                                       <dt><label for="authorName">{lang}wcf.acp.style.authorName{/lang}</label></dt>
+                                       <dd>
+                                               <input type="text" name="authorName" id="authorName" value="{$authorName}" class="long" />
+                                               {if $errorField == 'authorName'}
+                                                       <small class="innerError">
+                                                               {if $errorType == 'empty'}
+                                                                       {lang}wcf.global.form.error.empty{/lang}
+                                                               {else}
+                                                                       {lang}wcf.acp.style.error.authorName.{$errorType}{/lang}
+                                                               {/if}
+                                                       </small>
+                                               {/if}
+                                       </dd>
+                               </dl>
+                               <dl{if $errorField == 'copyright'} class="formError"{/if}>
+                                       <dt><label for="copyright">{lang}wcf.acp.style.copyright{/lang}</label></dt>
+                                       <dd>
+                                               <input type="text" name="copyright" id="copyright" value="{$copyright}" class="long" />
+                                               {if $errorField == 'copyright'}
+                                                       <small class="innerError">
+                                                               {if $errorType == 'empty'}
+                                                                       {lang}wcf.global.form.error.empty{/lang}
+                                                               {else}
+                                                                       {lang}wcf.acp.style.error.copyright.{$errorType}{/lang}
+                                                               {/if}
+                                                       </small>
+                                               {/if}
+                                       </dd>
+                               </dl>
+                               <dl{if $errorField == 'styleVersion'} class="formError"{/if}>
+                                       <dt><label for="styleVersion">{lang}wcf.acp.style.styleVersion{/lang}</label></dt>
+                                       <dd>
+                                               <input type="text" name="styleVersion" id="styleVersion" value="{$styleVersion}" class="small" />
+                                               {if $errorField == 'styleVersion'}
+                                                       <small class="innerError">
+                                                               {if $errorType == 'empty'}
+                                                                       {lang}wcf.global.form.error.empty{/lang}
+                                                               {else}
+                                                                       {lang}wcf.acp.style.error.styleVersion.{$errorType}{/lang}
+                                                               {/if}
+                                                       </small>
+                                               {/if}
+                                       </dd>
+                               </dl>
+                               <dl{if $errorField == 'styleDate'} class="formError"{/if}>
+                                       <dt><label for="styleDate">{lang}wcf.acp.style.styleDate{/lang}</label></dt>
+                                       <dd>
+                                               <input type="date" name="styleDate" id="styleDate" value="{$styleDate}" class="small" />
+                                               {if $errorField == 'styleDate'}
+                                                       <small class="innerError">
+                                                               {if $errorType == 'empty'}
+                                                                       {lang}wcf.global.form.error.empty{/lang}
+                                                               {else}
+                                                                       {lang}wcf.acp.style.error.styleDate.{$errorType}{/lang}
+                                                               {/if}
+                                                       </small>
+                                               {/if}
+                                       </dd>
+                               </dl>
+                               <dl{if $errorField == 'license'} class="formError"{/if}>
+                                       <dt><label for="license">{lang}wcf.acp.style.license{/lang}</label></dt>
+                                       <dd>
+                                               <input type="text" name="license" id="license" value="{$license}" class="long" />
+                                               {if $errorField == 'license'}
+                                                       <small class="innerError">
+                                                               {if $errorType == 'empty'}
+                                                                       {lang}wcf.global.form.error.empty{/lang}
+                                                               {else}
+                                                                       {lang}wcf.acp.style.error.license.{$errorType}{/lang}
+                                                               {/if}
+                                                       </small>
+                                               {/if}
+                                       </dd>
+                               </dl>
+                               <dl{if $errorField == 'authorURL'} class="formError"{/if}>
+                                       <dt><label for="authorURL">{lang}wcf.acp.style.authorURL{/lang}</label></dt>
+                                       <dd>
+                                               <input type="text" name="authorURL" id="authorURL" value="{$authorURL}" class="long" />
+                                               {if $errorField == 'authorURL'}
+                                                       <small class="innerError">
+                                                               {if $errorType == 'empty'}
+                                                                       {lang}wcf.global.form.error.empty{/lang}
+                                                               {else}
+                                                                       {lang}wcf.acp.style.error.authorURL.{$errorType}{/lang}
+                                                               {/if}
+                                                       </small>
+                                               {/if}
+                                       </dd>
+                               </dl>
+                               <dl{if $errorField == 'styleDescription'} class="formError"{/if}>
+                                       <dt><label for="styleDescription">{lang}wcf.acp.style.styleDescription{/lang}</label></dt>
+                                       <dd>
+                                               <textarea name="styleDescription" id="styleDescription">{$styleDescription}</textarea>
+                                               {if $errorField == 'styleDescription'}
+                                                       <small class="innerError">
+                                                               {if $errorType == 'empty'}
+                                                                       {lang}wcf.global.form.error.empty{/lang}
+                                                               {else}
+                                                                       {lang}wcf.acp.style.error.styleDescription.{$errorType}{/lang}
+                                                               {/if}
+                                                       </small>
+                                               {/if}
+                                       </dd>
+                               </dl>
+                       </fieldset>
+                       
+                       <fieldset>
+                               <legend>{lang}wcf.acp.style.general.files{/lang}</legend>
+                               
+                               <dl{if $errorField == 'image'} class="formError"{/if}>
+                                       <dt><label for="image">{lang}wcf.acp.style.image{/lang}</label></dt>
+                                       <dd class="framed">
+                                               <img src="{if $action == 'add'}{@$__wcf->getPath()}images/stylePreview.png{else}{@$style->getPreviewImage()}{/if}" alt="" id="styleImage" />
+                                               <div id="uploadImage"></div>
+                                               {if $errorField == 'image'}
+                                                       <small class="innerError">
+                                                               {if $errorType == 'empty'}
+                                                                       {lang}wcf.global.form.error.empty{/lang}
+                                                               {else}
+                                                                       {lang}wcf.acp.style.error.image.{$errorType}{/lang}
+                                                               {/if}
+                                                       </small>
+                                               {/if}
+                                               <small>{lang}wcf.acp.style.image.description{/lang}</small>
+                                       </dd>
+                               </dl>
+                               {hascontent}
+                                       <dl{if $errorField == 'templateGroupID'} class="formError"{/if}>
+                                               <dt><label for="templateGroupID">{lang}wcf.acp.style.templateGroupID{/lang}</label></dt>
+                                               <dd>
+                                                       <select name="templateGroupID" id="templateGroupID">
+                                                               <option value="0"></option>
+                                                               {content}
+                                                                       {foreach from=$availableTemplateGroups item=templateGroup}
+                                                                               <option value="{@$templateGroup->templateGroupID}">{$templateGroup->templateGroupName}</option>
+                                                                       {/foreach}
+                                                               {/content}
+                                                       </select>
+                                                       {if $errorField == 'templateGroupID'}
+                                                               <small class="innerError">
+                                                                       {if $errorType == 'empty'}
+                                                                               {lang}wcf.global.form.error.empty{/lang}
+                                                                       {else}
+                                                                               {lang}wcf.acp.style.error.templateGroupID.{$errorType}{/lang}
+                                                                       {/if}
+                                                               </small>
+                                                       {/if}
+                                               </dd>
+                                       </dl>
+                               {/hascontent}
+                               <dl{if $errorField == 'iconPath'} class="formError"{/if}>
+                                       <dt><label for="iconPath">{lang}wcf.acp.style.iconPath{/lang}</label></dt>
+                                       <dd>
+                                               <input type="text" name="iconPath" id="iconPath" value="{$iconPath}" class="long" />
+                                               {if $errorField == 'iconPath'}
+                                                       <small class="innerError">
+                                                               {if $errorType == 'empty'}
+                                                                       {lang}wcf.global.form.error.empty{/lang}
+                                                               {else}
+                                                                       {lang}wcf.acp.style.error.iconPath.{$errorType}{/lang}
+                                                               {/if}
+                                                       </small>
+                                               {/if}
+                                               <small>{lang}wcf.acp.style.iconPath.description{/lang}</small>
+                                       </dd>
+                               </dl>
+                               <dl{if $errorField == 'imagePath'} class="formError"{/if}>
+                                       <dt><label for="imagePath">{lang}wcf.acp.style.imagePath{/lang}</label></dt>
+                                       <dd>
+                                               <input type="text" name="imagePath" id="imagePath" value="{$imagePath}" class="long" />
+                                               {if $errorField == 'imagePath'}
+                                                       <small class="innerError">
+                                                               {if $errorType == 'empty'}
+                                                                       {lang}wcf.global.form.error.empty{/lang}
+                                                               {else}
+                                                                       {lang}wcf.acp.style.error.imagePath.{$errorType}{/lang}
+                                                               {/if}
+                                                       </small>
+                                               {/if}
+                                               <small>{lang}wcf.acp.style.imagePath.description{/lang}</small>
+                                       </dd>
+                               </dl>
+                       </fieldset>
+               </div>
+               
+               {* globals *}
+               <div id="globals" class="container containerPadding tabMenuContainer tabMenuContent">
+                       {* layout *}
+                       <fieldset>
+                               <legend>{lang}wcf.acp.style.globals.layout{/lang}</legend>
+                               
+                               <dl>
+                                       <dd><label>
+                                               <input type="checkbox" id="useFluidLayout" name="useFluidLayout" value="1"{if $variables[useFluidLayout]} checked="checked"{/if} />
+                                               <span>{lang}wcf.acp.style.globals.useFluidLayout{/lang}</span>
+                                       </label></dd>
+                               </dl>
+                               <div id="fluidLayoutVariables">
+                                       <dl>
+                                               <dt><label for="wcfLayoutFluidGap">{lang}wcf.acp.style.globals.fluidLayoutGap{/lang}</label></dt>
+                                               <dd>
+                                                       <input type="number" id="wcfLayoutFluidGap" name="wcfLayoutFluidGap" value="{@$variables[wcfLayoutFluidGap]}" class="tiny" />
+                                                       <select name="wcfLayoutFluidGap_unit">
+                                                               {foreach from=$availableUnits item=unit}
+                                                                       <option value="{@$unit}"{if $variables[wcfLayoutFluidGap_unit] == $unit} selected="selected"{/if}>{@$unit}</option>
+                                                               {/foreach}
+                                                       </select>
+                                               </dd>
+                                       </dl>
+                               </div>
+                               <div id="fixedLayoutVariables">
+                                       <dl>
+                                               <dt><label for="wcfLayoutFixedWidth">{lang}wcf.acp.style.globals.fixedLayoutWidth{/lang}</label></dt>
+                                               <dd>
+                                                       <input type="number" id="wcfLayoutFixedWidth" name="wcfLayoutFixedWidth" value="{@$variables[wcfLayoutFixedWidth]}" class="tiny" />
+                                                       <select name="wcfLayoutFixedWidth_unit">
+                                                               {foreach from=$availableUnits item=unit}
+                                                                       <option value="{@$unit}"{if $variables[wcfLayoutFixedWidth_unit] == $unit} selected="selected"{/if}>{@$unit}</option>
+                                                               {/foreach}
+                                                       </select>
+                                               </dd>
+                                       </dl>
+                               </div>
+                               <dl>
+                                       <dt><label for="pageLogo">{lang}wcf.acp.style.globals.pageLogo{/lang}</label></dt>
+                                       <dd>
+                                               <input type="text" name="pageLogo" id="pageLogo" value="{$variables[pageLogo]}" class="long" />
+                                               <small>{lang}wcf.acp.style.globals.pageLogo.description{/lang}</small>
+                                       </dd>
+                               </dl>
+                       </fieldset>
+                       
+                       {* font *}
+                       <fieldset>
+                               <legend>{lang}wcf.acp.style.globals.font{/lang}</legend>
+                               
+                               <dl>
+                                       <dt><label for="wcfBaseFontSize">{lang}wcf.acp.style.globals.fontSize{/lang}</label></dt>
+                                       <dd>
+                                               <input type="number" id="wcfBaseFontSize" name="wcfBaseFontSize" value="{@$variables[wcfBaseFontSize]}" class="tiny" />
+                                               <select name="wcfBaseFontSize_unit">
+                                                       {foreach from=$availableUnits item=unit}
+                                                               <option value="{@$unit}"{if $variables[wcfBaseFontSize_unit] == $unit} selected="selected"{/if}>{@$unit}</option>
+                                                       {/foreach}
+                                               </select>
+                                       </dd>
+                               </dl>
+                               <dl>
+                                       <dt><label for="wcfBaseFontFamily">{lang}wcf.acp.style.globals.fontFamily{/lang}</label></dt>
+                                       <dd>
+                                               <select name="wcfBaseFontFamily" id="wcfBaseFontFamily">
+                                                       {foreach from=$availableFontFamilies key=fontFamily item=primaryFont}
+                                                               <option value='{@$fontFamily}'{if $variables[wcfBaseFontFamily] == $fontFamily} selected="selected"{/if}>{@$primaryFont}</option>
+                                                       {/foreach}
+                                               </select>
+                                       </dd>
+                               </dl>
+                       </fieldset>
+               </div>
+               
+               {* colors *}
+               <div id="colors" class="container containerPadding tabMenuContainer tabMenuContent">
+                       <fieldset>
+                               <legend>{lang}wcf.acp.style.colors.page{/lang}</legend>
+                               
+                               {* page *}
+                               <ul class="colorList">
+                                       <li>{include file='styleVariableColor' variableName='wcfPageBackgroundColor' languageVariable='backgroundColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfPageColor' languageVariable='color'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfPageLinkColor' languageVariable='linkColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfPageLinkHoverColor' languageVariable='linkHoverColor'}</li>
+                               </ul>
+                       </fieldset>
+                       
+                       <fieldset>
+                               <legend>{lang}wcf.acp.style.colors.content{/lang}</legend>
+                               
+                               {* content *}
+                               <ul class="colorList">
+                                       <li>{include file='styleVariableColor' variableName='wcfContentBackgroundColor' languageVariable='backgroundColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfColor' languageVariable='color'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfDimmedColor' languageVariable='dimmedColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfLinkColor' languageVariable='linkColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfLinkHoverColor' languageVariable='linkHoverColor'}</li>
+                               </ul>
+                       </fieldset>
+                       
+                       <fieldset>
+                               <legend>{lang}wcf.acp.style.colors.container{/lang}</legend>
+                               
+                               {* general *}
+                               <ul class="colorList">
+                                       <li>{include file='styleVariableColor' variableName='wcfContainerBackgroundColor' languageVariable='backgroundColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfContainerAccentBackgroundColor' languageVariable='accentBackgroundColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfContainerBorderColor' languageVariable='borderColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfContainerHoverBackgroundColor' languageVariable='hoverBackgroundColor'}</li>
+                               </ul>
+                       </fieldset>
+                       
+                       <fieldset>
+                               <legend>{lang}wcf.acp.style.colors.userPanel{/lang}</legend>
+                               
+                               {* user panel *}
+                               <ul class="colorList">
+                                       <li>{include file='styleVariableColor' variableName='wcfUserPanelBackgroundColor' languageVariable='backgroundColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfUserPanelColor' languageVariable='color'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfUserPanelHoverBackgroundColor' languageVariable='hoverBackgroundColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfUserPanelHoverColor' languageVariable='hoverColor'}</li>
+                               </ul>
+                       </fieldset>
+                       
+                       <fieldset>
+                               <legend>{lang}wcf.acp.style.colors.tabular{/lang}</legend>
+                               
+                               {* general *}
+                               <ul class="colorList">
+                                       <li>{include file='styleVariableColor' variableName='wcfTabularBoxBackgroundColor' languageVariable='backgroundColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfTabularBoxColor' languageVariable='color'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfTabularBoxHoverColor' languageVariable='hoverColor'}</li>
+                               </ul>
+                       </fieldset>
+                       
+                       <fieldset>
+                               <legend>{lang}wcf.acp.style.colors.buttons{/lang}</legend>
+                               
+                               {* default button *}
+                               <ul class="colorList">
+                                       <li>{include file='styleVariableColor' variableName='wcfButtonBackgroundColor' languageVariable='backgroundColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfButtonBorderColor' languageVariable='borderColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfButtonColor' languageVariable='color'}</li>
+                               </ul>
+                               
+                               {* button:hover *}
+                               <ul class="colorList">
+                                       <li>{include file='styleVariableColor' variableName='wcfButtonHoverBackgroundColor' languageVariable='hoverBackgroundColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfButtonHoverBorderColor' languageVariable='hoverBorderColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfButtonHoverColor' languageVariable='hoverColor'}</li>
+                               </ul>
+                               
+                               {* primary button *}
+                               <ul class="colorList">
+                                       <li>{include file='styleVariableColor' variableName='wcfButtonPrimaryBackgroundColor' languageVariable='primaryBackgroundColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfButtonPrimaryBorderColor' languageVariable='primaryBorderColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfButtonPrimaryColor' languageVariable='primaryColor'}</li>
+                               </ul>
+                       </fieldset>
+                       
+                       <fieldset>
+                               <legend>{lang}wcf.acp.style.colors.formInput{/lang}</legend>
+                               
+                               {* default button *}
+                               <ul class="colorList">
+                                       <li>{include file='styleVariableColor' variableName='wcfInputBackgroundColor' languageVariable='backgroundColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfInputBorderColor' languageVariable='borderColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfInputColor' languageVariable='color'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfInputHoverBackgroundColor' languageVariable='hoverBackgroundColor'}</li>
+                                       <li>{include file='styleVariableColor' variableName='wcfInputHoverBorderColor' languageVariable='hoverBorderColor'}</li>
+                               </ul>
+                       </fieldset>
+               </div>
+               
+               {* advanced *}
+               <div id="advanced" class="container containerPadding tabMenuContainer tabMenuContent">
+                       <p class="info">{lang}wcf.acp.style.advanced.syntax{/lang}</p>
+                       
+                       <fieldset class="marginTop">
+                               <legend>{lang}wcf.acp.style.advanced.individualLess{/lang}</legend>
+                               
+                               <textarea rows="20" cols="40" name="individualLess">{$variables[individualLess]}</textarea>
+                               <small>{lang}wcf.acp.style.advanced.individualLess.description{/lang}</small>
+                       </fieldset>
+                       
+                       <fieldset{if $errorField == 'overrideLess'} class="formError"{/if}>
+                               <legend>{lang}wcf.acp.style.advanced.overrideLess{/lang}</legend>
+                               
+                               <p class="warning">{lang}wcf.acp.style.advanced.overrideLess.warning{/lang}</p>
+                               
+                               <textarea rows="20" cols="40" name="overrideLess" class="marginTop">{$variables[overrideLess]}</textarea>
+                               {if $errorField == 'overrideLess'}
+                                       <small class="innerError">
+                                               {lang}wcf.acp.style.advanced.overrideLess.error{/lang}
+                                               {implode from=$errorType item=error}{lang}wcf.acp.style.advanced.overrideLess.error.{$error.error}{/lang}{/implode}
+                                       </small>
+                               {/if}
+                               <small>{lang}wcf.acp.style.advanced.overrideLess.description{/lang}</small>
+                       </fieldset>
+               </div>
+       </div>
+       
+       <div class="formSubmit">
+               <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s" />
+               <input type="hidden" name="tmpHash" value="{$tmpHash}" />
+       </div>
+</form>
+
+{include file='footer'}
\ No newline at end of file
diff --git a/wcfsetup/install/files/acp/templates/styleExport.tpl b/wcfsetup/install/files/acp/templates/styleExport.tpl
new file mode 100644 (file)
index 0000000..897665f
--- /dev/null
@@ -0,0 +1,75 @@
+{include file='header' pageTitle='wcf.acp.style.exportStyle'}
+
+<header class="boxHeadline">
+       <hgroup>
+               <h1>{lang}wcf.acp.style.exportStyle{/lang}</h1>
+       </hgroup>
+</header>
+
+<div class="contentNavigation">
+       <nav>
+               <ul>
+                       <li><a href="{link controller='StyleList'}{/link}" title="{lang}wcf.acp.menu.link.style.list{/lang}" class="button"><img src="{@$__wcf->getPath()}icon/list.svg" alt="" class="icon24" /> <span>{lang}wcf.acp.menu.link.style.list{/lang}</span></a></li>
+               </ul>
+       </nav>
+</div>
+
+<form method="post" action="{link controller='StyleExport' id=$styleID}{/link}">
+       <div class="container containerPadding marginTop">
+               <fieldset>
+                       <legend>{lang}wcf.acp.style.exportStyle.components{/lang}</legend>
+                       <small>{lang}wcf.acp.style.exportStyle.components.description{/lang}</small>
+                       
+                       <dl>
+                               <dd>
+                                       <label><input type="checkbox" name="exportIcons" value="1"{if $exportIcons} checked="checked"{/if}{if !$canExportIcons} disabled="disabled"{/if} /> <span>{lang}wcf.acp.style.exportIcons{/lang}</span></label>
+                               </dd>
+                       </dl>
+                       <dl>
+                               <dd>
+                                       <label><input type="checkbox" name="exportImages" value="1"{if $exportImages} checked="checked"{/if}{if !$canExportImages} disabled="disabled"{/if} /> <span>{lang}wcf.acp.style.exportImages{/lang}</span></label>
+                               </dd>
+                       </dl>
+                       <dl>
+                               <dd>
+                                       <label><input type="checkbox" name="exportTemplates" value="1"{if $exportTemplates} checked="checked"{/if}{if !$canExportTemplates} disabled="disabled"{/if} /> <span>{lang}wcf.acp.style.exportTemplates{/lang}</span></label>
+                               </dd>
+                       </dl>
+               </fieldset>
+               
+               <fieldset>
+                       <legend>{lang}wcf.acp.style.exportStyle.asPackage{/lang}</legend>
+                       <small>{lang}wcf.acp.style.exportStyle.asPackage.description{/lang}</small>
+                       
+                       <dl>
+                               <dd>
+                                       <label><input type="checkbox" name="exportAsPackage" value="1"{if $exportAsPackage} checked="checked"{/if} /> <span>{lang}wcf.acp.style.exportAsPackage{/lang}</span></label>
+                               </dd>
+                       </dl>
+                       <dl{if $errorField == 'packageName'} class="formError"{/if}>
+                               <dt>
+                                       <label for="packageName">{lang}wcf.acp.style.packageName{/lang}</label>
+                               </dt>
+                               <dd>
+                                       <input type="text" name="packageName" id="packageName" class="long" value="{$packageName}" />
+                                       {if $errorField == 'packageName'}
+                                               <small class="innerError">
+                                                       {if $errorType == 'empty'}
+                                                               {lang}wcf.global.form.error.empty{/lang}
+                                                       {else}
+                                                               {lang}wcf.acp.style.packageName.error.{$errorType}{/lang}
+                                                       {/if}
+                                               </small>
+                                       {/if}
+                                       <small>{lang}wcf.acp.style.packageName.description{/lang}</small>
+                               </dd>
+                       </dl>
+               </fieldset>
+       </div>
+       
+       <div class="formSubmit">
+               <input type="submit" value="{lang}wcf.acp.style.button.exportStyle{/lang}" accesskey="s" />
+       </div>
+</form>
+
+{include file='footer'}
\ No newline at end of file
diff --git a/wcfsetup/install/files/acp/templates/styleImport.tpl b/wcfsetup/install/files/acp/templates/styleImport.tpl
new file mode 100644 (file)
index 0000000..c1e034b
--- /dev/null
@@ -0,0 +1,60 @@
+{include file='header' pageTitle='wcf.acp.style.importStyle'}
+
+<header class="boxHeadline">
+       <hgroup>
+               <h1>{lang}wcf.acp.style.importStyle{/lang}</h1>
+       </hgroup>
+</header>
+
+{if $success|isset}
+       <p class="success">{lang}wcf.global.form.add.success{/lang}</p> 
+{/if}
+
+{hascontent}
+       <div class="contentNavigation">
+               <nav>
+                       <ul>
+                               {content}
+                                       {if $__wcf->session->getPermission('admin.style.canDeleteStyle') || $__wcf->session->getPermission('admin.style.canEditStyle')}
+                                               <li><a href="{link controller='StyleList'}{/link}" title="{lang}wcf.acp.menu.link.style.list{/lang}" class="button"><img src="{@$__wcf->getPath()}icon/list.svg" alt="" class="icon24" /> <span>{lang}wcf.acp.menu.link.style.list{/lang}</span></a></li>
+                                       {/if}
+                               {/content}
+                       </ul>
+               </nav>
+       </div>
+{/hascontent}
+
+<form method="post" action="{link controller='StyleImport'}{/link}" enctype="multipart/form-data">
+       <div class="container containerPadding marginTop">
+               <fieldset>
+                       <legend>{lang}wcf.acp.style.import.source{/lang}</legend>
+                       
+                       <dl{if $errorField == 'source'} class="formError"{/if}>
+                               <dt><label for="source">{lang}wcf.acp.style.import.source.upload{/lang}</label></dt>
+                               <dd>
+                                       <input type="file" id="source" name="source" value="" />
+                                       {if $errorField == 'source'}
+                                               <small class="innerError">
+                                                       {if $errorType == 'empty'}
+                                                               {lang}wcf.global.form.error.empty{/lang}
+                                                       {else}
+                                                               {lang}wcf.acp.style.import.source.error.{@$errorType}{/lang}
+                                                       {/if}
+                                               </small>
+                                       {/if}
+                                       <small>{lang}wcf.acp.style.import.source.upload.description{/lang}</small>
+                               </dd>
+                       </dl>
+                       
+                       {event name='sourceFields'}
+               </fieldset>
+               
+               {event name='fieldsets'}
+       </div>
+       
+       <div class="formSubmit">
+               <input type="submit" name="submitButton" value="{lang}wcf.global.button.submit{/lang}" accesskey="s" />
+       </div>
+</form>
+
+{include file='footer'}
\ No newline at end of file
diff --git a/wcfsetup/install/files/acp/templates/styleList.tpl b/wcfsetup/install/files/acp/templates/styleList.tpl
new file mode 100644 (file)
index 0000000..064436d
--- /dev/null
@@ -0,0 +1,95 @@
+{include file='header' pageTitle='wcf.acp.style.list'}
+
+<script type="text/javascript" src="{@$__wcf->getPath()}acp/js/WCF.ACP.Style.js"></script>
+<script type="text/javascript">
+       //<![CDATA[
+       $(function() {
+               new WCF.Action.Toggle('wcf\\data\\style\\StyleAction', $('.buttonList'));
+               new WCF.ACP.Style.List();
+       });
+       //]]>
+</script>
+
+<header class="boxHeadline">
+       <hgroup>
+               <h1>{lang}wcf.acp.style.list{/lang}</h1>
+       </hgroup>
+</header>
+
+<div class="contentNavigation">
+       {pages print=true assign=pagesLinks controller="StyleList" link="pageNo=%d"}
+       
+       {hascontent}
+               <nav>
+                       <ul>
+                               {content}
+                                       {if $__wcf->session->getPermission('admin.style.canAddStyle')}
+                                               <li><a href="{link controller='StyleAdd'}{/link}" title="{lang}wcf.acp.menu.link.style.add{/lang}" class="button"><img src="{@$__wcf->getPath()}icon/add.svg" alt="" class="icon24" /> <span>{lang}wcf.acp.menu.link.style.add{/lang}</span></a></li>
+                                               <li><a href="{link controller='StyleImport'}{/link}" title="{lang}wcf.acp.menu.link.style.import{/lang}" class="button"><img src="{@$__wcf->getPath()}icon/upload.svg" alt="" class="icon24" /> <span>{lang}wcf.acp.menu.link.style.import{/lang}</span></a></li>
+                                       {/if}
+                                       
+                                       {event name='largeButtons'}
+                               {/content}
+                       </ul>
+               </nav>
+       {/hascontent}
+</div>
+
+<div class="container marginTop">
+       <ol class="containerList styleList">
+               {foreach from=$objects item=style}
+                       <li>
+                               <div class="box64">
+                                       <span class="framed"><img src="{@$style->getPreviewImage()}" alt="" /></span>
+                                       <div class="details">
+                                               <hgroup class="containerHeadline">
+                                                       <h1><a href="{link controller='StyleEdit' id=$style->styleID}{/link}">{$style->styleName}</a></h1>
+                                                       {if $style->styleDescription}<h2>{$style->styleDescription}</h2>{/if}
+                                               </hgroup>
+                                               <ul class="buttonList" data-style-id="{@$style->styleID}">
+                                                       <li><a href="{link controller='StyleEdit' id=$style->styleID}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip"><img src="{@$__wcf->getPath()}icon/edit.svg" class="icon16" alt="" /></a></li>
+                                                       {if !$style->isDefault}
+                                                               <li><img src="{@$__wcf->getPath()}icon/{if $style->disabled}disabled{else}enabled{/if}.svg" title="{lang}wcf.global.button.{if $style->disabled}enable{else}disable{/if}{/lang}" alt="" class="icon16 jsToggleButton jsTooltip" data-object-id="{@$style->styleID}" /></li>
+                                                               <li><a title="{lang}wcf.acp.style.button.setAsDefault{/lang}" class="jsSetAsDefault jsTooltip"><img src="{@$__wcf->getPath()}icon/default.svg" class="icon16 jsTooltip" alt="" /></a></li>
+                                                               <li><a title="{lang}wcf.global.button.delete{/lang}" class="jsDelete jsTooltip" data-confirm-message="{lang}wcf.acp.style.delete.confirmMessage{/lang}"><img src="{@$__wcf->getPath()}icon/delete.svg" class="icon16" alt="" /></a></li>
+                                                       {/if}
+                                               </ul>
+                                               <dl class="plain inlineDataList">
+                                                       <dt>{lang}wcf.acp.style.users{/lang}</dt>
+                                                       <dd>{#$style->users}</dd>
+                                               </dl>
+                                               <dl class="plain inlineDataList">
+                                                       <dt>{lang}wcf.acp.style.styleVersion{/lang}</dt>
+                                                       <dd>{$style->styleVersion} ({$style->styleDate})</dd>
+                                               </dl>
+                                               <dl class="plain inlineDataList">
+                                                       <dt>{lang}wcf.acp.style.authorName{/lang}</dt>
+                                                       <dd>{if $style->authorURL}<a href="{@$__wcf->getPath()}acp/dereferrer.php?url={$style->authorURL}">{$style->authorName}</a>{else}{$style->authorName}{/if}</dd>
+                                               </dl>
+                                       </div>
+                               </div>
+                       </li>
+               {/foreach}
+       </ol>
+</div>
+
+<div class="contentNavigation">
+       {@$pagesLinks}
+       
+       {hascontent}
+               <nav>
+                       <ul>
+                               {content}
+                                       {if $__wcf->session->getPermission('admin.style.canAddStyle')}
+                                               <li><a href="{link controller='StyleAdd'}{/link}" title="{lang}wcf.acp.menu.link.style.add{/lang}" class="button"><img src="{@$__wcf->getPath()}icon/add.svg" alt="" class="icon24" /> <span>{lang}wcf.acp.menu.link.style.add{/lang}</span></a></li>
+                                               <li><a href="{link controller='StyleImport'}{/link}" title="{lang}wcf.acp.menu.link.style.import{/lang}" class="button"><img src="{@$__wcf->getPath()}icon/upload.svg" alt="" class="icon24" /> <span>{lang}wcf.acp.menu.link.style.import{/lang}</span></a></li>
+                                       {/if}
+                                       
+                                       {event name='largeButtons'}
+                               {/content}
+                       </ul>
+               </nav>
+       {/hascontent}
+</div>
+
+{include file='footer'}
diff --git a/wcfsetup/install/files/acp/templates/styleVariableColor.tpl b/wcfsetup/install/files/acp/templates/styleVariableColor.tpl
new file mode 100644 (file)
index 0000000..beffc07
--- /dev/null
@@ -0,0 +1,5 @@
+<figure>
+       <figcaption>{lang}wcf.acp.style.colors.{$languageVariable}{/lang}</figcaption>
+       <div class="colorPreview"><div class="jsColorPicker jsToolTip" title="{$variableName}" style="background-color: {$variables[$variableName]}" data-color="{$variables[$variableName]}" data-store="{$variableName}_value"></div></div>
+       <input type="hidden" id="{$variableName}_value" name="{$variableName}" value="{$variables[$variableName]}" /> 
+</figure>
\ No newline at end of file
diff --git a/wcfsetup/install/files/acp/templates/styleVariableUnit.tpl b/wcfsetup/install/files/acp/templates/styleVariableUnit.tpl
new file mode 100644 (file)
index 0000000..e9c76b5
--- /dev/null
@@ -0,0 +1,12 @@
+<dl>
+       <dt><label for="{$variableName}">{lang}wcf.acp.style.variable.{$variableName}{/lang}</label></dt>
+       <dd>
+               <input type="number" name="{$variableName}" id="{$variableName}" value="{$variableValue}" />
+               <select name="{$variableName}_unit" id="{$variableName}_unit">
+                       <option value="%"{if $variableUnit == '%'} selected="selected"{/if}>%</option>
+                       <option value="em"{if $variableUnit == 'em'} selected="selected"{/if}>em</option>
+                       <option value="pt"{if $variableUnit == 'pt'} selected="selected"{/if}>pt</option>
+                       <option value="px"{if $variableUnit == 'px'} selected="selected"{/if}>px</option>
+               </select>
+       </dd>
+</dl>
\ No newline at end of file
diff --git a/wcfsetup/install/files/lib/acp/form/StyleAddForm.class.php b/wcfsetup/install/files/lib/acp/form/StyleAddForm.class.php
new file mode 100644 (file)
index 0000000..d4c1e00
--- /dev/null
@@ -0,0 +1,540 @@
+<?php
+namespace wcf\acp\form;
+use wcf\data\package\Package;
+use wcf\data\style\StyleAction;
+use wcf\data\template\group\TemplateGroupList;
+use wcf\system\event\EventHandler;
+use wcf\system\exception\SystemException;
+use wcf\system\exception\UserInputException;
+use wcf\system\Regex;
+use wcf\system\WCF;
+use wcf\util\DateUtil;
+use wcf\util\FileUtil;
+use wcf\util\StringUtil;
+
+/**
+ * Shows the style add form.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2013 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage acp.form
+ * @category   Community Framework
+ */
+class StyleAddForm extends ACPForm {
+       /**
+        * @see wcf\acp\form\ACPForm::$activeMenuItem
+        */
+       public $activeMenuItem = 'wcf.acp.menu.link.style.add';
+       
+       /**
+        * author's name
+        * @var string
+        */
+       public $authorName = '';
+       
+       /**
+        * author's URL
+        * @var string
+        */
+       public $authorURL = '';
+       
+       /**
+        * list of available font families
+        * @var array<string>
+        */
+       public $availableFontFamilies = array(
+               'Arial, Helvetica, sans-serif' => 'Arial',
+               'Chicago, Impact, Compacta, sans-serif' => 'Chicago',
+               '"Comic Sans MS", sans-serif' => 'Comic Sans',
+               '"Courier New", Courier, monospace' => 'Courier New',
+               'Geneva, Arial, Helvetica, sans-serif' => 'Geneva',
+               'Georgia, "Times New Roman", Times, serif' => 'Georgia',
+               'Helvetica, Verdana, sans-serif' => 'Helvetica',
+               'Impact, Compacta, Chicago, sans-serif' => 'Impact',
+               '"Lucida Sans", "Lucida Grande", Monaco, Geneva, sans-serif' => 'Lucida',
+               'Tahoma, Arial, Helvetica, sans-serif' => 'Tahoma',
+               '"Times New Roman", Times, Georgia, serif' => 'Times New Roman',
+               '"Trebuchet MS", Arial, sans-serif' => 'Trebuchet MS',
+               'Verdana, Helvetica, sans-serif' => 'Verdana'
+       );
+       
+       /**
+        * list of available template groups
+        * @var array<wcf\data\template\group\TemplateGroup>
+        */
+       public $availableTemplateGroups = array();
+       
+       /**
+        * list of available units
+        * @var array<string>
+        */
+       public $availableUnits = array('px', 'em', '%', 'pt');
+       
+       /**
+        * list of color variables
+        * @var array<string>
+        */
+       public $colors = array();
+       
+       /**
+        * copyright message
+        * @var string
+        */
+       public $copyright = '';
+       
+       /**
+        * font family
+        * @var string
+        */
+       public $fontFamily = '';
+       
+       /**
+        * list of global variables
+        * @var array
+        */
+       public $globals = array();
+       
+       /**
+        * icon path
+        * @var string
+        */
+       public $iconPath = 'icon/';
+       
+       /**
+        * image path
+        * @var string
+        */
+       public $imagePath = 'images/';
+       
+       /**
+        * license name
+        * @var string
+        */
+       public $license = '';
+       
+       /**
+        * @see wcf\page\AbstractPage::$neededPermissions
+        */
+       public $neededPermissions = array('admin.style.canAddStyle');
+       
+       /**
+        * last change date
+        * @var string
+        */
+       public $styleDate = '0000-00-00';
+       
+       /**
+        * description
+        * @var string
+        */
+       public $styleDescription = '';
+       
+       /**
+        * style name
+        * @var string
+        */
+       public $styleName = '';
+       
+       /**
+        * version number
+        * @var string
+        */
+       public $styleVersion = '';
+       
+       /**
+        * template group id
+        * @var integer
+        */
+       public $templateGroupID = 0;
+       
+       /**
+        * temporary image hash
+        * @var string
+        */
+       public $tmpHash = '';
+       
+       /**
+        * list of variables and their value
+        * @var array<string>
+        */
+       public $variables = array();
+       
+       /**
+        * list of specialized variables
+        * @var array<string>
+        */
+       public $specialVariables = array();
+       
+       /**
+        * @see wcf\page\IPage::readParameters()
+        */
+       public function readParameters() {
+               parent::readParameters();
+               
+               $this->setVariables();
+               $this->readStyleVariables();
+               
+               $templateGroupList = new TemplateGroupList();
+               $templateGroupList->sqlLimit = 0;
+               $templateGroupList->sqlOrderBy = "template_group.templateGroupName ASC";
+               $templateGroupList->readObjects();
+               $this->availableTemplateGroups = $templateGroupList->getObjects();
+               
+               if (isset($_REQUEST['tmpHash'])) {
+                       $this->tmpHash = StringUtil::trim($_REQUEST['tmpHash']);
+               }
+               if (empty($this->tmpHash)) {
+                       $this->tmpHash = StringUtil::getRandomID();
+               }
+       }
+       
+       /**
+        * @see wcf\form\IForm::readFormParameters()
+        */
+       public function readFormParameters() {
+               parent::readFormParameters();
+               
+               // ignore everything except well-formed rgba()
+               $regEx = new Regex('rgba\(\d{1,3}, \d{1,3}, \d{1,3}, (1|1\.00?|0|0?\.[0-9]{1,2})\)');
+               foreach ($this->colors as $variableName) {
+                       if (isset($_POST[$variableName]) && $regEx->match($_POST[$variableName])) {
+                               $this->variables[$variableName] = $_POST[$variableName];
+                       }
+               }
+               
+               // read variables with units, e.g. 13px
+               foreach ($this->globals as $variableName) {
+                       if (isset($_POST[$variableName]) && is_numeric($_POST[$variableName])) {
+                               if (isset($_POST[$variableName.'_unit']) && in_array($_POST[$variableName.'_unit'], $this->availableUnits)) { 
+                                       $this->variables[$variableName] = $_POST[$variableName].$_POST[$variableName.'_unit'];
+                               }
+                       }
+               }
+               
+               // read specialized variables
+               foreach ($this->specialVariables as $variableName) {
+                       if (isset($_POST[$variableName])) $this->variables[$variableName] = StringUtil::trim($_POST[$variableName]);
+               }
+               $this->variables['useFluidLayout'] = (isset($_POST['useFluidLayout'])) ? 1 : 0;
+               
+               // style data
+               if (isset($_POST['authorName'])) $this->authorName = StringUtil::trim($_POST['authorName']);
+               if (isset($_POST['authorURL'])) $this->authorURL = StringUtil::trim($_POST['authorURL']);
+               if (isset($_POST['copyright'])) $this->copyright = StringUtil::trim($_POST['copyright']);
+               if (isset($_POST['iconPath'])) $this->iconPath = StringUtil::trim($_POST['iconPath']);
+               if (isset($_POST['imagePath'])) $this->imagePath = StringUtil::trim($_POST['imagePath']);
+               if (isset($_POST['license'])) $this->license = StringUtil::trim($_POST['license']);
+               if (isset($_POST['styleDate'])) $this->styleDate = StringUtil::trim($_POST['styleDate']);
+               if (isset($_POST['styleDescription'])) $this->styleDescription = StringUtil::trim($_POST['styleDescription']);
+               if (isset($_POST['styleName'])) $this->styleName = StringUtil::trim($_POST['styleName']);
+               if (isset($_POST['styleVersion'])) $this->styleVersion = StringUtil::trim($_POST['styleVersion']);
+               if (isset($_POST['templateGroupID'])) $this->templateGroupID = intval($_POST['templateGroupID']);
+       }
+       
+       /**
+        * @see wcf\form\IForm::validate()
+        */
+       public function validate() {
+               parent::validate();
+               
+               if (empty($this->authorName)) {
+                       throw new UserInputException('authorName');
+               }
+               
+               if (empty($this->license)) {
+                       throw new UserInputException('license');
+               }
+               
+               // validate date
+               if (empty($this->styleDate)) {
+                       throw new UserInputException('styleDate');
+               }
+               else {
+                       try {
+                               DateUtil::validateDate($this->styleDate);
+                       }
+                       catch (SystemException $e) {
+                               throw new UserInputException('styleDate', 'notValid');
+                       }
+               }
+               
+               if (empty($this->styleName)) {
+                       throw new UserInputException('styleName');
+               }
+               
+               // validate version
+               if (empty($this->styleVersion)) {
+                       throw new UserInputException('styleVersion');
+               }
+               else if (!Package::isValidVersion($this->styleVersion)) {
+                       throw new UserInputException('styleVersion', 'notValid');
+               }
+               
+               // validate template group id
+               if ($this->templateGroupID) {
+                       if (!isset($this->availableTemplateGroups[$this->templateGroupID])) {
+                               throw new UserInputException('templateGroupID');
+                       }
+               }
+               
+               // ensure icon path is below WCF_DIR/icon/
+               if ($this->iconPath) {
+                       $relativePath = FileUtil::unifyDirSeperator(FileUtil::getRelativePath(WCF_DIR.'icon/', WCF_DIR.$this->iconPath));
+                       if (strpos($relativePath, '../') !== false) {
+                               throw new UserInputException('iconPath', 'notValid');
+                       }
+               }
+               
+               // ensure image path is below WCF_DIR/images/
+               if ($this->imagePath) {
+                       $relativePath = FileUtil::unifyDirSeperator(FileUtil::getRelativePath(WCF_DIR.'images/', WCF_DIR.$this->imagePath));
+                       if (strpos($relativePath, '../') !== false) {
+                               throw new UserInputException('imagePath', 'notValid');
+                       }
+               }
+               
+               if (!empty($this->variables['overrideLess'])) {
+                       $this->parseOverrides();
+               }
+       }
+       
+       /**
+        * Validates LESS-variable overrides.
+        * 
+        * If an override is invalid, unknown or matches a variable covered by
+        * the style editor itself, it will be silently discarded.
+        */
+       protected function parseOverrides() {
+               // get available variables
+               $sql = "SELECT  variableName
+                       FROM    wcf".WCF_N."_style_variable";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute();
+               $variables = array();
+               while ($row = $statement->fetchArray()) {
+                       $variables[] = $row['variableName'];
+               }
+               
+               $lines = explode("\n", StringUtil::unifyNewlines($this->variables['overrideLess']));
+               $regEx = new Regex('^@([a-zA-Z]+): ?([@a-zA-Z0-9 ,\.\(\)\%\#]+);$');
+               $errors = array();
+               foreach ($lines as $index => &$line) {
+                       $line = StringUtil::trim($line);
+                       
+                       // ignore empty lines
+                       if (empty($line)) {
+                               unset($lines[$index]);
+                               continue;
+                       }
+                       
+                       if ($regEx->match($line)) {
+                               $matches = $regEx->getMatches();
+                               
+                               // cannot override variables covered by style editor
+                               if (in_array($matches[1], $this->colors) || in_array($matches[1], $this->globals) || in_array($matches[1], $this->specialVariables)) {
+                                       $errors[] = array(
+                                               'error' => 'predefined',
+                                               'text' => $matches[1]
+                                       );
+                               }
+                               else if (!in_array($matches[1], $variables)) {
+                                       // unknown style variable
+                                       $errors[] = array(
+                                               'error' => 'unknown',
+                                               'text' => $matches[1]
+                                       );
+                               }
+                               else {
+                                       $this->variables[$matches[1]] = $matches[2];
+                               }
+                       }
+                       else {
+                               // not valid
+                               $errors[] = array(
+                                       'error' => 'notValid',
+                                       'text' => $line
+                               );
+                       }
+               }
+               
+               $this->variables['overrideLess'] = implode("\n", $lines);
+               
+               if (!empty($errors)) {
+                       throw new UserInputException('overrideLess', $errors);
+               }
+       }
+       
+       /**
+        * @see wcf\page\IPage::readData()
+        */
+       public function readData() {
+               parent::readData();
+               
+               // parse global (unit) variables
+               foreach ($this->globals as $variableName) {
+                       $unit = '';
+                       $value = $this->variables[$variableName];
+                       $i = strlen($value) - 1;
+                       while ($i >= 0) {
+                               $unit = $value[$i] . $unit;
+                               if (in_array($unit, $this->availableUnits)) {
+                                       $this->variables[$variableName] = str_replace($unit, '', $value);
+                                       $this->variables[$variableName.'_unit'] = $unit;
+                                       break;
+                               }
+                               
+                               $i--;
+                       }
+               }
+               
+               if (empty($_POST)) {
+                       $this->styleDate = date('Y-m-d', TIME_NOW);
+               }
+       }
+       
+       /**
+        * Sets available variables
+        */
+       protected function setVariables() {
+               // set color variables
+               $this->colors = array(
+                       'wcfButtonBackgroundColor',
+                       'wcfButtonBorderColor',
+                       'wcfButtonColor',
+                       'wcfButtonHoverBackgroundColor',
+                       'wcfButtonHoverBorderColor',
+                       'wcfButtonHoverColor',
+                       'wcfButtonPrimaryBackgroundColor',
+                       'wcfButtonPrimaryBorderColor',
+                       'wcfButtonPrimaryColor',
+                       'wcfColor',
+                       'wcfContainerAccentBackgroundColor',
+                       'wcfContainerBackgroundColor',
+                       'wcfContainerBorderColor',
+                       'wcfContainerHoverBackgroundColor',
+                       'wcfContentBackgroundColor',
+                       'wcfDimmedColor',
+                       'wcfInputBackgroundColor',
+                       'wcfInputBorderColor',
+                       'wcfInputColor',
+                       'wcfInputHoverBackgroundColor',
+                       'wcfInputHoverBorderColor',
+                       'wcfLinkColor',
+                       'wcfLinkHoverColor',
+                       'wcfPageBackgroundColor',
+                       'wcfPageColor',
+                       'wcfPageLinkColor',
+                       'wcfPageLinkHoverColor',
+                       'wcfTabularBoxBackgroundColor',
+                       'wcfTabularBoxColor',
+                       'wcfTabularBoxHoverColor',
+                       'wcfUserPanelBackgroundColor',
+                       'wcfUserPanelColor',
+                       'wcfUserPanelHoverBackgroundColor',
+                       'wcfUserPanelHoverColor',
+               );
+               
+               // set global variables
+               $this->globals = array(
+                       'wcfBaseFontSize',
+                       'wcfLayoutFixedWidth',
+                       'wcfLayoutFluidGap'
+               );
+               
+               // set specialized variables
+               $this->specialVariables = array(
+                       'individualLess',
+                       'overrideLess',
+                       'pageLogo',
+                       'useFluidLayout'
+               );
+               
+               EventHandler::getInstance()->fireAction($this, 'setVariables');
+       }
+       
+       /**
+        * Reads style variable values.
+        */
+       protected function readStyleVariables() {
+               $sql = "SELECT  variableName, defaultValue
+                       FROM    wcf".WCF_N."_style_variable";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute();
+               while ($row = $statement->fetchArray()) {
+                       $this->variables[$row['variableName']] = $row['defaultValue'];
+               }
+       }
+       
+       /**
+        * @see wcf\form\IForm::save()
+        */
+       public function save() {
+               parent::save();
+               
+               $this->objectAction = new StyleAction(array(), 'create', array(
+                       'data' => array(
+                               'styleName' => $this->styleName,
+                               'templateGroupID' => $this->templateGroupID,
+                               'disabled' => 1, // styles are disabled by default
+                               'styleDescription' => ($this->styleDescription ? $this->styleDescription : null),
+                               'styleVersion' => $this->styleVersion,
+                               'styleDate' => $this->styleDate,
+                               'imagePath' => $this->imagePath,
+                               'copyright' => $this->copyright,
+                               'license' => $this->license,
+                               'authorName' => $this->authorName,
+                               'authorURL' => $this->authorURL,
+                               'iconPath' => $this->iconPath
+                       ),
+                       'tmpHash' => $this->tmpHash,
+                       'variables' => $this->variables
+               ));
+               $this->objectAction->executeAction();
+               
+               // call saved event
+               $this->saved();
+               
+               // reset variables
+               $this->authorName = $this->authorURL = $this->copyright = $this->fontFamily = $this->image = '';
+               $this->license = $this->styleDate = $this->styleDescription = $this->styleName = $this->styleVersion = '';
+               
+               $this->iconPath = 'icon/';
+               $this->imagePath = 'images/';
+               $this->templateGroupID = 0;
+               
+               // reload variables
+               $this->readStyleVariables();
+               
+               WCF::getTPL()->assign('success', true);
+       }
+       
+       /**
+        * @see wcf\page\IPage::assignVariables()
+        */
+       public function assignVariables() {
+               parent::assignVariables();
+               
+               WCF::getTPL()->assign(array(
+                       'action' => 'add',
+                       'authorName' => $this->authorName,
+                       'authorURL' => $this->authorURL,
+                       'availableFontFamilies' => $this->availableFontFamilies,
+                       'availableTemplateGroups' => $this->availableTemplateGroups,
+                       'availableUnits' => $this->availableUnits,
+                       'copyright' => $this->copyright,
+                       'fontFamily' => $this->fontFamily,
+                       'iconPath' => $this->iconPath,
+                       'imagePath' => $this->imagePath,
+                       'license' => $this->license,
+                       'styleDate' => $this->styleDate,
+                       'styleDescription' => $this->styleDescription,
+                       'styleName' => $this->styleName,
+                       'styleVersion' => $this->styleVersion,
+                       'templateGroupID' => $this->templateGroupID,
+                       'tmpHash' => $this->tmpHash,
+                       'variables' => $this->variables
+               ));
+       }
+}
diff --git a/wcfsetup/install/files/lib/acp/form/StyleEditForm.class.php b/wcfsetup/install/files/lib/acp/form/StyleEditForm.class.php
new file mode 100644 (file)
index 0000000..8c0d8c2
--- /dev/null
@@ -0,0 +1,137 @@
+<?php
+namespace wcf\acp\form;
+use wcf\data\style\Style;
+use wcf\data\style\StyleAction;
+use wcf\form\AbstractForm;
+use wcf\system\exception\IllegalLinkException;
+use wcf\system\WCF;
+
+/**
+ * Shows the style edit form.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2013 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage acp.form
+ * @category   Community Framework
+ */
+class StyleEditForm extends StyleAddForm {
+       /**
+        * @see wcf\acp\form\ACPForm::$activeMenuItem
+        */
+       public $activeMenuItem = 'wcf.acp.menu.link.style';
+       
+       /**
+        * @see wcf\page\AbstractPage::$neededPermissions
+        */
+       public $neededPermissions = array('admin.style.canEditStyle');
+       
+       /**
+        * style object
+        * @var wcf\data\style\Style
+        */
+       public $style = null;
+       
+       /**
+        * style id
+        * @var integer
+        */
+       public $styleID = 0;
+       
+       /**
+        * @see wcf\page\IPage::readParameters()
+        */
+       public function readParameters() {
+               if (isset($_REQUEST['id'])) $this->styleID = intval($_REQUEST['id']);
+               $this->style = new Style($this->styleID);
+               if (!$this->style->styleID) {
+                       throw new IllegalLinkException();
+               }
+               
+               parent::readParameters();
+       }
+       
+       /**
+        * @see wcf\acp\form\StyleAddForm::readStyleVariables()
+        */
+       protected function readStyleVariables() {
+               $this->variables = $this->style->getVariables();
+               
+               // fix empty values ~""
+               foreach ($this->variables as &$variableValue) {
+                       if ($variableValue == '~""') {
+                               $variableValue = '';
+                       }
+               }
+               unset($variableValue);
+       }
+       
+       /**
+        * @see wcf\page\IPage::readData()
+        */
+       public function readData() {
+               parent::readData();
+               
+               if (empty($_POST)) {
+                       $this->authorName = $this->style->authorName;
+                       $this->authorURL = $this->style->authorURL;
+                       $this->copyright = $this->style->copyright;
+                       $this->iconPath = $this->style->iconPath;
+                       $this->imagePath = $this->style->imagePath;
+                       $this->license = $this->style->license;
+                       $this->styleDate = $this->style->styleDate;
+                       $this->styleDescription = $this->style->styleDescription;
+                       $this->styleName = $this->style->styleName;
+                       $this->styleVersion = $this->style->styleVersion;
+                       $this->templateGroupID = $this->style->templateGroupID;
+               }
+       }
+       
+       /**
+        * @see wcf\form\IForm::save()
+        */
+       public function save() {
+               AbstractForm::saved();
+               
+               $this->objectAction = new StyleAction(array($this->style), 'update', array(
+                       'data' => array(
+                               'styleName' => $this->styleName,
+                               'templateGroupID' => $this->templateGroupID,
+                               'styleDescription' => ($this->styleDescription ? $this->styleDescription : null),
+                               'styleVersion' => $this->styleVersion,
+                               'styleDate' => $this->styleDate,
+                               'imagePath' => $this->imagePath,
+                               'copyright' => $this->copyright,
+                               'license' => $this->license,
+                               'authorName' => $this->authorName,
+                               'authorURL' => $this->authorURL,
+                               'iconPath' => $this->iconPath
+                       ),
+                       'tmpHash' => $this->tmpHash,
+                       'variables' => $this->variables
+               ));
+               $this->objectAction->executeAction();
+               
+               // call saved event
+               $this->saved();
+               
+               // reload style object to update preview image
+               $this->style = new Style($this->style->styleID);
+               
+               WCF::getTPL()->assign('success', true);
+       }
+       
+       /**
+        * @see wcf\page\IPage::assignVariables()
+        */
+       public function assignVariables() {
+               parent::assignVariables();
+               
+               WCF::getTPL()->assign(array(
+                       'action' => 'edit',
+                       'style' => $this->style,
+                       'styleID' => $this->styleID
+               ));
+       }
+}
diff --git a/wcfsetup/install/files/lib/acp/form/StyleExportForm.class.php b/wcfsetup/install/files/lib/acp/form/StyleExportForm.class.php
new file mode 100644 (file)
index 0000000..b926217
--- /dev/null
@@ -0,0 +1,197 @@
+<?php
+namespace wcf\acp\form;
+use wcf\data\package\Package;
+use wcf\data\style\Style;
+use wcf\data\style\StyleEditor;
+use wcf\form\AbstractForm;
+use wcf\system\exception\IllegalLinkException;
+use wcf\system\exception\UserInputException;
+use wcf\system\WCF;
+use wcf\util\StringUtil;
+
+/**
+ * Shows the style export form.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2013 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage acp.form
+ * @category   Community Framework
+ */
+class StyleExportForm extends AbstractForm {
+       /**
+        * @see wcf\acp\form\ACPForm::$activeMenuItem
+        */
+       public $activeMenuItem = 'wcf.acp.menu.link.style';
+       
+       /**
+        * true, if style has custom icons
+        * @var boolean
+        */
+       public $canExportIcons = false;
+       
+       /**
+        * true, if style has custom images
+        * @var boolean
+        */
+       public $canExportImages = false;
+       
+       /**
+        * true, if style has custom templates
+        * @var boolean
+        */
+       public $canExportTemplates = false;
+       
+       /**
+        * export style as installable package
+        * @var boolean
+        */
+       public $exportAsPackage = false;
+       
+       /**
+        * true, if icons should be exported
+        * @var boolean
+        */
+       public $exportIcons = false;
+       
+       /**
+        * true, if images should be exported
+        * @var boolean
+        */
+       public $exportImages = false;
+       
+       /**
+        * true, if templates should be exported
+        * @var boolean
+        */
+       public $exportTemplates = false;
+       
+       /**
+        * @see wcf\page\AbstractPage::$neededPermissions
+        */
+       public $neededPermissions = array('admin.style.canEditStyle');
+       
+       /**
+        * package identifier
+        * @var string
+        */
+       public $packageName = '';
+       
+       /**
+        * style object
+        * @var wcf\data\style\Style
+        */
+       public $style = null;
+       
+       /**
+        * style id
+        * @var integer
+        */
+       public $styleID = 0;
+       
+       /**
+        * @see wcf\page\IPage::readParameters()
+        */
+       public function readParameters() {
+               parent::readParameters();
+               
+               if (isset($_REQUEST['id'])) $this->styleID = intval($_REQUEST['id']);
+               $this->style = new Style($this->styleID);
+               if (!$this->style->styleID) {
+                       throw new IllegalLinkException();
+               }
+               
+               if ($this->style->iconPath && $this->style->iconPath != 'icon/') $this->canExportIcons = true;
+               if ($this->style->imagePath && $this->style->imagePath != 'images/') $this->canExportImages = true;
+               if ($this->style->templateGroupID) $this->canExportTemplates = true;
+       }
+       
+       /**
+        * @see wcf\form\IForm::readFormParameters()
+        */
+       public function readFormParameters() {
+               parent::readFormParameters();
+               
+               if ($this->canExportIcons && isset($_POST['exportIcons'])) $this->exportIcons = true;
+               if ($this->canExportImages && isset($_POST['exportImages'])) $this->exportImages = true;
+               if ($this->canExportTemplates && isset($_POST['exportTemplates'])) $this->exportTemplates = true;
+               
+               if (isset($_POST['exportAsPackage'])) {
+                       $this->exportAsPackage = true;
+                       
+                       if (isset($_POST['packageName'])) $this->packageName = StringUtil::trim($_POST['packageName']);
+               }
+       }
+       
+       /**
+        * @see wcf\form\IForm::validate()
+        */
+       public function validate() {
+               parent::validate();
+               
+               if ($this->exportAsPackage) {
+                       if (empty($this->packageName)) {
+                               throw new UserInputException('packageName');
+                       }
+                       
+                       if (!Package::isValidPackageName($this->packageName)) {
+                               throw new UserInputException('packageName', 'notValid');
+                       }
+                       
+                       // 3rd party packages may never have com.woltlab.* as name
+                       if (strpos($this->packageName, 'com.woltlab.') === 0) {
+                               throw new UserInputException('packageName', 'reserved');
+                       }
+               }
+       }
+       
+       /**
+        * @see wcf\form\IForm::save()
+        */
+       public function save() {
+               parent::save();
+               
+               // get style filename
+               $filename = str_replace(' ', '-', preg_replace('/[^a-z0-9 _-]/', '', StringUtil::toLowerCase($this->style->styleName)));
+               
+               // send headers
+               header('Content-Type: application/x-gzip; charset=utf-8');
+               
+               if ($this->exportAsPackage) {
+                       header('Content-Disposition: attachment; filename="'.$this->packageName.'.tar.gz"');
+               }
+               else {
+                       header('Content-Disposition: attachment; filename="'.$filename.'-style.tgz"');
+               }
+               
+               // export style
+               $styleEditor = new StyleEditor($this->style);
+               $styleEditor->export($this->exportTemplates, $this->exportImages, $this->exportIcons, $this->packageName);
+               
+               // call saved event
+               $this->saved();
+               
+               exit;
+       }
+       
+       /**
+        * @see wcf\form\IForm::assignVariables()
+        */
+       public function assignVariables() {
+               parent::assignVariables();
+               
+               WCF::getTPL()->assign(array(
+                       'canExportIcons' => $this->canExportIcons,
+                       'canExportImages' => $this->canExportImages,
+                       'canExportTemplates' => $this->canExportTemplates,
+                       'exportAsPackage' => $this->exportAsPackage,
+                       'exportIcons' => $this->exportIcons,
+                       'exportImages' => $this->exportImages,
+                       'exportTemplates' => $this->exportTemplates,
+                       'packageName' => $this->packageName,
+                       'style' => $this->style,
+                       'styleID' => $this->styleID
+               ));
+       }
+}
diff --git a/wcfsetup/install/files/lib/acp/form/StyleImportForm.class.php b/wcfsetup/install/files/lib/acp/form/StyleImportForm.class.php
new file mode 100644 (file)
index 0000000..9a71c1c
--- /dev/null
@@ -0,0 +1,91 @@
+<?php
+namespace wcf\acp\form;
+use wcf\data\style\StyleEditor;
+use wcf\form\AbstractForm;
+use wcf\system\exception\UserInputException;
+use wcf\system\WCF;
+use wcf\util\FileUtil;
+
+/**
+ * Shows the style import form.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2013 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage acp.form
+ * @category   Community Framework
+ */
+class StyleImportForm extends AbstractForm {
+       /**
+        * @see wcf\acp\form\ACPForm::$activeMenuItem
+        */
+       public $activeMenuItem = 'wcf.acp.menu.link.style.import';
+       
+       /**
+        * @see wcf\page\AbstractPage::$neededPermissions
+        */
+       public $neededPermissions = array('admin.style.canAddStyle');
+       
+       /**
+        * upload data
+        * @var array<string>
+        */
+       public $source = array();
+       
+       /**
+        * style editor object
+        * @var wcf\data\style\StyleEditor
+        */
+       public $style = null;
+       
+       /**
+        * @see wcf\form\IForm::readFormParameters()
+        */
+       public function readFormParameters() {
+               parent::readFormParameters();
+               
+               if (isset($_FILES['source'])) $this->source = $_FILES['source'];
+       }
+       
+       /**
+        * @see wcf\form\IForm::validate()
+        */
+       public function validate() {
+               parent::validate();
+       
+               if (empty($this->source['name'])) {
+                       throw new UserInputException('source');
+               }
+               
+               if (empty($this->source['tmp_name'])) {
+                       throw new UserInputException('source', 'uploadFailed');
+               }
+               
+               // get filename
+               $this->source['name'] = FileUtil::getTemporaryFilename('style_', preg_replace('!^.*(?=\.(?:tar\.gz|tgz|tar)$)!i', '', basename($this->source['name'])));
+               
+               if (!@move_uploaded_file($this->source['tmp_name'], $this->source['name'])) {
+                       throw new UserInputException('source', 'uploadFailed');
+               }
+       }
+       
+       /**
+        * @see wcf\form\IForm::save()
+        */
+       public function save() {
+               parent::save();
+               
+               try {
+                       $this->style = StyleEditor::import($this->source['name']);
+               }
+               catch (\Exception $e) {
+                       @unlink($this->source['name']);
+               }
+               
+               @unlink($this->source['name']);
+               $this->saved();
+               
+               WCF::getTPL()->assign('success', true);
+       }
+}
diff --git a/wcfsetup/install/files/lib/acp/page/StyleListPage.class.php b/wcfsetup/install/files/lib/acp/page/StyleListPage.class.php
new file mode 100644 (file)
index 0000000..25ae710
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+namespace wcf\acp\page;
+use wcf\page\MultipleLinkPage;
+
+/**
+ * Shows the style list page.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2013 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage acp.page
+ * @category   Community Framework
+ */
+class StyleListPage extends MultipleLinkPage {
+       /**
+        * @see wcf\page\AbstractPage::$activeMenuItem
+        */
+       public $activeMenuItem = 'wcf.acp.menu.link.style.list';
+       
+       /**
+        * @see wcf\page\AbstractPage::$neededPermissions
+        */
+       public $neededPermissions = array('admin.style.canEditStyle', 'admin.style.canDeleteStyle');
+       
+       /**
+        * @see wcf\page\MultipleLinkPage::$objectListClassName
+        */
+       public $objectListClassName = 'wcf\data\style\StyleList';
+       
+       /**
+        * @see wcf\page\MultipleLinkPage::$sortField
+        */
+       public $sortField = 'style.styleName';
+       
+       /**
+        * @see wcf\page\MultipleLinkPage::$sortOrder
+        */
+       public $sortOrder = 'ASC';
+       
+       /**
+        * @see wcf\page\MultipleLinkPage::initObjectList()
+        */
+       public function initObjectList() {
+               parent::initObjectList();
+               
+               $this->objectList->sqlSelects = "(SELECT COUNT(*) FROM wcf".WCF_N."_user WHERE styleID = style.styleID) AS users";
+       }
+}
diff --git a/wcfsetup/install/files/style/styleEditor.less b/wcfsetup/install/files/style/styleEditor.less
new file mode 100644 (file)
index 0000000..820c8a1
--- /dev/null
@@ -0,0 +1,37 @@
+.colorPreview {
+       border: 1px solid @wcfContainerBorderColor;
+       border-radius: @wcfContainerBorderRadius;
+       display: inline-block;
+       
+       &:hover {
+               .boxShadow(0, 0, @wcfContainerBorderColor, 15px, 0);
+       }
+       
+       > div {
+               border: 2px solid rgba(255, 255, 255, 1);
+               border-radius: @wcfContainerBorderRadius;
+               cursor: pointer;
+               display: block;
+               height: 60px;
+               width: 200px;
+       }
+}
+
+.colorList {
+       > li {
+               float: left;
+               padding: @wcfGapSmall;
+               
+               > figure > figcaption {
+                       font-size: 85%;
+                       margin-bottom: @wcfGapSmall;
+                       text-align: center;
+               }
+       }
+       
+       &:after {
+               clear: both;
+               content: "";
+               display: block;
+       }
+}
index 3b3afffbd45551f08dc454b40f1ab746866be625..cf30ee1279c6ee0556d1e4435652d7876fbe8b00 100644 (file)
                <item name="wcf.acp.menu.link.pageMenu"><![CDATA[Seitenmenü]]></item>
                <item name="wcf.acp.menu.link.pageMenu.add"><![CDATA[Menüpunkt hinzufügen]]></item>
                <item name="wcf.acp.menu.link.pageMenu.list"><![CDATA[Menüpunkte auflisten]]></item>
+               <item name="wcf.acp.menu.link.style"><![CDATA[Stile]]></item>
+               <item name="wcf.acp.menu.link.style.add"><![CDATA[Stil hinzufügen]]></item>
+               <item name="wcf.acp.menu.link.style.import"><![CDATA[Stil importieren]]></item>
+               <item name="wcf.acp.menu.link.style.list"><![CDATA[Stile auflisten]]></item>
                <item name="wcf.acp.menu.link.system"><![CDATA[System]]></item>
                <item name="wcf.acp.menu.link.user"><![CDATA[Benutzer]]></item>
                <item name="wcf.acp.menu.link.user.add"><![CDATA[Benutzer hinzufügen]]></item>
                <item name="wcf.acp.sessionLog.time"><![CDATA[Datum]]></item>
        </category>
        
+       <category name="wcf.acp.style">
+               <item name="wcf.acp.style.add"><![CDATA[Stil hinzufügen]]></item>
+               <item name="wcf.acp.style.advanced"><![CDATA[Erweiterte Einstellungen]]></item>
+               <item name="wcf.acp.style.advanced.individualLess"><![CDATA[Individuelles CSS und LESS]]></item>
+               <item name="wcf.acp.style.advanced.individualLess.description"><![CDATA[Die Eingabe wird am Ende des Stils eingefügt und kann vollständig aus CSS bestehen. Sie haben zusätzlich den Zugriff auf LESS und alle von Community Framework zur Verfügung gestellten Mixins.]]></item>
+               <item name="wcf.acp.style.advanced.overrideLess"><![CDATA[Überschreiben von LESS-Variablen]]></item>
+               <item name="wcf.acp.style.advanced.overrideLess.description"><![CDATA[Sie können innerhalb dieser Eingabe beliebige LESS-Variablen überschreiben, die nicht durch den Stil-Editor direkt bearbeitbar ist. Beim Bezug auf andere Variablen muss sichergestellt werden, dass diese in der Reihenfolge vorher definiert wurden. Die Syntax muss wie folgt lauten: „@variableName: variableValue;“]]></item>
+               <item name="wcf.acp.style.advanced.overrideLess.error"><![CDATA[Ihre Eingabe war ungültig, bitte überprüfen Sie die folgenden Einträge:]]></item>
+               <item name="wcf.acp.style.advanced.overrideLess.error.notValid"><![CDATA[Eingabe „{$error[text]}“ ungültig]]></item>
+               <item name="wcf.acp.style.advanced.overrideLess.error.predefined"><![CDATA[Variable „{$error[text]}“ wird bereits durch den Stil-Editor gesetzt]]></item>
+               <item name="wcf.acp.style.advanced.overrideLess.error.unknown"><![CDATA[Variable „{$error[text]}“ unbekannt]]></item>
+               <item name="wcf.acp.style.advanced.overrideLess.warning"><![CDATA[Fehlerhafte Eingaben führen dazu, dass der Stil nicht erzeugt werden kann. Überschreiben Sie LESS-Variablen nur, wenn Sie sich den Auswirkungen bewusst sind und eine Änderung anderweitig nicht möglich ist.]]></item>
+               <item name="wcf.acp.style.advanced.syntax"><![CDATA[Sie können sowohl CSS als auch <a href="{@$__wcf->getPath()}acp/dereferrer.php?url=http://www.lesscss.org">LESS</a> verwenden. Bitte beachten Sie, dass der Stil nicht erzeugt werden kann, wenn der LESS-Code ungültig ist.]]></item>
+               <item name="wcf.acp.style.authorName"><![CDATA[Autor]]></item>
+               <item name="wcf.acp.style.authorURL"><![CDATA[Website]]></item>
+               <item name="wcf.acp.style.button.exportStyle"><![CDATA[Export starten]]></item>
+               <item name="wcf.acp.style.button.setAsDefault"><![CDATA[Zum Standard machen]]></item>
+               <item name="wcf.acp.style.colors"><![CDATA[Farbpalette]]></item>
+               <item name="wcf.acp.style.colors.accentBackgroundColor"><![CDATA[Hintergrundfarbe (Akzent)]]></item>
+               <item name="wcf.acp.style.colors.backgroundColor"><![CDATA[Hintergrundfarbe]]></item>
+               <item name="wcf.acp.style.colors.borderColor"><![CDATA[Rahmenfarbe]]></item>
+               <item name="wcf.acp.style.colors.buttons"><![CDATA[Buttons]]></item>
+               <item name="wcf.acp.style.colors.container"><![CDATA[Container]]></item>
+               <item name="wcf.acp.style.colors.content"><![CDATA[Inhaltsbereich]]></item>
+               <item name="wcf.acp.style.colors.color"><![CDATA[Schriftfarbe]]></item>
+               <item name="wcf.acp.style.colors.dimmedColor"><![CDATA[Schriftfarbe (abgeschwächt)]]></item>
+               <item name="wcf.acp.style.colors.formInput"><![CDATA[Eingabeelemente in Formularen]]></item>
+               <item name="wcf.acp.style.colors.hoverBackgroundColor"><![CDATA[Hintergrundfarbe (Hover)]]></item>
+               <item name="wcf.acp.style.colors.hoverBorderColor"><![CDATA[Rahmenfarbe (Hover)]]></item>
+               <item name="wcf.acp.style.colors.hoverColor"><![CDATA[Schriftfarbe (Hover)]]></item>
+               <item name="wcf.acp.style.colors.linkColor"><![CDATA[Linkfarbe]]></item>
+               <item name="wcf.acp.style.colors.linkHoverColor"><![CDATA[Linkfarbe (Hover)]]></item>
+               <item name="wcf.acp.style.colors.page"><![CDATA[Seite]]></item>
+               <item name="wcf.acp.style.colors.primaryBackgroundColor"><![CDATA[Hintergrundfarbe (primär)]]></item>
+               <item name="wcf.acp.style.colors.primaryBorderColor"><![CDATA[Rahmenfarbe (primär)]]></item>
+               <item name="wcf.acp.style.colors.primaryColor"><![CDATA[Schriftfarbe (primär)]]></item>
+               <item name="wcf.acp.style.colors.tabular"><![CDATA[Tabellarische Auflistungen]]></item>
+               <item name="wcf.acp.style.colors.userPanel"><![CDATA[Benutzerleiste]]></item>
+               <item name="wcf.acp.style.copyright"><![CDATA[Copyright]]></item>
+               <item name="wcf.acp.style.copyStyle"><![CDATA[Stil kopieren]]></item>
+               <item name="wcf.acp.style.copyStyle.confirmMessage"><![CDATA[Möchten Sie den Stil „{$style->styleName}“ wirklich duplizieren?]]></item>
+               <item name="wcf.acp.style.delete.confirmMessage"><![CDATA[Möchten Sie den Stil „{$style->styleName}“ wirklich löschen?]]></item>
+               <item name="wcf.acp.style.edit"><![CDATA[Stil bearbeiten]]></item>
+               <item name="wcf.acp.style.exportAsPackage"><![CDATA[Als Paket exportieren]]></item>
+               <item name="wcf.acp.style.exportIcons"><![CDATA[Icons exportieren ({$style->iconPath})]]></item>
+               <item name="wcf.acp.style.exportImages"><![CDATA[Grafiken exportieren ({$style->imagePath})]]></item>
+               <item name="wcf.acp.style.exportTemplates"><![CDATA[Templates exportieren]]></item>
+               <item name="wcf.acp.style.exportStyle"><![CDATA[Stil exportieren]]></item>
+               <item name="wcf.acp.style.exportStyle.asPackage"><![CDATA[Export als Paket]]></item>
+               <item name="wcf.acp.style.exportStyle.asPackage.description"><![CDATA[Wählen Sie hier aus, ob sie den Stil „{$style->styleName}“ als Paket exportieren möchten. Pakete können über die Paketverwaltung installiert oder in den <a href="{@$__wcf->getPath()}acp/dereferrer.php?url=http://www.woltlab.com/de/pluginstore/">WoltLab® Plugin-Store</a> hochgeladen werden.]]></item>
+               <item name="wcf.acp.style.exportStyle.components"><![CDATA[Optionen]]></item>
+               <item name="wcf.acp.style.exportStyle.components.description"><![CDATA[Wählen Sie hier aus, welche Bestandteile des Stils „{$style->styleName}“ mit exportiert werden sollen]]></item>
+               <item name="wcf.acp.style.general"><![CDATA[Daten]]></item>
+               <item name="wcf.acp.style.general.data"><![CDATA[Allgemein]]></item>
+               <item name="wcf.acp.style.general.files"><![CDATA[Dateien]]></item>
+               <item name="wcf.acp.style.globals"><![CDATA[Globale Einstellungen]]></item>
+               <item name="wcf.acp.style.globals.fixedLayoutWidth"><![CDATA[Breite]]></item>
+               <item name="wcf.acp.style.globals.fluidLayoutGap"><![CDATA[Abstand zum Seitenrand]]></item>
+               <item name="wcf.acp.style.globals.font"><![CDATA[Schriftbild]]></item>
+               <item name="wcf.acp.style.globals.fontFamily"><![CDATA[Schriftart]]></item>
+               <item name="wcf.acp.style.globals.fontSize"><![CDATA[Schriftgröße]]></item>
+               <item name="wcf.acp.style.globals.layout"><![CDATA[Layout]]></item>
+               <item name="wcf.acp.style.globals.useFluidLayout"><![CDATA[Flexible Breite verwenden]]></item>
+               <item name="wcf.acp.style.iconPath"><![CDATA[Icon-Pfad]]></item>
+               <item name="wcf.acp.style.iconPath.description"><![CDATA[Wenn Ihr Stil eigene Icons benötigt, sollten diese in einem Unterordner des Ordners „icons“ ablegen. Geben Sie hier den Pfad zu diesem Ordner an.]]></item>
+               <item name="wcf.acp.style.image"><![CDATA[Vorschaubild]]></item>
+               <item name="wcf.acp.style.image.description"><![CDATA[Laden Sie hier ein Vorschaubild dieses Stiles hoch, als Bildformate sind JPG und PNG zulässig. Es wird empfohlen Vorschaubilder immer mit der Größe 102px × 64px anzulegen, größere Grafiken werden automatisch skaliert.]]></item>
+               <item name="wcf.acp.style.imagePath"><![CDATA[Bilder-Pfad]]></item>
+               <item name="wcf.acp.style.imagePath.description"><![CDATA[Wenn Ihr Stil eigene Grafiken benötigt, sollten diese in einem Unterordner des Ordners „images“ ablegen. Geben Sie hier den Pfad zu diesem Ordner an.]]></item>
+               <item name="wcf.acp.style.importStyle"><![CDATA[Stil importieren]]></item>
+               <item name="wcf.acp.style.import.source"><![CDATA[Datenquelle]]></item>
+               <item name="wcf.acp.style.import.source.upload"><![CDATA[Stil hochladen]]></item>
+               <item name="wcf.acp.style.import.source.upload.description"><![CDATA[Geben Sie eine Stil-Datei von Ihrem lokalen Rechner an.]]></item>
+               <item name="wcf.acp.style.license"><![CDATA[Lizenz]]></item>
+               <item name="wcf.acp.style.list"><![CDATA[Stile auflisten]]></item>
+               <item name="wcf.acp.style.packageName"><![CDATA[Paketbezeichner]]></item>
+               <item name="wcf.acp.style.packageName.description"><![CDATA[Geben Sie hier den Paketbezeichner in der Form „tld.domain.paketName“ an. Wenn Ihnen beispielsweise die Domain „example.com“ gehört und Ihr Stil „Blue Sunrise“ heißt, so wäre „com.example.style.blueSunrise“ ein passender und gültiger Paketbezeichner.]]></item>
+               <item name="wcf.acp.style.packageName.error.notValid"><![CDATA[Der eingegebene Paketbezeichner ist ungültig]]></item>
+               <item name="wcf.acp.style.packageName.error.reserved"><![CDATA[Der Paketbezeichner darf nicht mit „com.woltlab.“ beginnen]]></item>
+               <item name="wcf.acp.style.styleDate"><![CDATA[Datum]]></item>
+               <item name="wcf.acp.style.styleDescription"><![CDATA[Beschreibung]]></item>
+               <item name="wcf.acp.style.styleName"><![CDATA[Name]]></item>
+               <item name="wcf.acp.style.styleVersion"><![CDATA[Version]]></item>
+               <item name="wcf.acp.style.templateGroupID"><![CDATA[Template-Gruppe]]></item>
+               <item name="wcf.acp.style.users"><![CDATA[Benutzer]]></item>
+       </category>
+       
        <category name="wcf.acp.user">
                <item name="wcf.acp.user.add"><![CDATA[Benutzer hinzufügen]]></item>
                <item name="wcf.acp.user.assignToGroup"><![CDATA[Benutzergruppe zuweisen]]></item>