diff --git a/acloptions.xml b/acloptions.xml index 8042782..5df092e 100644 --- a/acloptions.xml +++ b/acloptions.xml @@ -1,8 +1,34 @@ - + + + timwolla.wcf.chat.room + + + timwolla.wcf.chat.room + + + + + + + + + + + \ No newline at end of file diff --git a/acpMenu.xml b/acpMenu.xml new file mode 100644 index 0000000..2752765 --- /dev/null +++ b/acpMenu.xml @@ -0,0 +1,22 @@ + + + + + wcf.acp.menu.link.content + + + + index.php/ChatRoomList/ + wcf.acp.menu.link.chat + admin.content.chat.canEditRoom,admin.content.chat.canDeleteRoom + 1 + + + + index.php/ChatRoomAdd/ + wcf.acp.menu.link.chat + admin.content.chat.canAddRoom + 2 + + + diff --git a/acptemplate/chatRoomAdd.tpl b/acptemplate/chatRoomAdd.tpl new file mode 100644 index 0000000..a3c0e81 --- /dev/null +++ b/acptemplate/chatRoomAdd.tpl @@ -0,0 +1,101 @@ +{include file='header'} + + + + + + + + +
+ +
+

{lang}wcf.acp.chat.room.{$action}{/lang}

+
+
+ +{if $errorField} +

{lang}wcf.global.form.error{/lang}

+{/if} + +{if $success|isset} +

{lang}wcf.global.form.{$action}.success{/lang}

+{/if} + +
+ +
+ +
+
+
+ {lang}wcf.acp.chat.room.data{/lang} + + +
+
+ + {if $errorField == 'title'} + + {if $errorType == 'empty'} + {lang}wcf.global.form.error.empty{/lang} + {else} + {lang}wcf.acp.chat.room.title.error.{@$errorType}{/lang} + {/if} + + {/if} +
+ + + {include file='multipleLanguageInputJavascript' elementIdentifier='title'} + + +
+
+ + {if $errorField == 'topic'} + + {if $errorType == 'empty'} + {lang}wcf.global.form.error.empty{/lang} + {else} + {lang}wcf.acp.chat.room.topic.error.{@$errorType}{/lang} + {/if} + + {/if} +
+ + + {include file='multipleLanguageInputJavascript' elementIdentifier='topic'} + +
+
{lang}wcf.acp.acl.permissions{/lang}
+
+
+
+
+ +
+ + + {@SID_INPUT_TAG} + {if $roomID|isset}{/if} +
+
+ +{include file='footer'} \ No newline at end of file diff --git a/acptemplate/chatRoomList.tpl b/acptemplate/chatRoomList.tpl new file mode 100644 index 0000000..e42144a --- /dev/null +++ b/acptemplate/chatRoomList.tpl @@ -0,0 +1,58 @@ +{include file='header'} + + + +
+ +
+

{lang}wcf.acp.chat.room.list{/lang}

+
+
+ +
+ {pages print=true assign=pagesLinks controller="ChatRoomList" link="pageNo=%d"} + + {if $__wcf->session->getPermission('admin.content.chat.canAddRoom')} + + {/if} +
+ +
+ {hascontent} +
    + {content} + {foreach from=$objects item=chatRoom} +
  1. + + {$chatRoom->title|language} + + + {if $__wcf->session->getPermission('admin.content.chat.canEditRoom')} + + {/if} + {if $__wcf->session->getPermission('admin.content.chat.canDeleteRoom')} + + {/if} + + +
  2. + {/foreach} + {/content} +
+ {hascontentelse} +

{lang}wcf.acp.chat.room.noneAvailable{/lang}

