<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>
<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>
--- /dev/null
+/**
+ * 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();
+ }
+});
--- /dev/null
+{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
--- /dev/null
+{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
--- /dev/null
+{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
--- /dev/null
+{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'}
--- /dev/null
+<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
--- /dev/null
+<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
--- /dev/null
+<?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
+ ));
+ }
+}
--- /dev/null
+<?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
+ ));
+ }
+}
--- /dev/null
+<?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
+ ));
+ }
+}
--- /dev/null
+<?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);
+ }
+}
--- /dev/null
+<?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";
+ }
+}
--- /dev/null
+.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;
+ }
+}
<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>