The boolean option type allowed only for a simple true/false, which is sometimes quite difficult to work with. For example revoking group permissions is usually accomplished by fiddling with all groups.
The 'Never' option solves this by using the unique value '-1' to revoke a permission regardless how often it was granted.
--- /dev/null
+<ol class="optionTypeBoolean">
+ <li>
+ <input type="radio" id="{$option->optionName}_yes"{if $value == 1} checked="checked"{/if} name="values[{$option->optionName}]" value="1"{if $disableOptions || $enableOptions} class="jsEnablesOptions" data-is-boolean="true" data-disable-options="[ {@$disableOptions}]" data-enable-options="[ {@$enableOptions}]"{/if}>
+ <label for="{$option->optionName}_yes" class="yes"><span class="icon icon16 fa-check"></span> {lang}wcf.acp.group.option.type.boolean.yes{/lang}</label>
+ </li>
+ <li>
+ <input type="radio" id="{$option->optionName}_no"{if $value == 0} checked="checked"{/if} name="values[{$option->optionName}]" value="0"{if $disableOptions || $enableOptions} class="jsEnablesOptions" data-is-boolean="true" data-disable-options="[ {@$disableOptions}]" data-enable-options="[ {@$enableOptions}]"{/if}>
+ <label for="{$option->optionName}_no" class="no"><span class="icon icon16 fa-times"></span> {lang}wcf.acp.group.option.type.boolean.no{/lang}</label>
+ </li>
+ {if $group === null || !$group->isEveryone()}
+ <li>
+ <input type="radio" id="{$option->optionName}_never"{if $value == -1} checked="checked"{/if} name="values[{$option->optionName}]" value="-1"{if $disableOptions || $enableOptions} class="jsEnablesOptions" data-is-boolean="true" data-disable-options="[ {@$disableOptions}]" data-enable-options="[ {@$enableOptions}]"{/if}>
+ <label for="{$option->optionName}_never" class="never"><span class="icon icon16 fa-ban"></span> {lang}wcf.acp.group.option.type.boolean.never{/lang}</label>
+ </li>
+ {/if}
+</ol>
case 'radio':
if (option.prop('checked')) {
- this._execute(true, $disableOptions, $enableOptions);
+ var isActive = true;
+ if (option.data('isBoolean') && option.val() != 1) {
+ isActive = false;
+ }
+
+ this._execute(isActive, $disableOptions, $enableOptions);
}
break;
}
return false;
}
+ /**
+ * Returns true if this is the 'Everyone' group.
+ *
+ * @return boolean
+ */
+ public function isEveryone() {
+ return $this->groupType == self::EVERYONE;
+ }
+
/**
* Returns true if the given groups are accessible for the active user.
*
* list of used group option type objects
* @var array<\wcf\system\option\group\IGroupOptionType>
*/
- protected $typeObjects = array();
+ protected $typeObjects = [];
/**
* @see \wcf\system\cache\builder\AbstractCacheBuilder::rebuild()
*/
public function rebuild(array $parameters) {
- $data = array();
+ $data = [];
- // get all options
- $sql = "SELECT optionName, optionID
- FROM wcf".WCF_N."_user_group_option";
- $statement = WCF::getDB()->prepareStatement($sql);
- $statement->execute();
+ // get option values
+ $conditions = new PreparedStatementConditionBuilder();
+ $conditions->add("option_value.groupID IN (?)", [ $parameters ]);
- $options = array();
+ $sql = "SELECT option_table.optionName, option_table.optionType, option_value.optionValue
+ FROM wcf".WCF_N."_user_group_option_value option_value
+ LEFT JOIN wcf".WCF_N."_user_group_option option_table
+ ON (option_table.optionID = option_value.optionID)
+ ".$conditions;
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute($conditions->getParameters());
while ($row = $statement->fetchArray()) {
- $options[$row['optionName']] = $row['optionID'];
+ if (!isset($data[$row['optionName']])) {
+ $data[$row['optionName']] = [ 'type' => $row['optionType'], 'values' => [] ];
+ }
+
+ $data[$row['optionName']]['values'][] = $row['optionValue'];
}
- if (!empty($options)) {
- // get needed options
- $conditions = new PreparedStatementConditionBuilder();
- $conditions->add("option_value.groupID IN (?)", array($parameters));
- $conditions->add("option_value.optionID IN (?)", array($options));
-
- $sql = "SELECT option_table.optionName, option_table.optionType, option_value.optionValue
- FROM wcf".WCF_N."_user_group_option_value option_value
- LEFT JOIN wcf".WCF_N."_user_group_option option_table
- ON (option_table.optionID = option_value.optionID)
- ".$conditions;
- $statement = WCF::getDB()->prepareStatement($sql);
- $statement->execute($conditions->getParameters());
- while ($row = $statement->fetchArray()) {
- if (!isset($data[$row['optionName']])) {
- $data[$row['optionName']] = array('type' => $row['optionType'], 'values' => array());
- }
-
- $data[$row['optionName']]['values'][] = $row['optionValue'];
+ // merge values
+ foreach ($data as $optionName => $option) {
+ if (count($option['values']) == 1) {
+ $result = $option['values'][0];
}
-
- // merge values
- foreach ($data as $optionName => $option) {
- if (count($option['values']) == 1) {
- $result = $option['values'][0];
- }
- else {
- $typeObj = $this->getTypeObject($option['type']);
- $result = array_shift($option['values']);
- foreach ($option['values'] as $value) {
- $newValue = $typeObj->merge($result, $value);
- if ($newValue !== null) {
- $result = $newValue;
- }
+ else {
+ $typeObj = $this->getTypeObject($option['type']);
+ $result = array_shift($option['values']);
+ foreach ($option['values'] as $value) {
+ $newValue = $typeObj->merge($result, $value);
+ if ($newValue !== null) {
+ $result = $newValue;
}
}
-
- // unset false values
- if ($result === false) {
- unset($data[$optionName]);
- }
- else {
- $data[$optionName] = $result;
- }
+ }
+
+ // handle special value 'Never' for boolean options
+ if ($option['type'] === 'boolean' && $result == -1) {
+ $result = 0;
+ }
+
+ // unset false values
+ if ($result === false) {
+ unset($data[$optionName]);
+ }
+ else {
+ $data[$optionName] = $result;
}
}
use wcf\system\exception\SystemException;
use wcf\system\exception\UserInputException;
use wcf\system\language\I18nHandler;
-use wcf\system\WCF;
use wcf\util\ClassUtil;
use wcf\util\StringUtil;
<?php
namespace wcf\system\option\user\group;
+use wcf\data\option\Option;
use wcf\system\option\BooleanOptionType;
+use wcf\system\WCF;
/**
* User group option type implementation for boolean values.
* @subpackage system.option.user.group
* @category Community Framework
*/
-class BooleanUserGroupOptionType extends BooleanOptionType implements IUserGroupOptionType {
+class BooleanUserGroupOptionType extends BooleanOptionType implements IUserGroupOptionType, IUserGroupGroupOptionType {
+ use TUserGroupOptionType;
+
+ /**
+ * @see \wcf\system\option\IOptionType::getFormElement()
+ */
+ public function getFormElement(Option $option, $value) {
+ $options = Option::parseEnableOptions($option->enableOptions);
+
+ WCF::getTPL()->assign([
+ 'disableOptions' => $options['disableOptions'],
+ 'enableOptions' => $options['enableOptions'],
+ 'group' => $this->userGroup,
+ 'option' => $option,
+ 'value' => $value
+ ]);
+
+ return WCF::getTPL()->fetch('userGroupBooleanOptionType');
+ }
+
+ /**
+ * @see \wcf\system\option\IOptionType::getCSSClassName()
+ */
+ public function getCSSClassName() {
+ return '';
+ }
+
/**
* @see \wcf\system\option\user\group\IUserGroupOptionType::merge()
*/
public function merge($defaultValue, $groupValue) {
+ // force value for 'Never'
+ if ($defaultValue == -1 || $groupValue == -1) {
+ return -1;
+ }
+
// don't save if values are equal or $defaultValue is better
if ($defaultValue == $groupValue || $defaultValue && !$groupValue) {
return null;
--- /dev/null
+<?php
+namespace wcf\system\option\user\group;
+use wcf\data\user\group\UserGroup;
+
+/**
+ * Default interface for user group option types requiring the active user group object.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage system.option.user.group
+ * @category Community Framework
+ */
+interface IUserGroupGroupOptionType {
+ /**
+ * Sets the active user group object.
+ *
+ * @param \wcf\data\user\group\UserGroup $group
+ */
+ public function setUserGroup(UserGroup $group);
+
+ /**
+ * Returns the active user group object or null.
+ *
+ * @return \wcf\data\user\group\UserGroup
+ */
+ public function getUserGroup();
+}
--- /dev/null
+<?php
+namespace wcf\system\option\user\group;
+use wcf\data\user\group\UserGroup;
+
+/**
+ * Default trait for user group option types implementing IUserGroupGroupOptionType.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage system.option.user.group
+ * @category Community Framework
+ */
+trait TUserGroupOptionType {
+ /**
+ * user group object
+ * @var \wcf\data\user\group\UserGroup
+ */
+ protected $userGroup = null;
+
+ /**
+ * @see \wcf\system\option\user\group\IUserGroupGroupOptionType::setUserGroup()
+ */
+ public function setUserGroup(UserGroup $group) {
+ $this->userGroup = $group;
+ }
+
+ /**
+ * @see \wcf\system\option\user\group\IUserGroupGroupOptionType::getUserGroup()
+ */
+ public function getUserGroup() {
+ return $this->userGroup;
+ }
+}
$this->group = $group;
}
+ /**
+ * @see \wcf\system\option\OptionHandler::getTypeObject()
+ */
+ public function getTypeObject($type) {
+ $objectType = parent::getTypeObject($type);
+
+ if ($this->group !== null && $objectType instanceof IUserGroupGroupOptionType) {
+ $objectType->setUserGroup($this->group);
+ }
+
+ return $objectType;
+ }
+
/**
* @see \wcf\system\option\OptionHandler::checkOption()
*/
.redactor-editor {
font-size: 16px;
}
+}
+
+/* BooleanUserGroupOptionType */
+.optionTypeBoolean {
+ display: flex;
+
+ > li {
+ border: 1px solid @wcfContainerBorderColor;
+ display: flex;
+ flex: 0 1 100px;
+
+ &:not(:last-child) {
+ border-right-width: 0;
+ }
+
+ &:first-child {
+ border-radius: 3px 0 0 3px;
+ }
+
+ &:last-child {
+ border-radius: 0 3px 3px 0;
+ }
+
+ &:hover > label {
+ opacity: 1 !important;
+ }
+
+ > input {
+ display: none;
+
+ &:not(:checked) + label {
+ opacity: .6;
+ }
+
+ &:checked + label {
+ opacity: 1;
+
+ &.yes {
+ background-color: rgb(223, 240, 216);
+ color: rgb(60, 118, 61);
+
+ > .icon {
+ color: rgb(60, 118, 61);
+ }
+ }
+
+ &.no {
+ background-color: rgb(242, 222, 222);
+ color: rgb(169, 68, 66);
+
+ > .icon {
+ color: rgb(169, 68, 66);
+ }
+ }
+
+ &.never {
+ background-color: rgb(252, 248, 227);
+ color: rgb(138, 109, 59);
+
+ > .icon {
+ color: rgb(138, 109, 59);
+ }
+ }
+ }
+ }
+
+ > label {
+ cursor: pointer;
+ flex: 1 auto;
+ font-size: .85rem;
+ padding: @wcfGapTiny;
+ text-align: center;
+
+ transition: all .3s linear;
+
+ > .icon {
+ cursor: pointer !important;
+ }
+ }
+ }
+}
+
+@media only screen and (max-width: 800px) {
+ .optionTypeBoolean > li {
+ flex: 1;
+ }
}
\ No newline at end of file
<item name="wcf.acp.group.copy.copyUserGroupOptions.description"><![CDATA[Die neue Benutzergruppe wird die gleichen Berechtigungen besitzen wie die kopierte Benutzergruppe.]]></item>
<item name="wcf.acp.group.option.admin.paidSubscription.canManageSubscription"><![CDATA[Kann bezahlte Mitgliedschaften verwalten]]></item>
<item name="wcf.acp.group.option.user.tag.canViewTag"><![CDATA[Kann Tag sehen]]></item>
+ <item name="wcf.acp.group.option.type.boolean.never"><![CDATA[Nie]]></item>
+ <item name="wcf.acp.group.option.type.boolean.no"><![CDATA[Nein]]></item>
+ <item name="wcf.acp.group.option.type.boolean.yes"><![CDATA[Ja]]></item>
</category>
<category name="wcf.acp.index">
<item name="wcf.acp.group.copy.copyUserGroupOptions.description"><![CDATA[The new user group will have the same permissions as the copied user group.]]></item>
<item name="wcf.acp.group.option.admin.paidSubscription.canManageSubscription"><![CDATA[Can manage paid subscriptions]]></item>
<item name="wcf.acp.group.option.user.tag.canViewTag"><![CDATA[Can view tags]]></item>
+ <item name="wcf.acp.group.option.type.boolean.never"><![CDATA[Never]]></item>
+ <item name="wcf.acp.group.option.type.boolean.no"><![CDATA[No]]></item>
+ <item name="wcf.acp.group.option.type.boolean.yes"><![CDATA[Yes]]></item>
</category>
<category name="wcf.acp.index">