+ {/hascontent} +
+ +{include file='footer'} \ No newline at end of file diff --git a/build.php b/build.php index f10da56..5b96816 100755 --- a/build.php +++ b/build.php @@ -15,6 +15,7 @@ Cleaning up EOT; if (file_exists('file.tar')) unlink('file.tar'); if (file_exists('template.tar')) unlink('template.tar'); + if (file_exists('acptemplate.tar')) unlink('acptemplate.tar'); foreach (glob('file/js/*.js') as $jsFile) unlink($jsFile); foreach (glob('file/style/*.css') as $cssFile) unlink($cssFile); if (file_exists('timwolla.wcf.chat.tar')) unlink('timwolla.wcf.chat.tar'); @@ -60,15 +61,25 @@ EOT; if ($code != 0) exit($code); echo << + * @package timwolla.wcf.chat + */ +final class Update { + private $rooms = null; + public function __construct() { + $this->rooms = \wcf\data\chat\room\ChatRoom::getCache(); + } + + public function execute() { + foreach ($this->rooms as $room) { + $messageAction = new \wcf\data\chat\message\ChatMessageAction(array(), 'create', array( + 'data' => array( + 'roomID' => $room->roomID, + 'time' => TIME_NOW, + 'type' => \wcf\data\chat\message\ChatMessage::TYPE_INFORMATION, + // TODO: Language item + 'message' => 'Tims Chat was updated. Please refresh the page.' + ) + )); + $messageAction->executeAction(); + } + } +} +$update = new Update(); +$update->execute(); diff --git a/file/icon/chat.svg b/file/icon/chat.svg new file mode 100644 index 0000000..19808ff --- /dev/null +++ b/file/icon/chat.svg @@ -0,0 +1,58 @@ + + + + + Chat + Chat Icon (outlined) + + + + + + + + + + + + + + + + + diff --git a/file/js/TimWolla.WCF.Chat.coffee b/file/js/TimWolla.WCF.Chat.coffee index 8b81072..7bd749c 100644 --- a/file/js/TimWolla.WCF.Chat.coffee +++ b/file/js/TimWolla.WCF.Chat.coffee @@ -9,12 +9,18 @@ TimWolla ?= {} TimWolla.WCF ?= {} +consoleMock = console consoleMock ?= log: () ->, - warn: () -> + warn: () ->, + error: () -> (($, window, console) -> TimWolla.WCF.Chat = + # Tims Chat stops loading when this reaches zero + # TODO: We need an explosion animation + shields: 3 + # Templates titleTemplate: null messageTemplate: null @@ -34,17 +40,21 @@ consoleMock ?= events: newMessage: $.Callbacks() userMenu: $.Callbacks() + pe: + getMessages: null + refreshRoomList: null + fish: null init: () -> console.log '[TimWolla.WCF.Chat] Initializing' @bindEvents() @events.newMessage.add $.proxy @notify, @ - new WCF.PeriodicalExecuter $.proxy(@refreshRoomList, @), 60e3 - new WCF.PeriodicalExecuter $.proxy(@getMessages, @), @config.reloadTime * 1e3 + @pe.refreshRoomList = new WCF.PeriodicalExecuter $.proxy(@refreshRoomList, @), 60e3 + @pe.getMessages = new WCF.PeriodicalExecuter $.proxy(@getMessages, @), @config.reloadTime * 1e3 @refreshRoomList() @getMessages() - console.log '[TimWolla.WCF.Chat] Finished initializing' + console.log '[TimWolla.WCF.Chat] Finished initializing - Shields at 104 percent' ### # Autocompletes a username ### @@ -64,6 +74,7 @@ consoleMock ?= # Binds all the events needed for Tims Chat. ### bindEvents: () -> + # Mark window as focused $(window).focus $.proxy () -> document.title = @titleTemplate.fetch title: $('#timsChatRoomList .activeMenuItem a').text() @@ -71,12 +82,19 @@ consoleMock ?= @isActive = true , @ + # Mark window as blurred $(window).blur $.proxy () -> @isActive = false , @ + # Unload the chat + window.onbeforeunload = $.proxy () -> + @unload() + return undefined + , @ + # Insert a smiley - $('.smiley').click $.proxy (event) -> + $('.jsSmiley').click $.proxy (event) -> @insertText ' ' + $(event.target).attr('alt') + ' ' , @ @@ -118,11 +136,11 @@ consoleMock ?= # Clears the stream $('#timsChatClear').click (event) -> - event.preventDefault() - $('.timsChatMessage').remove() - @oldScrollTop = $('.timsChatMessageContainer').scrollTop() - $('.timsChatMessageContainer').scrollTop $('.timsChatMessageContainer ul').height() - $('#timsChatInput').focus() + event.preventDefault() + $('.timsChatMessage').remove() + @oldScrollTop = null + $('.timsChatMessageContainer').scrollTop $('.timsChatMessageContainer ul').height() + $('#timsChatInput').focus() # Toggle Buttons $('.timsChatToggle').click (event) -> @@ -139,7 +157,7 @@ consoleMock ?= # Immediatly scroll down when activating autoscroll $('#timsChatAutoscroll').click (event) -> - $(this).removeClass('hot') + $(this).parent().removeClass('default') if $(this).data 'status' $('.timsChatMessageContainer').scrollTop $('.timsChatMessageContainer ul').height() @oldScrollTop = $('.timsChatMessageContainer').scrollTop() @@ -172,15 +190,15 @@ consoleMock ?= # Set new topic if data.topic is '' - return if $('#topic').text().trim() is '' + return if $('#timsChatTopic').text().trim() is '' - $('#topic').wcfBlindOut 'vertical', () -> + $('#timsChatTopic').wcfBlindOut 'vertical', () -> $(@).text '' else - $('#topic').text data.topic - $('#topic').wcfBlindIn() if $('#topic').text().trim() isnt '' and $('#topic').is(':hidden') + $('#timsChatTopic').text data.topic + $('#timsChatTopic').wcfBlindIn() if $('#timsChatTopic').text().trim() isnt '' and $('#timsChatTopic').is(':hidden') - $('.timsChatMessage').animate('opacity', .8); + $('.timsChatMessage').addClass('unloaded', 800); @handleMessages data.messages document.title = @titleTemplate.fetch data , @) @@ -198,7 +216,7 @@ consoleMock ?= # Frees the fish ### freeTheFish: () -> - return if $.wcfIsset('fish') + return if $.wcfIsset 'fish' console.warn '[TimWolla.WCF.Chat] Freeing the fish' fish = $ '
' + WCF.String.escapeHTML('><((((\u00B0>') + '
' fish.css @@ -210,16 +228,16 @@ consoleMock ?= zIndex: 9999 fish.appendTo $ 'body' - new WCF.PeriodicalExecuter(() -> + @pe.fish = new WCF.PeriodicalExecuter(() -> left = Math.random() * 100 - 50 top = Math.random() * 100 - 50 - fish = $('#fish') + fish = $ '#fish' left *= -1 unless fish.width() < (fish.position().left + left) < ($(document).width() - fish.width()) top *= -1 unless fish.height() < (fish.position().top + top) < ($(document).height() - fish.height()) - fish.text('><((((\u00B0>') if left > 0 - fish.text('<\u00B0))))><') if left < 0 + fish.text '><((((\u00B0>' if left > 0 + fish.text '<\u00B0))))><' if left < 0 fish.animate top: '+=' + top @@ -237,6 +255,15 @@ consoleMock ?= @handleMessages(data.messages) @handleUsers(data.users) , @) + error: $.proxy((jqXHR, textStatus, errorThrown) -> + console.error '[TimWolla.WCF.Chat] Battle Station hit - shields at ' + (--@shields / 3 * 104) + ' percent' + if @shields is 0 + @pe.refreshRoomList.stop() + @pe.getMessages.stop() + @freeTheFish() + console.error '[TimWolla.WCF.Chat] We got destroyed, but could free our friend the fish before he was killed as well. Have a nice life in freedom!' + alert 'herp i cannot load messages' + , @) ### # Inserts the new messages. # @@ -248,14 +275,16 @@ consoleMock ?= if $('.timsChatMessageContainer').scrollTop() < @oldScrollTop if $('#timsChatAutoscroll').data('status') is 1 $('#timsChatAutoscroll').click() - $('#timsChatAutoscroll').addClass('hot').fadeOut('slow').fadeIn('slow') + $('#timsChatAutoscroll').parent().addClass('default').fadeOut('slow').fadeIn('slow') # Insert the messages for message in messages + continue if $.wcfIsset 'timsChatMessage'+message.messageID # Prevent problems with race condition @events.newMessage.fire message output = @messageTemplate.fetch message li = $ '
  • ' + li.attr 'id', 'timsChatMessage'+message.messageID li.addClass 'timsChatMessage timsChatMessage'+message.type li.addClass 'ownMessage' if message.sender is WCF.User.userID li.append output @@ -314,7 +343,7 @@ consoleMock ?= $(@).remove(); - $('#toggleUsers .badge').text(users.length); + $('#toggleUsers .wcf-badge').text(users.length); ### # Inserts text into our input. # @@ -371,7 +400,7 @@ consoleMock ?= success: $.proxy((data, textStatus, jqXHR) -> $('#timsChatRoomList li').remove() $('#toggleRooms a').removeClass 'ajaxLoad' - $('#toggleRooms .badge').text(data.length); + $('#toggleRooms .wcf-badge').text(data.length); for room in data li = $ '
  • ' @@ -447,4 +476,11 @@ consoleMock ?= else li.addClass 'activeMenuItem' li.find('.timsChatUserMenu').wcfBlindIn 'vertical' + ### + # Unloads the chat. + ### + unload: () -> + $.ajax @config.unloadURL, + type: 'POST' + async: false )(jQuery, @, consoleMock) diff --git a/file/lib/acp/form/ChatRoomAddForm.class.php b/file/lib/acp/form/ChatRoomAddForm.class.php new file mode 100644 index 0000000..e5a95e1 --- /dev/null +++ b/file/lib/acp/form/ChatRoomAddForm.class.php @@ -0,0 +1,149 @@ + + * @package timwolla.wcf.chat + * @subpackage acp.form + */ +class ChatRoomAddForm extends ACPForm { + /** + * @see \wcf\acp\form\ACPForm::$activeMenuItem + */ + public $activeMenuItem = 'wcf.acp.menu.link.chat.room.add'; + + /** + * @see \wcf\page\AbstractPage::$neededPermissions + */ + public $neededPermissions = array('admin.content.chat.canAddRoom'); + + /** + * Title of the room + * + * @var string + */ + public $title = ''; + + /** + * Topic of the room + * + * @var string + */ + public $topic = ''; + + /** + * @see \wcf\page\AbstractPage::__construct() + */ + public function __construct() { + $this->objectTypeID = \wcf\system\acl\ACLHandler::getInstance()->getObjectTypeID('timwolla.wcf.chat.room'); + + parent::__construct(); + } + + /** + * @see \wcf\page\IPage::readParameters() + */ + public function readParameters() { + parent::readParameters(); + + I18nHandler::getInstance()->register('title'); + I18nHandler::getInstance()->register('topic'); + } + + /** + * @see \wcf\form\IForm::readFormParameters() + */ + public function readFormParameters() { + parent::readFormParameters(); + + I18nHandler::getInstance()->readValues(); + + if (I18nHandler::getInstance()->isPlainValue('title')) $this->title = I18nHandler::getInstance()->getValue('title'); + if (I18nHandler::getInstance()->isPlainValue('topic')) $this->topic = I18nHandler::getInstance()->getValue('topic'); + } + + /** + * @see \wcf\form\IForm::validate() + */ + public function validate() { + parent::validate(); + + // validate title + if (!I18nHandler::getInstance()->validateValue('title')) { + throw new UserInputException('title'); + } + } + + /** + * @see \wcf\form\IForm::save() + */ + public function save() { + parent::save(); + + // save room + $this->objectAction = new \wcf\data\chat\room\ChatRoomAction(array(), 'create', array('data' => array( + 'title' => $this->title, + 'topic' => $this->topic + ))); + $this->objectAction->executeAction(); + $returnValues = $this->objectAction->getReturnValues(); + $chatRoomEditor = new \wcf\data\chat\room\ChatRoomEditor($returnValues['returnValues']); + $roomID = $returnValues['returnValues']->roomID; + + if (!I18nHandler::getInstance()->isPlainValue('title')) { + I18nHandler::getInstance()->save('title', 'wcf.chat.room.title'.$roomID, 'wcf.chat.room', PackageDependencyHandler::getPackageID('timwolla.wcf.chat')); + + // update title + $chatRoomEditor->update(array( + 'title' => 'wcf.chat.room.title'.$roomID + )); + } + + if (!I18nHandler::getInstance()->isPlainValue('topic')) { + I18nHandler::getInstance()->save('topic', 'wcf.chat.room.topic'.$roomID, 'wcf.chat.room', PackageDependencyHandler::getPackageID('timwolla.wcf.chat')); + + // update topic + $chatRoomEditor->update(array( + 'topic' => 'wcf.chat.room.topic'.$roomID + )); + } + + \wcf\system\acl\ACLHandler::getInstance()->save($roomID, $this->objectTypeID); + \wcf\system\chat\permission\ChatPermissionHandler::clearCache(); + + $this->saved(); + + // reset values + $this->topic = $this->title = ''; + I18nHandler::getInstance()->disableAssignValueVariables(); + + // show success + WCF::getTPL()->assign(array( + 'success' => true + )); + } + + /** + * @see \wcf\page\IPage::assignVariables() + */ + public function assignVariables() { + parent::assignVariables(); + + I18nHandler::getInstance()->assignVariables(); + + WCF::getTPL()->assign(array( + 'action' => 'add', + 'title' => $this->title, + 'topic' => $this->topic, + 'objectTypeID' => $this->objectTypeID + )); + } +} diff --git a/file/lib/acp/form/ChatRoomEditForm.class.php b/file/lib/acp/form/ChatRoomEditForm.class.php new file mode 100644 index 0000000..a0298be --- /dev/null +++ b/file/lib/acp/form/ChatRoomEditForm.class.php @@ -0,0 +1,129 @@ + + * @package timwolla.wcf.chat + * @subpackage acp.form + */ +class ChatRoomEditForm extends ChatRoomAddForm { + /** + * @see \wcf\page\AbstractPage::$templateName + */ + public $templateName = 'chatRoomAdd'; + + /** + * @see \wcf\acp\form\ACPForm::$activeMenuItem + */ + public $activeMenuItem = 'wcf.acp.menu.link.chat.room.list'; + + /** + * @see \wcf\page\AbstractPage::$neededPermissions + */ + public $neededPermissions = array('admin.content.chat.canEditRoom'); + + /** + * room id + * + * @var integer + */ + public $roomID = 0; + + /** + * room object + * + * @var \wcf\data\chat\room\ChatRoom + */ + public $roomObj = null; + + /** + * @see \wcf\page\IPage::readParameters() + */ + public function readParameters() { + parent::readParameters(); + + if (isset($_REQUEST['id'])) $this->roomID = intval($_REQUEST['id']); + $this->roomObj = new \wcf\data\chat\room\ChatRoom($this->roomID); + if (!$this->roomObj->roomID) { + throw new \wcf\system\exception\IllegalLinkException(); + } + } + + /** + * @see \wcf\form\IForm::save() + */ + public function save() { + ACPForm::save(); + + $this->title = 'wcf.chat.room.title'.$this->roomObj->roomID; + if (I18nHandler::getInstance()->isPlainValue('title')) { + I18nHandler::getInstance()->remove($this->title, PackageDependencyHandler::getPackageID('timwolla.wcf.chat')); + $this->title = I18nHandler::getInstance()->getValue('title'); + } + else { + I18nHandler::getInstance()->save('title', $this->title, 'wcf.chat.room', PackageDependencyHandler::getPackageID('timwolla.wcf.chat')); + } + + $this->topic = 'wcf.chat.room.topic'.$this->roomObj->roomID; + if (I18nHandler::getInstance()->isPlainValue('topic')) { + I18nHandler::getInstance()->remove($this->topic, PackageDependencyHandler::getPackageID('timwolla.wcf.chat')); + $this->topic = I18nHandler::getInstance()->getValue('topic'); + } + else { + I18nHandler::getInstance()->save('topic', $this->topic, 'wcf.chat.room', PackageDependencyHandler::getPackageID('timwolla.wcf.chat')); + } + + \wcf\system\acl\ACLHandler::getInstance()->save($this->roomID, $this->objectTypeID); + \wcf\system\chat\permission\ChatPermissionHandler::clearCache(); + + // update room + $this->objectAction = new \wcf\data\chat\room\ChatRoomAction(array($this->roomID), 'update', array('data' => array( + 'title' => $this->title, + 'topic' => $this->topic + ))); + $this->objectAction->executeAction(); + + $this->saved(); + + // show success + WCF::getTPL()->assign(array( + 'success' => true + )); + } + + /** + * @see \wcf\page\IPage::readData() + */ + public function readData() { + parent::readData(); + + if (!count($_POST)) { + I18nHandler::getInstance()->setOptions('title', PackageDependencyHandler::getPackageID('timwolla.wcf.chat'), $this->roomObj->title, 'wcf.chat.room.title\d+'); + I18nHandler::getInstance()->setOptions('topic', PackageDependencyHandler::getPackageID('timwolla.wcf.chat'), $this->roomObj->topic, 'wcf.chat.room.topic\d+'); + + $this->title = $this->roomObj->title; + $this->topic = $this->roomObj->topic; + } + } + + /** + * @see \wcf\page\IPage::assignVariables() + */ + public function assignVariables() { + parent::assignVariables(); + + I18nHandler::getInstance()->assignVariables((bool) count($_POST)); + + WCF::getTPL()->assign(array( + 'roomID' => $this->roomID, + 'action' => 'edit' + )); + } +} \ No newline at end of file diff --git a/file/lib/acp/page/ChatRoomListPage.class.php b/file/lib/acp/page/ChatRoomListPage.class.php new file mode 100644 index 0000000..ac1314a --- /dev/null +++ b/file/lib/acp/page/ChatRoomListPage.class.php @@ -0,0 +1,46 @@ + + * @package timwolla.wcf.chat + * @subpackage acp.page + */ +class ChatRoomListPage extends \wcf\page\MultipleLinkPage { + /** + * @see \wcf\page\AbstractPage::$neededPermissions + */ + public $neededPermissions = array( + 'admin.content.chat.canEditRoom', + 'admin.content.chat.canDeleteRoom' + ); + + /** + * @see \wcf\page\MultipleLinkPage::$objectListClassName + */ + public $objectListClassName = '\wcf\data\chat\room\ChatRoomList'; + + /** + * @see \wcf\page\MultipleLinkPage::$sortField + */ + public $sortField = 'position'; + + /** + * @see \wcf\page\MultipleLinkPage::$sortOrder + */ + public $sortOrder = 'ASC'; + + /** + * @see \wcf\page\IPage::show() + */ + public function show() { + // set active menu item. + \wcf\system\menu\acp\ACPMenu::getInstance()->setActiveMenuItem('wcf.acp.menu.link.chat.room.list'); + + parent::show(); + } +} diff --git a/file/lib/action/ChatLeaveAction.class.php b/file/lib/action/ChatLeaveAction.class.php new file mode 100644 index 0000000..f2f3146 --- /dev/null +++ b/file/lib/action/ChatLeaveAction.class.php @@ -0,0 +1,65 @@ + + * @package timwolla.wcf.chat + * @subpackage action + */ +class ChatLeaveAction extends AbstractAction { + /** + * @see \wcf\action\AbstractAction::$neededModules + */ + public $neededModules = array('CHAT_ACTIVE'); + //public $neededPermissions = array('user.chat.canEnter'); + public $room = null; + public $userData = array(); + + /** + * @see \wcf\action\IAction::execute() + */ + public function execute() { + parent::execute(); + + // validate + if (!WCF::getUser()->userID) { + throw new IllegalLinkException(); + } + + $this->userData['roomID'] = \wcf\util\ChatUtil::readUserData('roomID'); + + $this->room = chat\room\ChatRoom::getCache()->search($this->userData['roomID']); + if (!$this->room) throw new \wcf\system\exception\IllegalLinkException(); + if (!$this->room->canEnter()) throw new \wcf\system\exception\PermissionDeniedException(); + + if (CHAT_DISPLAY_JOIN_LEAVE) { + $this->userData['color'] = \wcf\util\ChatUtil::readUserData('color'); + + $messageAction = new chat\message\ChatMessageAction(array(), 'create', array( + 'data' => array( + 'roomID' => $this->room->roomID, + 'sender' => WCF::getUser()->userID, + 'username' => WCF::getUser()->username, + 'time' => TIME_NOW, + 'type' => chat\message\ChatMessage::TYPE_LEAVE, + 'message' => '', + 'color1' => $this->userData['color'][1], + 'color2' => $this->userData['color'][2] + ) + )); + $messageAction->executeAction(); + } + + \wcf\util\ChatUtil::writeUserData(array('roomID' => null)); + + $this->executed(); + header("HTTP/1.0 204 No Content"); + exit; + } +} diff --git a/file/lib/data/chat/message/ChatMessage.class.php b/file/lib/data/chat/message/ChatMessage.class.php index ebbddfa..f8e5db5 100755 --- a/file/lib/data/chat/message/ChatMessage.class.php +++ b/file/lib/data/chat/message/ChatMessage.class.php @@ -13,12 +13,12 @@ use \wcf\system\WCF; */ class ChatMessage extends \wcf\data\DatabaseObject { /** - * @see wcf\data\DatabaseObject::$databaseTableName + * @see \wcf\data\DatabaseObject::$databaseTableName */ protected static $databaseTableName = 'chat_message'; /** - * @see wcf\data\DatabaseObject::$databaseTableIndexName + * @see \wcf\data\DatabaseObject::$databaseTableIndexName */ protected static $databaseTableIndexName = 'messageID'; @@ -110,7 +110,8 @@ class ChatMessage extends \wcf\data\DatabaseObject { 'time' => $this->time, 'receiver' => $this->receiver, 'type' => $this->type, - 'roomID' => $this->roomID + 'roomID' => $this->roomID, + 'messageID' => $this->messageID ); if ($raw) return $array; diff --git a/file/lib/data/chat/message/ChatMessageAction.class.php b/file/lib/data/chat/message/ChatMessageAction.class.php index 4d6d4ff..fef87e4 100644 --- a/file/lib/data/chat/message/ChatMessageAction.class.php +++ b/file/lib/data/chat/message/ChatMessageAction.class.php @@ -12,7 +12,7 @@ namespace wcf\data\chat\message; */ class ChatMessageAction extends \wcf\data\AbstractDatabaseObjectAction { /** - * @see wcf\data\AbstractDatabaseObjectAction::$className + * @see \wcf\data\AbstractDatabaseObjectAction::$className */ protected $className = '\wcf\data\chat\message\ChatMessageEditor'; } diff --git a/file/lib/data/chat/message/ChatMessageEditor.class.php b/file/lib/data/chat/message/ChatMessageEditor.class.php index abad314..ee54251 100644 --- a/file/lib/data/chat/message/ChatMessageEditor.class.php +++ b/file/lib/data/chat/message/ChatMessageEditor.class.php @@ -12,7 +12,7 @@ namespace wcf\data\chat\message; */ class ChatMessageEditor extends \wcf\data\DatabaseObjectEditor { /** - * @see wcf\data\DatabaseObjectDecorator::$baseClass + * @see \wcf\data\DatabaseObjectDecorator::$baseClass */ protected static $baseClass = '\wcf\data\chat\message\ChatMessage'; diff --git a/file/lib/data/chat/message/ChatMessageList.class.php b/file/lib/data/chat/message/ChatMessageList.class.php index 2f3e01e..bb3853e 100644 --- a/file/lib/data/chat/message/ChatMessageList.class.php +++ b/file/lib/data/chat/message/ChatMessageList.class.php @@ -12,7 +12,7 @@ namespace wcf\data\chat\message; */ class ChatMessageList extends \wcf\data\DatabaseObjectList { /** - * @see wcf\data\DatabaseObjectList::$className + * @see \wcf\data\DatabaseObjectList::$className */ public $className = 'wcf\data\chat\message\ChatMessage'; diff --git a/file/lib/data/chat/room/ChatRoom.class.php b/file/lib/data/chat/room/ChatRoom.class.php index 9193bf0..bc29a31 100644 --- a/file/lib/data/chat/room/ChatRoom.class.php +++ b/file/lib/data/chat/room/ChatRoom.class.php @@ -1,6 +1,7 @@ getTitle(); + } + + /** + * Returns the number of users currently active in this room. + * + * @return integer + */ + public function countUsers() { + $packageID = \wcf\system\package\PackageDependencyHandler::getPackageID('timwolla.wcf.chat'); + + $sql = "SELECT + count(*) as count + FROM + wcf".WCF_N."_user_storage + WHERE + field = 'roomID' + AND packageID = ".intval($packageID)." + AND fieldValue = ".intval($this->roomID); + $stmt = WCF::getDB()->prepareStatement($sql); + $stmt->execute(); + $row = $stmt->fetchArray(); + + return $row['count']; + } + /** * Loads the room cache. */ @@ -37,7 +68,7 @@ class ChatRoom extends \wcf\data\DatabaseObject implements \wcf\system\request\I CacheHandler::getInstance()->addResource( 'chatrooms', WCF_DIR.'cache/cache.chatrooms.php', - 'wcf\system\cache\builder\ChatRoomCacheBuilder' + '\wcf\system\cache\builder\ChatRoomCacheBuilder' ); self::$cache = CacheHandler::getInstance()->get('chatrooms'); } @@ -46,10 +77,12 @@ class ChatRoom extends \wcf\data\DatabaseObject implements \wcf\system\request\I } /** - * @see \wcf\data\chat\room\ChatRoom::getTitle(); + * Returns the ID of this chat-room. + * + * @see \wcf\system\request\IRouteController */ - public function __toString() { - return $this->getTitle(); + public function getID() { + return $this->roomID; } /** @@ -62,12 +95,39 @@ class ChatRoom extends \wcf\data\DatabaseObject implements \wcf\system\request\I } /** - * Returns the ID of this chat-room. - * - * @see \wcf\system\request\RRouteHandler + * Returns the users that are currently active in this room. + * + * @return array<\wcf\data\user\User> */ - public function getID() { - return $this->roomID; + public function getUsers() { + $packageID = \wcf\system\package\PackageDependencyHandler::getPackageID('timwolla.wcf.chat'); + + $sql = "SELECT + userID + FROM + wcf".WCF_N."_user_storage + WHERE + field = 'roomID' + AND packageID = ".intval($packageID)." + AND fieldValue = ".intval($this->roomID); + $stmt = WCF::getDB()->prepareStatement($sql); + $stmt->execute(); + $userIDs = array(); + while ($row = $stmt->fetchArray()) $userIDs[] = $row['userID']; + + if (!count($userIDs)) return; + + $sql = "SELECT + * + FROM + wcf".WCF_N."_user + WHERE + userID IN (".rtrim(str_repeat('?,', count($userIDs)), ',').") + ORDER BY + username ASC"; + $stmt = WCF::getDB()->prepareStatement($sql); + $stmt->execute($userIDs); + return $stmt->fetchObjects('\wcf\data\user\User'); } /** @@ -76,6 +136,8 @@ class ChatRoom extends \wcf\data\DatabaseObject implements \wcf\system\request\I * @return boolean */ public function canEnter() { - return \wcf\system\chat\permissions\ChatPermissionHandler::getInstance()->getPermission($this, 'canEnter'); + $ph = \wcf\system\chat\permission\ChatPermissionHandler::getInstance(); + + return $ph->getPermission($this, 'user.canEnter') || $ph->getPermission($this, 'mod.canAlwaysEnter'); } } diff --git a/file/lib/data/chat/room/ChatRoomAction.class.php b/file/lib/data/chat/room/ChatRoomAction.class.php new file mode 100644 index 0000000..d83f994 --- /dev/null +++ b/file/lib/data/chat/room/ChatRoomAction.class.php @@ -0,0 +1,95 @@ + + * @package timwolla.wcf.chat + * @subpackage data.chat.room + */ +class ChatRoomAction extends \wcf\data\AbstractDatabaseObjectAction { + /** + * @see \wcf\data\AbstractDatabaseObjectAction::$className + */ + protected $className = '\wcf\data\chat\room\ChatRoomEditor'; + + /** + * @see \wcf\data\AbstractDatabaseObjectAction::$permissionsDelete + */ + protected $permissionsDelete = array('admin.content.chat.canDeleteRoom'); + + /** + * @see \wcf\data\AbstractDatabaseObjectAction::$permissionsUpdate + */ + protected $permissionsUpdate = array('admin.content.chat.canEditRoom'); + + /** + * Fixes create to append new boards. + */ + public function create() { + $room = parent::create(); + + WCF::getDB()->beginTransaction(); + $sql = "SELECT max(position) as max + FROM wcf".WCF_N."_chat_room + FOR UPDATE"; + $stmt = WCF::getDB()->prepareStatement($sql); + $stmt->execute(); + $row = $stmt->fetchArray(); + + $sql = "UPDATE wcf".WCF_N."_chat_room + SET position = ".($row['max'] + 1)." + WHERE roomID = ?"; + $stmt = WCF::getDB()->prepareStatement($sql); + $stmt->execute(array($room->roomID)); + WCF::getDB()->commitTransaction(); + + return $room; + } + + /** + * Validates parameters to update sorting. + */ + public function validateUpdatePosition() { + // validate permissions + if (is_array($this->permissionsUpdate) && count($this->permissionsUpdate)) { + try { + WCF::getSession()->checkPermissions($this->permissionsUpdate); + } + catch (\wcf\system\exception\PermissionDeniedException $e) { + throw new ValidateActionException('Insufficient permissions'); + } + } + else { + throw new ValidateActionException('Insufficient permissions'); + } + + if (!isset($this->parameters['data']['structure'])) { + throw new ValidateActionException('Missing parameter structure'); + } + } + + /** + * Updates sorting. + */ + public function updatePosition() { + $roomList = new \wcf\data\chat\room\ChatRoomList(); + $roomList->sqlOrderBy = "chat_room.position"; + $roomList->sqlLimit = 0; + $roomList->readObjects(); + + $i = 0; + WCF::getDB()->beginTransaction(); + foreach ($this->parameters['data']['structure'][0] as $roomID) { + $room = $roomList->search($roomID); + if ($room === null) continue; + $editor = new ChatRoomEditor($room); + $editor->update(array('position' => $i++)); + } + WCF::getDB()->commitTransaction(); + } +} diff --git a/file/lib/data/chat/room/ChatRoomEditor.class.php b/file/lib/data/chat/room/ChatRoomEditor.class.php index 73e0a2a..43216c4 100644 --- a/file/lib/data/chat/room/ChatRoomEditor.class.php +++ b/file/lib/data/chat/room/ChatRoomEditor.class.php @@ -1,5 +1,6 @@ clearResource('chatrooms'); + \wcf\system\cache\CacheHandler::getInstance()->clear(WCF_DIR.'cache', 'cache.chatrooms.php'); + } + + /** + * @see \wcf\data\DatabaseObjectEditor::deleteAll() + */ + public static function deleteAll(array $objectIDs = array()) { + parent::deleteAll($objectIDs); + $packageID = \wcf\system\package\PackageDependencyHandler::getPackageID('timwolla.wcf.chat'); + + WCF::getDB()->beginTransaction(); + foreach ($objectIDs as $objectID) { + \wcf\system\language\I18nHandler::getInstance()->remove('wcf.chat.room.title'.$objectID, $packageID); + \wcf\system\language\I18nHandler::getInstance()->remove('wcf.chat.room.topic'.$objectID, $packageID); + } + WCF::getDB()->commitTransaction(); + + return count($objectIDs); } } diff --git a/file/lib/data/chat/room/ChatRoomList.class.php b/file/lib/data/chat/room/ChatRoomList.class.php index 6a311d7..7e369be 100644 --- a/file/lib/data/chat/room/ChatRoomList.class.php +++ b/file/lib/data/chat/room/ChatRoomList.class.php @@ -12,7 +12,7 @@ namespace wcf\data\chat\room; */ class ChatRoomList extends \wcf\data\DatabaseObjectList { /** - * @see wcf\data\DatabaseObjectList::$className + * @see \wcf\data\DatabaseObjectList::$className */ public $className = 'wcf\data\chat\room\ChatRoom'; } diff --git a/file/lib/form/ChatForm.class.php b/file/lib/form/ChatForm.class.php index 32e9d54..554f5a3 100644 --- a/file/lib/form/ChatForm.class.php +++ b/file/lib/form/ChatForm.class.php @@ -1,15 +1,14 @@ * @package timwolla.wcf.chat @@ -20,10 +19,14 @@ class ChatForm extends AbstractForm { public $message = ''; public $room = null; public $userData = array(); + + /** + * @see \wcf\page\AbstractForm::$useTemplate + */ public $useTemplate = false; /** - * @see \wcf\page\AbstractPage::readData() + * @see \wcf\page\IPage::readData() */ public function readData() { $this->userData['color'] = \wcf\util\ChatUtil::readUserData('color'); @@ -37,17 +40,17 @@ class ChatForm extends AbstractForm { } /** - * @see \wcf\form\AbstractForm::readFormParameters() + * @see \wcf\form\IForm::readFormParameters() */ public function readFormParameters() { parent::readFormParameters(); - if (isset($_REQUEST['text'])) $this->message = StringUtil::trim($_REQUEST['text']); + if (isset($_REQUEST['text'])) $this->message = \wcf\util\MessageUtil::stripCrap(StringUtil::trim($_REQUEST['text'])); if (isset($_REQUEST['smilies'])) $this->enableSmilies = intval($_REQUEST['smilies']); } /** - * @see \wcf\form\AbstractForm::validate() + * @see \wcf\form\IForm::validate() */ public function validate() { parent::validate(); @@ -55,10 +58,14 @@ class ChatForm extends AbstractForm { if ($this->message === '') { throw new UserInputException('text'); } + + if (strlen($this->message) > CHAT_MAX_LENGTH) { + throw new UserInputException('text', 'tooLong'); + } } /** - * @see \wcf\form\AbstractForm::save() + * @see \wcf\form\IForm::save() */ public function save() { parent::save(); @@ -107,4 +114,12 @@ class ChatForm extends AbstractForm { $this->saved(); } + + /** + * @see \wcf\page\IPage::show() + */ + public function show() { + header("HTTP/1.0 204 No Content"); + parent::show(); + } } diff --git a/file/lib/page/ChatMessagePage.class.php b/file/lib/page/ChatMessagePage.class.php index 873e95a..4b1a5d9 100644 --- a/file/lib/page/ChatMessagePage.class.php +++ b/file/lib/page/ChatMessagePage.class.php @@ -22,14 +22,14 @@ class ChatMessagePage extends AbstractPage { public $useTemplate = false; /** - * @see \wcf\page\Page::readData() + * @see \wcf\page\Page::readData() */ public function readData() { parent::readData(); $this->readRoom(); $this->readMessages(); - $this->readUsers(); + $this->users = $this->room->getUsers(); } public function readMessages() { @@ -54,34 +54,6 @@ class ChatMessagePage extends AbstractPage { if (!$this->room->canEnter()) throw new \wcf\system\exception\PermissionDeniedException(); } - public function readUsers() { - $packageID = \wcf\system\package\PackageDependencyHandler::getPackageID('timwolla.wcf.chat'); - - $sql = "SELECT - userID - FROM - wcf".WCF_N."_user_storage - WHERE - field = 'roomID' - AND packageID = ".intval($packageID)." - AND fieldValue = ".intval($this->roomID); - $stmt = WCF::getDB()->prepareStatement($sql); - $stmt->execute(); - while ($row = $stmt->fetchArray()) $userIDs[] = $row['userID']; - - $sql = "SELECT - * - FROM - wcf".WCF_N."_user - WHERE - userID IN (".rtrim(str_repeat('?,', count($userIDs)), ',').") - ORDER BY - username ASC"; - $stmt = WCF::getDB()->prepareStatement($sql); - $stmt->execute($userIDs); - $this->users = $stmt->fetchObjects('\wcf\data\user\User'); - } - /** * @see \wcf\page\IPage::show() */ @@ -94,6 +66,11 @@ class ChatMessagePage extends AbstractPage { parent::show(); @header('Content-type: application/json'); + // enable gzip compression + if (HTTP_ENABLE_GZIP && HTTP_GZIP_LEVEL > 0 && HTTP_GZIP_LEVEL < 10 && !defined('HTTP_DISABLE_GZIP')) { + \wcf\util\HeaderUtil::compressOutput(); + } + $json = array('users' => array(), 'messages' => array()); foreach ($this->messages as $message) { diff --git a/file/lib/page/ChatPage.class.php b/file/lib/page/ChatPage.class.php index d7dbe78..0023607 100644 --- a/file/lib/page/ChatPage.class.php +++ b/file/lib/page/ChatPage.class.php @@ -105,25 +105,24 @@ class ChatPage extends AbstractPage { public function readParameters() { parent::readParameters(); - if ($this->action == 'Message') { - new ChatMessagePage(); - exit; - } - else if ($this->action == 'Log') { - //TODO: Initialise LogPage - exit; - } - else if ($this->action == 'RefreshRoomList') { - new ChatRefreshRoomListPage(); - exit; - } - else if ($this->action == 'Send') { - new \wcf\form\ChatForm(); - exit; - } - else if ($this->action == 'Copyright') { - new ChatCopyrightPage(); - exit; + switch ($this->action) { + case 'Message': + new ChatMessagePage(); + exit; + case 'Log': + exit; + case 'RefreshRoomList': + new ChatRefreshRoomListPage(); + exit; + case 'Send': + new \wcf\form\ChatForm(); + exit; + case 'Leave': + new \wcf\action\ChatLeaveAction(); + exit; + case 'Copyright': + new ChatCopyrightPage(); + exit; } if (isset($_REQUEST['id'])) $this->roomID = (int) $_REQUEST['id']; diff --git a/file/lib/system/cache/builder/ChatPermissionCacheBuilder.class.php b/file/lib/system/cache/builder/ChatPermissionCacheBuilder.class.php new file mode 100644 index 0000000..947b05b --- /dev/null +++ b/file/lib/system/cache/builder/ChatPermissionCacheBuilder.class.php @@ -0,0 +1,44 @@ + + * @package timwolla.wcf.chat + * @subpackage system.cache.builder + */ +class ChatPermissionCacheBuilder implements ICacheBuilder { + /** + * @see wcf\system\cache\ICacheBuilder::getData() + */ + public function getData(array $cacheResource) { + $data = array(); + list(, $groupIDsStr) = explode('-', $cacheResource['cache']); + $groupIDs = explode(',', $groupIDsStr); + + if (count($groupIDs)) { + $conditionBuilder = new \wcf\system\database\util\PreparedStatementConditionBuilder(); + $conditionBuilder->add('acl_option.packageID IN (?)', array(\wcf\system\package\PackageDependencyHandler::getDependencies())); + $conditionBuilder->add('acl_option.objectTypeID = ?', array(\wcf\system\acl\ACLHandler::getInstance()->getObjectTypeID('timwolla.wcf.chat.room'))); + $conditionBuilder->add('option_to_group.optionID = acl_option.optionID'); + $conditionBuilder->add('option_to_group.groupID IN (?)', array($groupIDs)); + $sql = "SELECT option_to_group.groupID, option_to_group.objectID AS roomID, option_to_group.optionValue, + acl_option.optionName AS permission + FROM wcf".WCF_N."_acl_option acl_option, + wcf".WCF_N."_acl_option_to_group option_to_group + ".$conditionBuilder; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute($conditionBuilder->getParameters()); + while ($row = $statement->fetchArray()) { + if (!isset($data[$row['roomID']][$row['permission']])) $data[$row['roomID']][$row['permission']] = $row['optionValue']; + else $data[$row['roomID']][$row['permission']] = $row['optionValue'] || $data[$row['roomID']][$row['permission']]; + } + } + + return $data; + } +} \ No newline at end of file diff --git a/file/lib/system/cache/builder/ChatRoomCacheBuilder.class.php b/file/lib/system/cache/builder/ChatRoomCacheBuilder.class.php index c21267f..985d823 100644 --- a/file/lib/system/cache/builder/ChatRoomCacheBuilder.class.php +++ b/file/lib/system/cache/builder/ChatRoomCacheBuilder.class.php @@ -12,7 +12,7 @@ namespace wcf\system\cache\builder; */ class ChatRoomCacheBuilder implements ICacheBuilder { /** - * @see wcf\system\cache\ICacheBuilder::getData() + * @see \wcf\system\cache\ICacheBuilder::getData() */ public function getData(array $cacheResource) { // get all chat rooms diff --git a/file/lib/system/chat/permissions/ChatPermissionHandler.class.php b/file/lib/system/chat/permission/ChatPermissionHandler.class.php similarity index 70% rename from file/lib/system/chat/permissions/ChatPermissionHandler.class.php rename to file/lib/system/chat/permission/ChatPermissionHandler.class.php index d525b9e..fc3e79e 100644 --- a/file/lib/system/chat/permissions/ChatPermissionHandler.class.php +++ b/file/lib/system/chat/permission/ChatPermissionHandler.class.php @@ -1,6 +1,7 @@ true, + 'user.canWrite' => true, + 'mod.canAlwaysEnter' => false, + 'mod.canAlwaysWrite' => false + ); /** - * @see wcf\system\SingletonFactory::init() + * @see \wcf\system\SingletonFactory::init() */ protected function init() { $packageID = PackageDependencyHandler::getPackageID('timwolla.wcf.chat'); $ush = \wcf\system\user\storage\UserStorageHandler::getInstance(); - // TODO: get groups permissions + + // get groups permissions + $groups = implode(',', WCF::getUser()->getGroupIDs()); + $groupsFileName = \wcf\util\StringUtil::getHash(implode('-', WCF::getUser()->getGroupIDs())); + CacheHandler::getInstance()->addResource('chatPermission-'.$groups, WCF_DIR.'cache/cache.chatPermission-'.$groupsFileName.'.php', 'wcf\system\cache\builder\ChatPermissionCacheBuilder'); + $this->chatPermissions = CacheHandler::getInstance()->get('chatPermission-'.$groups); // get user permissions if (WCF::getUser()->userID) { @@ -75,7 +87,20 @@ class ChatPermissionHandler extends \wcf\system\SingletonFactory { * @return boolean */ public function getPermission(\wcf\data\chat\room\ChatRoom $room, $permission) { - if (!isset($this->chatPermissions[$room->roomID][$permission])) return true; + if (!isset($this->chatPermissions[$room->roomID][$permission])) { + return isset(self::$defaults[$permission]) ? self::$defaults[$permission] : false; + } return (boolean) $this->chatPermissions[$room->roomID][$permission]; } + + /** + * Clears the cache. + */ + public static function clearCache() { + $packageID = PackageDependencyHandler::getPackageID('timwolla.wcf.chat'); + $ush = \wcf\system\user\storage\UserStorageHandler::getInstance(); + + $ush->resetAll('chatUserPermissions', $packageID); + \wcf\system\cache\CacheHandler::getInstance()->clear(WCF_DIR.'cache', 'cache.chatPermission-[a-f0-9]{40}.php'); + } } \ No newline at end of file diff --git a/file/lib/system/event/listener/ChatRouteListener.class.php b/file/lib/system/event/listener/ChatRouteListener.class.php index 991bb35..7b6ee57 100644 --- a/file/lib/system/event/listener/ChatRouteListener.class.php +++ b/file/lib/system/event/listener/ChatRouteListener.class.php @@ -8,17 +8,17 @@ namespace wcf\system\event\listener; * @copyright 2010-2012 Tim Düsterhus * @license Creative Commons Attribution-NonCommercial-ShareAlike * @package timwolla.wcf.chat - * @subpackage system.event.listener + * @subpackage system.event.listener */ class ChatRouteListener implements \wcf\system\event\IEventListener { /** - * @see wcf\system\event\IEventListener::execute() + * @see \wcf\system\event\IEventListener::execute() */ public function execute($eventObj, $className, $eventName) { $route = new \wcf\system\request\Route('chatAction'); $route->setSchema('/{controller}/{action}'); $route->setParameterOption('controller', null, 'Chat'); - $route->setParameterOption('action', null, '(Message|Log|Send|RefreshRoomList|Copyright)'); + $route->setParameterOption('action', null, '(Message|Log|Send|RefreshRoomList|Copyright|Leave)'); $eventObj->addRoute($route); } } diff --git a/file/lib/system/menu/page/ChatPageMenuItemProvider.class.php b/file/lib/system/menu/page/ChatPageMenuItemProvider.class.php index 978c956..e38a136 100644 --- a/file/lib/system/menu/page/ChatPageMenuItemProvider.class.php +++ b/file/lib/system/menu/page/ChatPageMenuItemProvider.class.php @@ -17,7 +17,7 @@ class ChatPageMenuItemProvider extends DefaultPageMenuItemProvider { /** * Hides the button when there is no valid room * - * @see \wcf\system\menu\page\PageMenuItemProvider::isVisible() + * @see \wcf\system\menu\page\PageMenuItemProvider::isVisible() */ public function isVisible() { // guests are not supported @@ -43,7 +43,7 @@ class ChatPageMenuItemProvider extends DefaultPageMenuItemProvider { /** * Modifies the link to show the Link we would be redirect to. * - * @see \wcf\system\menu\page\PageMenuItemProvider::getLink() + * @see \wcf\system\menu\page\PageMenuItemProvider::getLink() */ public function getLink() { return \wcf\system\request\LinkHandler::getInstance()->getLink('Chat', array( diff --git a/file/lib/system/option/TimeIntervalOptionType.class.php b/file/lib/system/option/TimeIntervalOptionType.class.php index 7f35c22..68421af 100644 --- a/file/lib/system/option/TimeIntervalOptionType.class.php +++ b/file/lib/system/option/TimeIntervalOptionType.class.php @@ -12,14 +12,14 @@ namespace wcf\system\option; */ class TimeIntervalOptionType extends TextOptionType { /** - * @see wcf\system\option\IOptionType::getData() + * @see \wcf\system\option\IOptionType::getData() */ public function getData(\wcf\data\option\Option $option, $newValue) { return \wcf\util\ChatUtil::timeModifier($newValue); } /** - * @see wcf\system\option\TextOptionType::getFormElement() + * @see \wcf\system\option\TextOptionType::getFormElement() */ public function getFormElement(\wcf\data\option\Option $option, $value) { $tmp = (int) ($value / 60); diff --git a/file/lib/util/ChatUtil.class.php b/file/lib/util/ChatUtil.class.php index 2cfde2c..1be6657 100644 --- a/file/lib/util/ChatUtil.class.php +++ b/file/lib/util/ChatUtil.class.php @@ -67,7 +67,7 @@ class ChatUtil { if ($data[WCF::getUser()->userID] === null) { switch ($field) { case 'color': - $data[WCF::getUser()->userID] = array(1 => 0xFF0000, 2 => 0x00FF00); + $data[WCF::getUser()->userID] = array(1 => self::getRandomNumber(), 2 => self::getRandomNumber() * 0xFFFF); break; } static::writeUserData(array($field => $data[WCF::getUser()->userID])); @@ -79,6 +79,16 @@ class ChatUtil { else return $data[WCF::getUser()->userID]; } + /** + * Returns a random number. + * + * @return integer + */ + public static function /* int */ getRandomNumber() { + return 4; // chosen by a fair dice roll + // guaranteed to be random + } + /** * Writes user data * diff --git a/file/style/timwolla.wcf.chat.scss b/file/style/timwolla.wcf.chat.scss index 916840d..6445270 100644 --- a/file/style/timwolla.wcf.chat.scss +++ b/file/style/timwolla.wcf.chat.scss @@ -11,7 +11,7 @@ text-align: left; } -.sidebar { +.wcf-sidebar { margin-bottom: -20px !important; overflow: auto; padding: 0; @@ -32,7 +32,7 @@ } } -#timsChatTopic, #smileyList, #timsChatOptions { +#timsChatTopic, #smileyList { padding: 5px; } @@ -43,7 +43,7 @@ padding-left: 7px !important; } -#smileyList .smilies, .smallButtons { +#smileyList .smilies { li { display: inline; margin: 5px 5px 0 0; @@ -63,7 +63,9 @@ } #timsChatOptions { - display: inline-block; + > ul { + text-align: right; + } } #timsChatUserList { @@ -100,7 +102,7 @@ } } - .unloaded { + &.unloaded { opacity: 0.4; } } @@ -178,7 +180,7 @@ } } - &.active .badge { + &.active .wcf-badge { font-size: 65% !important; color: #fff; background-color: #369; diff --git a/install.sql b/install.sql index 21aa183..0a3219d 100644 --- a/install.sql +++ b/install.sql @@ -1,46 +1,47 @@ DROP TABLE IF EXISTS wcf1_chat_message; CREATE TABLE wcf1_chat_message ( - messageID int(10) NOT NULL AUTO_INCREMENT, - roomID int(10) NOT NULL, - sender int(10) DEFAULT NULL, - username varchar(255) DEFAULT NULL, - receiver int(10) DEFAULT NULL, - time int(10) NOT NULL, - type tinyint(3) NOT NULL DEFAULT 1, - message mediumtext NOT NULL, - enableSmilies tinyint(1) NOT NULL DEFAULT 1, - enableHTML tinyint(1) NOT NULL DEFAULT 0, - color1 int(10) NOT NULL DEFAULT 0, - color2 int(10) NOT NULL DEFAULT 0, - PRIMARY KEY (messageID), - KEY roomID (roomID), - KEY sender (sender), - KEY receiver (receiver) + messageID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY, + roomID INT(10) NOT NULL, + sender INT(10) DEFAULT NULL, + username VARCHAR(255) DEFAULT NULL, + receiver INT(10) DEFAULT NULL, + time INT(10) NOT NULL, + type TINYINT(3) NOT NULL DEFAULT 1, + message MEDIUMTEXT NOT NULL, + enableSmilies TINYINT(1) NOT NULL DEFAULT 1, + enableHTML TINYINT(1) NOT NULL DEFAULT 0, + color1 INT(10) NOT NULL DEFAULT 0, + color2 INT(10) NOT NULL DEFAULT 0, + + KEY roomID (roomID), + KEY sender (sender), + KEY receiver (receiver) ); DROP TABLE IF EXISTS wcf1_chat_room; CREATE TABLE wcf1_chat_room ( - roomID int(10) NOT NULL AUTO_INCREMENT, - title varchar(25) NOT NULL, - topic varchar(255) NOT NULL, - position int(10) NOT NULL DEFAULT 0, - permanent tinyint(1) NOT NULL DEFAULT 1, - owner int(10) DEFAULT NULL, - PRIMARY KEY (roomID), - KEY positionKey (position), - KEY owner (owner) + roomID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(255) NOT NULL, + topic VARCHAR(255) NOT NULL, + position INT(10) NOT NULL DEFAULT 0, + permanent TINYINT(1) NOT NULL DEFAULT 1, + owner INT(10) DEFAULT NULL, + + KEY positionKey (position), + KEY owner (owner) ); DROP TABLE IF EXISTS wcf1_chat_room_suspension; CREATE TABLE wcf1_chat_room_suspension ( - roomID int(10) NOT NULL, - userID int(10) NOT NULL, - type tinyint(3) NOT NULL, - time int(10) NOT NULL, - PRIMARY KEY (roomID, userID), - KEY userID (userID), - KEY type (type, time), - KEY time (time) + userID INT(10) NOT NULL, + roomID INT(10) DEFAULT NULL, + type TINYINT(3) NOT NULL, + time INT(10) NOT NULL, + + UNIQUE KEY main (userID, roomID), + KEY roomID (roomID), + KEY type (type, time), + KEY time (time) ); ALTER TABLE wcf1_chat_message ADD FOREIGN KEY (receiver) REFERENCES wcf1_user (userID) ON DELETE CASCADE; @@ -52,7 +53,7 @@ ALTER TABLE wcf1_chat_room ADD FOREIGN KEY (owner) REFERENCES wcf1_user (userID) ALTER TABLE wcf1_chat_room_suspension ADD FOREIGN KEY (userID) REFERENCES wcf1_user (userID) ON DELETE CASCADE; ALTER TABLE wcf1_chat_room_suspension ADD FOREIGN KEY (roomID) REFERENCES wcf1_chat_room (roomID) ON DELETE CASCADE; -INSERT INTO wcf1_chat_room (title, topic, position) VALUES ('Testroom 1', 'Topic of Testroom 1', 1); +INSERT INTO wcf1_chat_room (title, topic, position) VALUES ('wcf.chat.room.title1', 'wcf.chat.room.topic1', 1); INSERT INTO wcf1_chat_room (title, topic, position) VALUES ('Testroom 2', 'Topic of Testroom 2', 2); INSERT INTO wcf1_chat_room (title, topic, position) VALUES ('Testroom with a very long', 'The topic of this room is rather loing as well!', 3); INSERT INTO wcf1_chat_room (title, topic, position) VALUES ('Room w/o topic', '', 4); diff --git a/language/de.xml b/language/de.xml index 5330609..768f216 100644 --- a/language/de.xml +++ b/language/de.xml @@ -1,5 +1,17 @@ + + + + + + + + + + + + @@ -14,8 +26,8 @@ - - + + @@ -24,11 +36,7 @@ - - - - - + @@ -55,4 +63,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/option.xml b/option.xml index 13418c2..b491edd 100644 --- a/option.xml +++ b/option.xml @@ -49,7 +49,7 @@ 1 7 -