1
0
mirror of https://github.com/wbbaddons/Tims-Chat.git synced 2025-01-04 23:40:08 +00:00

Merge branch 'attachments'

This commit is contained in:
Maximilian Mader 2013-11-09 14:01:51 +01:00
commit 71dabf35fa
16 changed files with 528 additions and 33 deletions

View File

@ -37,6 +37,7 @@ exposed by a function if necessary.
current: {} current: {}
allTime: {} allTime: {}
currentRoom = {} currentRoom = {}
fileUploaded = no
errorVisible = false errorVisible = false
inputErrorHidingTimer = null inputErrorHidingTimer = null
@ -643,7 +644,7 @@ Fetch the roomlist from the server and update it in the GUI.
for room in data.returnValues for room in data.returnValues
li = $ '<li></li>' li = $ '<li></li>'
li.addClass 'active' if room.active li.addClass 'active' if room.active
$("""<a href="#{room.link}">#{room.title} <span class="badge">#{WCF.String.formatNumeric room.userCount}</span></a>""").addClass('timsChatRoom').data('roomID', room.roomID).appendTo li $("""<a href="#{room.link}">#{WCF.String.escapeHTML(room.title)} <span class="badge">#{WCF.String.formatNumeric room.userCount}</span></a>""").addClass('timsChatRoom').data('roomID', room.roomID).appendTo li
$('#timsChatRoomList ul').append li $('#timsChatRoomList ul').append li
if window.history?.replaceState? if window.history?.replaceState?
@ -741,7 +742,7 @@ Open private channel
if userID isnt 0 if userID isnt 0
$('#timsChatTopic').removeClass 'hidden empty' $('#timsChatTopic').removeClass 'hidden empty'
$('#timsChatTopic > .topic').text WCF.Language.get 'chat.general.privateChannelTopic', {username: userList.allTime[userID].username} $('#timsChatTopic > .topic').html WCF.Language.get 'chat.general.privateChannelTopic', {username: userList.allTime[userID].username}
$('#timsChatTopic > .jsTopicCloser').attr 'title', WCF.Language.get 'chat.general.closePrivateChannel' $('#timsChatTopic > .jsTopicCloser').attr 'title', WCF.Language.get 'chat.general.closePrivateChannel'
unless $.wcfIsset "privateChannel#{userID}" unless $.wcfIsset "privateChannel#{userID}"
@ -810,6 +811,221 @@ Remove the given callback from the given event.
true true
The following code handles attachment uploads
Enable attachment code if `WCF.Attachment.Upload` is defined
if WCF?.Attachment?.Upload? and $('#timsChatUploadContainer').length
Attachment = WCF.Attachment.Upload.extend
fileUploaded: no
Initialize WCF.Attachment.Upload
See WCF.Attachment.Upload.init()
init: ->
@_super $('#timsChatUploadContainer'), $(false), 'be.bastelstu.chat.message', 0, 0, 0, 1, null
unless @_supportsAJAXUpload
$('#timsChatUploadDropdownMenu .uploadButton').click => do @_showOverlay
label = $ '#timsChatUploadDropdownMenu li > span > label'
parent = do label.parent
css = parent.css ['padding-top', 'padding-right', 'padding-bottom', 'padding-left']
label.css css
label.css 'margin', "-#{css['padding-top']} -#{css['padding-right']} -#{css['padding-bottom']} -#{css['padding-left']}"
$('#timsChatUpload').click ->
$('#timsChatUpload > span.icon-ban-circle').removeClass('icon-ban-circle').addClass 'icon-paper-clip'
do $('#timsChatUploadContainer .innerError').remove
Overwrite WCF.Attachment.Upload._createButton() to create the upload button as small button into a button group
_createButton: ->
if @_supportsAJAXUpload
@_fileUpload = $ """<input id="timsChatUploadInput" type="file" name="#{@_name}" />"""
@_fileUpload.change => do @_upload
@_fileUpload.appendTo 'body'
_removeButton: ->
do @_fileUpload.remove
See WCF.Attachment.Upload._getParameters()
_getParameters: ->
@_tmpHash = do Math.random
@_parentObjectID = currentRoom.roomID
do @_super
_upload: ->
files = @_fileUpload.prop 'files'
if files.length
$('#timsChatUpload > span.icon').removeClass('icon-paper-clip icon-ban-circle').addClass('icon-spinner')
do @_super
Create a message containing the uploaded attachment
_insert: (event) ->
objectID = $(event.currentTarget).data 'objectID'
new WCF.Action.Proxy
autoSend: true
data:
actionName: 'sendAttachment'
className: 'chat\\data\\message\\MessageAction'
parameters:
objectID: objectID
tmpHash: @_tmpHash
parentObjectID: 1#@_parentObjectID
showLoadingOverlay: false
success: ->
do $('#timsChatUploadDropdownMenu .jsDeleteButton').parent().remove
do $('#timsChatUploadDropdownMenu .sendAttachmentButton').remove
do $('#timsChatUploadDropdownMenu .uploadButton').show
$('#timsChatUpload > span.icon').removeClass('icon-ok-sign').addClass 'icon-paper-clip'
fileUploaded = no
failure: (data) ->
false
_initFile: (file) ->
li = $("""<li class="uploadProgress">
<span>
<progress max="100"></progress>
</span>
</li>"""
).data('filename', file.name)
$('#timsChatUploadDropdownMenu').append li
do $('#timsChatUploadDropdownMenu .uploadButton').hide
# validate file size
if @_buttonSelector.data('maxSize') < file.size
# remove progress bar
do li.find('progress').remove
# upload icon
$('#timsChatUpload > span.icon-spinner').removeClass('icon-spinner').addClass 'icon-ban-circle'
# error message
$('#timsChatUpload').addClass('uploadFailed').after """<small class="innerError">#{WCF.Language.get('wcf.attachment.upload.error.tooLarge')}</small>"""
do @_error
li.addClass 'uploadFailed'
li
_validateLimit: ->
innerError = @_buttonSelector.next 'small.innerError'
if fileUploaded
# reached limit
unless innerError.length
innerError = $('<small class="innerError" />').insertAfter '#timsChatUpload'
innerError.html WCF.Language.get('wcf.attachment.upload.error.reachedLimit')
innerError.css 'position', 'absolute'
return false
# remove previous errors
do innerError.remove
true
_success: (uploadID, data) ->
for li in @_uploadMatrix[uploadID]
do li.find('progress').remove
li.removeClass('uploadProgress').addClass 'sendAttachmentButton'
li.find('span').addClass('box32').append """
<div class="framed attachmentImageContainer">
<span class="attachmentTinyThumbnail icon icon32 icon-paper-clip"></span>
</div>
<div class="containerHeaderline">
<p></p>
<small></small>
<p>#{WCF.Language.get('wcf.global.button.submit')}</p>
</div>"""
li.click (event) => @_insert(event)
filename = li.data 'filename'
internalFileID = li.data 'internalFileID'
if data.returnValues and data.returnValues.attachments[internalFileID]
if data.returnValues.attachments[internalFileID].tinyURL
li.find('.box32 > div.attachmentImageContainer > .icon-paper-clip').replaceWith $("""<img src="#{data.returnValues.attachments[internalFileID].tinyURL}'" alt="" class="attachmentTinyThumbnail" style="width: 32px; height: 32px;" />""")
link = $ '<a href="" class="jsTooltip"></a>'
link.attr {'href': data.returnValues.attachments[internalFileID].url, 'title': filename}
unless parseInt(data.returnValues.attachments[internalFileID].isImage) is 0
link.addClass('jsImageViewer')
if !data.returnValues.attachments[internalFileID].tinyURL
li.find('.box32 > div.attachmentImageContainer > .icon-paper-clip').replaceWith $("""<img src="#{data.returnValues.attachments[internalFileID].url}'" alt="" class="attachmentTinyThumbnail" style="width: 32px; height: 32px;" />""")
li.find('.attachmentTinyThumbnail').wrap link
li.find('small').append data.returnValues.attachments[internalFileID].formattedFilesize
li.data 'objectID', data.returnValues.attachments[internalFileID].attachmentID
deleteButton = $ """
<li>
<span class="jsDeleteButton" data-object-id="#{data.returnValues.attachments[internalFileID].attachmentID}" data-confirm-message="#{WCF.Language.get('wcf.attachment.delete.sure')}">
<span class="icon icon16 icon-remove pointer jsTooltip" />
<span>#{WCF.Language.get('wcf.global.button.delete')}</span>
</span>
</li>"""
li.parent().append deleteButton
fileUploaded = yes
else
$('#timsChatUpload .icon-spinner').removeClass('icon-spinner').addClass 'icon-ban-circle'
if data.returnValues and data.returnValues.errors[internalFileID]
errorMessage = data.returnValues.errors[internalFileID].errorType
else
errorMessage = 'uploadFailed'
$('#timsChatUpload').addClass('uploadFailed').after """<small class="innerError">#{WCF.Language.get('wcf.attachment.upload.error.' + errorMessage)}</small>"""
do $('#timsChatUploadDropdownMenu .sendAttachmentButton').remove
do $('#timsChatUploadDropdownMenu .uploadButton').show
fileUploaded = no
do WCF.DOMNodeInsertedHandler.execute
$('#timsChatUpload > span.icon').removeClass('icon-spinner').addClass 'icon-ok-sign'
do $('#timsChatUploadDropdownMenu .uploadProgress').remove
do $('#timsChatUploadDropdownMenu .sendAttachmentButton').show
_error: (jqXHR, textStatus, errorThrown) ->
$('#timsChatUpload > .icon-spinner').removeClass('icon-spinner').addClass 'icon-ban-circle'
unless $('#timsChatUpload').hasClass('uploadFailed')
$('#timsChatUpload').addClass('uploadFailed').after """<small class="innerError">#{WCF.Language.get('wcf.attachment.upload.error.uploadFailed')}</small>"""
do $('#timsChatUploadDropdownMenu .uploadProgress').remove
do $('#timsChatUploadDropdownMenu .uploadButton').show
fileUploaded = no
Action = {}
Action.Delete = WCF.Action.Delete.extend
triggerEffect: (objectIDs) ->
for index in @_containers
container = $ "##{index}"
if WCF.inArray container.find(@_buttonSelector).data('objectID'), objectIDs
self = @
container.wcfBlindOut 'up', (event) ->
parent = do $(@).parent
do $(@).remove
do parent.find('.sendAttachmentButton').remove
do parent.find('.uploadButton').show
$('#timsChatUpload > .icon-ok-sign').removeClass('icon-ok-sign').addClass 'icon-paper-clip'
self._containers.splice(self._containers.indexOf $(@).wcfIdentify(), 1)
self._didTriggerEffect($ @)
fileUploaded = no
return
And finally export the public methods and variables. And finally export the public methods and variables.
Chat = Chat =
@ -822,6 +1038,8 @@ And finally export the public methods and variables.
listener: listener:
add: addListener add: addListener
remove: removeListener remove: removeListener
Chat.Attachment = Attachment if Attachment?
Chat.Action = Action if Attachment?
window.be ?= {} window.be ?= {}
be.bastelstu ?= {} be.bastelstu ?= {}

View File

@ -1,6 +1,7 @@
<?php <?php
namespace chat\data\message; namespace chat\data\message;
use \chat\util\ChatUtil; use \chat\util\ChatUtil;
use \wcf\system\bbcode\AttachmentBBCode;
use \wcf\system\Regex; use \wcf\system\Regex;
use \wcf\system\WCF; use \wcf\system\WCF;
@ -36,6 +37,7 @@ class Message extends \chat\data\CHATDatabaseObject {
const TYPE_CLEAR = 9; const TYPE_CLEAR = 9;
const TYPE_TEAM = 10; const TYPE_TEAM = 10;
const TYPE_GLOBALMESSAGE = 11; const TYPE_GLOBALMESSAGE = 11;
const TYPE_ATTACHMENT = 12;
/** /**
* cache for users * cache for users
@ -87,6 +89,16 @@ public function getFormattedMessage($type = 'text/html') {
$message = $messageParser->parse($message, false, false, true, false); $message = $messageParser->parse($message, false, false, true, false);
break; break;
case self::TYPE_ATTACHMENT:
$attachmentList = new \wcf\data\attachment\GroupedAttachmentList('be.bastelstu.chat.message');
$attachmentList->getConditionBuilder()->add('attachment.objectID IN (?)', array($this->messageID));
$attachmentList->readObjects();
AttachmentBBCode::setAttachmentList($attachmentList);
AttachmentBBCode::setObjectID($this->messageID);
$message = $messageParser->parse($message, false, false, true, false);
break;
case self::TYPE_WHISPER: case self::TYPE_WHISPER:
case self::TYPE_NORMAL: case self::TYPE_NORMAL:
case self::TYPE_ME: case self::TYPE_ME:
@ -137,7 +149,7 @@ public function jsonify($raw = false) {
$array = array( $array = array(
'formattedUsername' => $this->getUsername(true), 'formattedUsername' => $this->getUsername(true),
'formattedMessage' => $this->getFormattedMessage(), 'formattedMessage' => $this->getFormattedMessage('text/html'),
'formattedTime' => \wcf\util\DateUtil::format(\wcf\util\DateUtil::getDateTimeByTimestamp($this->time), 'H:i:s'), 'formattedTime' => \wcf\util\DateUtil::format(\wcf\util\DateUtil::getDateTimeByTimestamp($this->time), 'H:i:s'),
'separator' => $separator, 'separator' => $separator,
'message' => $this->getFormattedMessage('text/plain'), 'message' => $this->getFormattedMessage('text/plain'),

View File

@ -197,4 +197,73 @@ public function validateGetMessages() {
$this->parameters['room'] = room\RoomCache::getInstance()->getRoom($this->parameters['roomID']); $this->parameters['room'] = room\RoomCache::getInstance()->getRoom($this->parameters['roomID']);
if ($this->parameters['room'] === null) throw new \wcf\system\exception\IllegalLinkException(); if ($this->parameters['room'] === null) throw new \wcf\system\exception\IllegalLinkException();
} }
public function validateSendAttachment() {
// read user data
$this->parameters['userData']['color1'] = WCF::getUser()->chatColor1;
$this->parameters['userData']['color2'] = WCF::getUser()->chatColor2;
$this->parameters['userData']['roomID'] = WCF::getUser()->chatRoomID;
$this->parameters['userData']['away'] = WCF::getUser()->chatAway;
// read and validate room
$this->parameters['room'] = room\RoomCache::getInstance()->getRoom($this->parameters['userData']['roomID']);
if ($this->parameters['room'] === null) throw new \wcf\system\exception\IllegalLinkException();
if (!$this->parameters['room']->canEnter()) throw new \wcf\system\exception\PermissionDeniedException();
if (!$this->parameters['room']->canWrite()) throw new \wcf\system\exception\PermissionDeniedException();
$this->readInteger('objectID');
if (!$this->parameters['objectID']) throw new \wcf\system\exception\IllegalLinkException();
$this->readInteger('parentObjectID');
if (!$this->parameters['parentObjectID']) throw new \wcf\system\exception\IllegalLinkException();
$editor = new \wcf\data\user\UserEditor(WCF::getUser());
$editor->update(array(
'chatAway' => null,
'chatLastActivity' => TIME_NOW
));
// mark user as back
if ($this->parameters['userData']['away'] !== null) {
$messageAction = new MessageAction(array(), 'create', array(
'data' => array(
'roomID' => $this->parameters['room']->roomID,
'sender' => WCF::getUser()->userID,
'username' => WCF::getUser()->username,
'time' => TIME_NOW,
'type' => Message::TYPE_BACK,
'message' => '',
'color1' => $this->parameters['userData']['color1'],
'color2' => $this->parameters['userData']['color2']
)
));
$messageAction->executeAction();
}
}
public function sendAttachment() {
$this->objectAction = new MessageAction(array(), 'create', array(
'data' => array(
'roomID' => $this->parameters['room']->roomID,
'sender' => WCF::getUser()->userID,
'username' => WCF::getUser()->username,
'time' => TIME_NOW,
'type' => Message::TYPE_ATTACHMENT,
'message' => '[attach]'. $this->parameters['objectID'] .'[/attach]',
'color1' => $this->parameters['userData']['color1'],
'color2' => $this->parameters['userData']['color2'],
'attachmentID' => $this->parameters['objectID']
)
));
$this->objectAction->executeAction();
$returnValues = $this->objectAction->getReturnValues();
$this->parameters['parentObjectID'] = 0;
$attachmentHandler = new \wcf\system\attachment\AttachmentHandler('be.bastelstu.chat.message', $this->parameters['objectID'], $this->parameters['tmpHash'], $this->parameters['parentObjectID']);
$attachmentHandler->updateObjectID($returnValues['returnValues']->messageID);
// add activity points
\wcf\system\user\activity\point\UserActivityPointHandler::getInstance()->fireEvent('be.bastelstu.chat.activityPointEvent.message', $returnValues['returnValues']->messageID, WCF::getUser()->userID);
}
} }

View File

@ -16,6 +16,17 @@ class MessageEditor extends \wcf\data\DatabaseObjectEditor {
*/ */
protected static $baseClass = '\chat\data\message\Message'; protected static $baseClass = '\chat\data\message\Message';
/**
* @see wcf\data\DatabaseObjectEditor::deleteAll()
*/
public static function deleteAll(array $objectIDs = array()) {
$count = parent::deleteAll($objectIDs);
// delete attached files
\wcf\system\attachment\AttachmentHandler::removeAttachments('be.bastelstu.chat.message', $objectIDs);
return $count;
}
/** /**
* Notify the Push-Server. * Notify the Push-Server.
*/ */

View File

@ -203,7 +203,7 @@ public function join() {
} }
$ipAddress = ''; $ipAddress = '';
if ($this->parameters['user']->userID == WCF::getUser()->userID) $ipAddress = \wcf\util\UserUtil::convertIPv6To4(\wcf\util\UserUtil::getIpAddress()); if (LOG_IP_ADDRESS && $this->parameters['user']->userID == WCF::getUser()->userID) $ipAddress = \wcf\util\UserUtil::convertIPv6To4(\wcf\util\UserUtil::getIpAddress());
// join message // join message
$messageAction = new message\MessageAction(array(), 'create', array( $messageAction = new message\MessageAction(array(), 'create', array(

View File

@ -73,6 +73,12 @@ class ChatPage extends \wcf\page\AbstractPage {
*/ */
public $smileyCategories = array(); public $smileyCategories = array();
/**
* attachment handler
* @see \wcf\system\attachment\AttachmentHandler
*/
public $attachmentHandler = null;
/** /**
* @see wcf\page\AbstractPage::$enableTracking * @see wcf\page\AbstractPage::$enableTracking
*/ */
@ -94,6 +100,7 @@ public function assignVariables() {
'messageTypes' => $reflection->getConstants(), 'messageTypes' => $reflection->getConstants(),
'defaultSmilies' => $this->defaultSmilies, 'defaultSmilies' => $this->defaultSmilies,
'smileyCategories' => $this->smileyCategories, 'smileyCategories' => $this->smileyCategories,
'attachmentHandler' => $this->attachmentHandler,
'sidebarCollapsed' => \wcf\system\user\collapsible\content\UserCollapsibleContentHandler::getInstance()->isCollapsed('com.woltlab.wcf.collapsibleSidebar', 'be.bastelstu.chat.ChatPage'), 'sidebarCollapsed' => \wcf\system\user\collapsible\content\UserCollapsibleContentHandler::getInstance()->isCollapsed('com.woltlab.wcf.collapsibleSidebar', 'be.bastelstu.chat.ChatPage'),
'sidebarName' => 'be.bastelstu.chat.ChatPage' 'sidebarName' => 'be.bastelstu.chat.ChatPage'
)); ));
@ -125,6 +132,10 @@ public function readData() {
$this->defaultSmilies = \wcf\data\smiley\SmileyCache::getInstance()->getCategorySmilies($firstCategory->categoryID ?: null); $this->defaultSmilies = \wcf\data\smiley\SmileyCache::getInstance()->getCategorySmilies($firstCategory->categoryID ?: null);
} }
} }
if (MODULE_ATTACHMENT) {
$this->attachmentHandler = new \wcf\system\attachment\AttachmentHandler('be.bastelstu.chat.message', 0, '', 0);
}
} }
/** /**

View File

@ -0,0 +1,73 @@
<?php
namespace chat\system\attachment;
use \wcf\system\WCF;
/**
* Attachment object type implementation for chat messages.
*
* @author Maximilian Mader
* @copyright 2010-2013 Tim Düsterhus
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
* @package be.bastelstu.chat
* @subpackage system.attachment
*/
class MessageAttachmentObjectType extends \wcf\system\attachment\AbstractAttachmentObjectType {
/**
* @see wcf\system\attachment\IAttachmentObjectType::getMaxSize()
*/
public function getMaxSize() {
return WCF::getSession()->getPermission('user.chat.maxAttachmentSize');
}
/**
* @see wcf\system\attachment\IAttachmentObjectType::getAllowedExtensions()
*/
public function getAllowedExtensions() {
return \wcf\util\ArrayUtil::trim(explode("\n", WCF::getSession()->getPermission('user.chat.allowedAttachmentExtensions')));
}
/**
* @see wcf\system\attachment\IAttachmentObjectType::getMaxCount()
*/
public function getMaxCount() {
return 1;
}
/**
* @see wcf\system\attachment\IAttachmentObjectType::canDownload()
*/
public function canDownload($objectID) {
if ($objectID) {
$message = new \chat\data\message\Message($objectID);
if (isset($message->roomID) && $message->roomID) {
$room = \chat\data\room\RoomCache::getInstance()->getRoom($message->roomID);
if ($room && $room->canEnter()) return true;
}
}
return false;
}
public function canPreview($objectID) {
return $this->canDownload($objectID);
}
/**
* @see wcf\system\attachment\IAttachmentObjectType::canUpload()
*/
public function canUpload($objectID, $parentObjectID = 0) {
if ($objectID) {
$room = \chat\data\room\RoomCache::getInstance()->getRoom($parentObjectID);
if (!$room || !$room->canWrite()) return false;
}
return WCF::getSession()->getPermission('user.chat.canUploadAttachment');
}
/**
* @see wcf\system\attachment\IAttachmentObjectType::canDelete()
*/
public function canDelete($objectID) {
return false;
}
}

View File

@ -15,7 +15,6 @@
* @subpackage system.chat.command.commands * @subpackage system.chat.command.commands
*/ */
class InfoCommand extends \chat\system\command\AbstractCommand { class InfoCommand extends \chat\system\command\AbstractCommand {
public $enableHTML = self::SETTING_ON;
public $lines = array(); public $lines = array();
public $user = null; public $user = null;

View File

@ -192,9 +192,24 @@
padding: 5px 20px 5px 5px; padding: 5px 20px 5px 5px;
position: relative; position: relative;
.userAvatar { > div.avatarContainer {
float: left; position: absolute;
margin-left: 16px; width: 40px;
height: 38px;
> .userAvatar {
float: left;
margin-left: 16px;
}
> .avatarExtra {
box-shadow: 0 0 3px 0 rgba(0, 0, 0, 0.3);
position: absolute;
left: 24px;
bottom: -2px;
width: 16px;
height: 16px;
}
} }
.innerMessage { .innerMessage {
@ -219,11 +234,9 @@
} }
&.bubble { &.bubble {
.userAvatar { > div.avatarContainer {
margin-left: 0; .userAvatar {
margin-left: 0;
.icon {
padding: 2px;
} }
} }
@ -388,6 +401,16 @@
} }
} }
#timsChatUploadInput {
display: none;
}
#timsChatUploadContainer {
.innerError {
position: absolute;
}
}
#timsChatRoomList { #timsChatRoomList {
> div { > div {
> div { > div {

View File

@ -22,10 +22,12 @@ CREATE TABLE chat1_message (
color1 INT(10) NOT NULL DEFAULT 0, color1 INT(10) NOT NULL DEFAULT 0,
color2 INT(10) NOT NULL DEFAULT 0, color2 INT(10) NOT NULL DEFAULT 0,
additionalData TEXT DEFAULT NULL, additionalData TEXT DEFAULT NULL,
attachmentID INT(10) DEFAULT NULL,
KEY (roomID), KEY (roomID),
KEY (sender), KEY (sender),
KEY (receiver) KEY (receiver),
KEY (attachmentID)
); );
DROP TABLE IF EXISTS chat1_room; DROP TABLE IF EXISTS chat1_room;
@ -69,6 +71,7 @@ ALTER TABLE wcf1_user ADD COLUMN chatLastSeen INT(10) NOT NULL DEFAULT 0;
ALTER TABLE chat1_message ADD FOREIGN KEY (receiver) REFERENCES wcf1_user (userID) ON DELETE CASCADE; ALTER TABLE chat1_message ADD FOREIGN KEY (receiver) REFERENCES wcf1_user (userID) ON DELETE CASCADE;
ALTER TABLE chat1_message ADD FOREIGN KEY (roomID) REFERENCES chat1_room (roomID) ON DELETE CASCADE; ALTER TABLE chat1_message ADD FOREIGN KEY (roomID) REFERENCES chat1_room (roomID) ON DELETE CASCADE;
ALTER TABLE chat1_message ADD FOREIGN KEY (sender) REFERENCES wcf1_user (userID) ON DELETE SET NULL; ALTER TABLE chat1_message ADD FOREIGN KEY (sender) REFERENCES wcf1_user (userID) ON DELETE SET NULL;
ALTER TABLE chat1_message ADD FOREIGN KEY (attachmentID) REFERENCES wcf1_attachment (attachmentID) ON DELETE CASCADE;
ALTER TABLE chat1_room ADD FOREIGN KEY (owner) REFERENCES wcf1_user (userID) ON DELETE SET NULL; ALTER TABLE chat1_room ADD FOREIGN KEY (owner) REFERENCES wcf1_user (userID) ON DELETE SET NULL;

View File

@ -194,6 +194,8 @@ Probieren Sie, den Chat neu zu laden<!-- , bei Risiken und Nebenwirkungen fragen
<item name="chat.message.5.unban"><![CDATA[hat {@$link} entbannt.]]></item> <item name="chat.message.5.unban"><![CDATA[hat {@$link} entbannt.]]></item>
<item name="chat.message.5.ungmute"><![CDATA[hat {@$link} global entknebelt.]]></item> <item name="chat.message.5.ungmute"><![CDATA[hat {@$link} global entknebelt.]]></item>
<item name="chat.message.5.ungban"><![CDATA[hat {@$link} global entbannt.]]></item> <item name="chat.message.5.ungban"><![CDATA[hat {@$link} global entbannt.]]></item>
<!-- 12 = TYPE_ATTACHMENT -->
<item name="chat.message.12"><![CDATA[hat eine Datei geteilt:]]></item>
<item name="chat.message.color.success"><![CDATA[Die Farbe wurde erfolgreich geändert.]]></item> <item name="chat.message.color.success"><![CDATA[Die Farbe wurde erfolgreich geändert.]]></item>
<item name="chat.message.temproom.success"><![CDATA[Der temporäre Raum „{$roomName}“ wurde erfolgreich erstellt. Laden Sie die Raumliste neu, damit dieser sichtbar wird.]]></item> <item name="chat.message.temproom.success"><![CDATA[Der temporäre Raum „{$roomName}“ wurde erfolgreich erstellt. Laden Sie die Raumliste neu, damit dieser sichtbar wird.]]></item>

View File

@ -24,5 +24,10 @@
<classname>chat\system\user\online\location\ChatLocation</classname> <classname>chat\system\user\online\location\ChatLocation</classname>
<languagevariable>chat.user.usersOnline.location.ChatPage</languagevariable> <languagevariable>chat.user.usersOnline.location.ChatPage</languagevariable>
</type> </type>
<type>
<name>be.bastelstu.chat.message</name>
<definitionname>com.woltlab.wcf.attachment.objectType</definitionname>
<classname>chat\system\attachment\MessageAttachmentObjectType</classname>
</type>
</import> </import>
</data> </data>

View File

@ -21,12 +21,26 @@
'chat.error.onMessageLoad': '{@"chat.error.onMessageLoad"|language|encodeJS}', 'chat.error.onMessageLoad': '{@"chat.error.onMessageLoad"|language|encodeJS}',
'chat.error.duplicateTab': '{lang}chat.error.duplicateTab{/lang}', 'chat.error.duplicateTab': '{lang}chat.error.duplicateTab{/lang}',
'chat.error.join': '{lang}chat.error.join{/lang}', 'chat.error.join': '{lang}chat.error.join{/lang}',
'chat.error.reload': '{lang}chat.error.reload{/lang}' 'chat.error.reload': '{lang}chat.error.reload{/lang}',
'wcf.attachment.upload.error.invalidExtension': '{lang}wcf.attachment.upload.error.invalidExtension{/lang}',
'wcf.attachment.upload.error.tooLarge': '{lang}wcf.attachment.upload.error.tooLarge{/lang}',
'wcf.attachment.upload.error.reachedLimit': '{lang}wcf.attachment.upload.error.reachedLimit{/lang}',
'wcf.attachment.upload.error.reachedRemainingLimit': '{lang}wcf.attachment.upload.error.reachedRemainingLimit{/lang}',
'wcf.attachment.upload.error.uploadFailed': '{lang}wcf.attachment.upload.error.uploadFailed{/lang}',
'wcf.global.button.upload': '{lang}wcf.global.button.upload{/lang}',
'wcf.attachment.insert': '{lang}wcf.attachment.insert{/lang}',
'wcf.attachment.delete.sure': '{lang}wcf.attachment.delete.sure{/lang}',
'chat.message.{$messageTypes[TYPE_ATTACHMENT]}': '{lang}chat.message.{$messageTypes[TYPE_ATTACHMENT]}{/lang}'
}); });
// Boot the chat // Boot the chat
{if MODULE_SMILEY}WCF.TabMenu.init();{/if} {if MODULE_SMILEY}WCF.TabMenu.init();{/if}
{if MODULE_ATTACHMENT && $__wcf->session->getPermission('user.chat.canUploadAttachment')}
new be.bastelstu.Chat.Attachment();
new be.bastelstu.Chat.Action.Delete('wcf\\data\\attachment\\AttachmentAction', '#timsChatUploadDropdownMenu > li');
{/if}
new WCF.Message.Smilies(); new WCF.Message.Smilies();
{capture assign='messageTemplate'}{include application='chat' file='message'}{/capture} {capture assign='messageTemplate'}{include application='chat' file='message'}{/capture}
{capture assign='userTemplate'}{include application='chat' file='userListUser'}{/capture} {capture assign='userTemplate'}{include application='chat' file='userListUser'}{/capture}
@ -113,10 +127,28 @@
<span class="invisible">{lang}chat.general.controls{/lang}</span> <span class="invisible">{lang}chat.general.controls{/lang}</span>
<ul class="smallButtons buttonGroup"> <ul class="smallButtons buttonGroup">
<li><a id="timsChatAutoscroll" accesskey="d" class="button active timsChatToggle jsTooltip" title="{lang}chat.general.scroll{/lang}" data-status="1"><span class="icon icon16 icon-arrow-down"></span><span class="invisible">{lang}chat.general.scroll{/lang}</span></a></li>{* <li><a id="timsChatAutoscroll" accesskey="d" class="button active timsChatToggle jsTooltip" title="{lang}chat.general.scroll{/lang}" data-status="1"><span class="icon icon16 icon-arrow-down"></span><span class="invisible">{lang}chat.general.scroll{/lang}</span></a></li>{*
*}<li><a id="timsChatFullscreen" accesskey="f" class="button timsChatToggle jsTooltip" title="{lang}chat.general.fullscreen{/lang}" data-status="0"><span class="icon icon16 icon-fullscreen"></span><span class="invisible">{lang}chat.general.fullscreen{/lang}</span></a></li>{* *}<li><a id="timsChatFullscreen" accesskey="f" class="button timsChatToggle jsTooltip" title="{lang}chat.general.fullscreen{/lang}" data-status="0"><span class="icon icon16 icon-fullscreen"></span><span class="invisible">{lang}chat.general.fullscreen{/lang}</span></a></li>{*
*}<li><a id="timsChatNotify" accesskey="n" class="button timsChatToggle jsTooltip" title="{lang}chat.general.notify{/lang}" data-status="0"><span class="icon icon16 icon-bell-alt"></span><span class="invisible">{lang}chat.general.notify{/lang}</span></a></li>{* *}<li><a id="timsChatNotify" accesskey="n" class="button timsChatToggle jsTooltip" title="{lang}chat.general.notify{/lang}" data-status="0"><span class="icon icon16 icon-bell-alt"></span><span class="invisible">{lang}chat.general.notify{/lang}</span></a></li>{*
*}<li{if !MODULE_SMILEY || !$smileyCategories|count} style="display: none;"{/if}><a id="timsChatSmilies" accesskey="e" class="button{if ENABLE_SMILIES_DEFAULT_VALUE} active{/if} timsChatToggle jsTooltip" title="{lang}chat.general.smilies{/lang}" data-status="{@ENABLE_SMILIES_DEFAULT_VALUE}"><span class="icon icon16 icon-smile"></span><span class="invisible">{lang}chat.general.smilies{/lang}</span></a></li>{* *}<li{if !MODULE_SMILEY || !$smileyCategories|count} style="display: none;"{/if}><a id="timsChatSmilies" accesskey="e" class="button{if ENABLE_SMILIES_DEFAULT_VALUE} active{/if} timsChatToggle jsTooltip" title="{lang}chat.general.smilies{/lang}" data-status="{@ENABLE_SMILIES_DEFAULT_VALUE}"><span class="icon icon16 icon-smile"></span><span class="invisible">{lang}chat.general.smilies{/lang}</span></a></li>{*
*}{if MODULE_ATTACHMENT && $__wcf->session->getPermission('user.chat.canUploadAttachment')}{*
*}<li id="timsChatUploadContainer" class="dropdown" data-max-size="{$attachmentHandler->getMaxSize()}">
<a id="timsChatUpload" class="dropdownToggle button jsTooltip" title="{lang}wcf.attachment.attachments{/lang}" data-toggle="timsChatUploadContainer">
<span class="icon icon16 icon-paper-clip"></span>
<span class="invisible">{lang}wcf.attachment.attachments{/lang}</span>
</a>
<ul id="timsChatUploadDropdownMenu" class="dropdownMenu">
<li class="uploadButton" style="margin-top: 0;">
<span><label for="timsChatUploadInput">{lang}wcf.global.button.upload{/lang}</label></span>
</li>
</ul>
</li>{/if}{*
*}<li><a id="timsChatClear" class="button jsTooltip" title="{lang}chat.general.clear{/lang}"><span class="icon icon16 icon-remove"></span><span class="invisible">{lang}chat.general.clear{/lang}</span></a></li>{* *}<li><a id="timsChatClear" class="button jsTooltip" title="{lang}chat.general.clear{/lang}"><span class="icon icon16 icon-remove"></span><span class="invisible">{lang}chat.general.clear{/lang}</span></a></li>{*
*}<li><a id="timsChatMark" class="button timsChatToggle jsTooltip" title="{lang}chat.general.mark{/lang}" data-status="0"><span class="icon icon16 icon-check"></span><span class="invisible">{lang}chat.general.mark{/lang}</span></a></li> *}<li><a id="timsChatMark" class="button timsChatToggle jsTooltip" title="{lang}chat.general.mark{/lang}" data-status="0"><span class="icon icon16 icon-check"></span><span class="invisible">{lang}chat.general.mark{/lang}</span></a></li>
</ul> </ul>
</nav> </nav>

View File

@ -1,2 +1,3 @@
{if MODULE_ATTACHMENT && $__wcf->session->getPermission('user.chat.canUploadAttachment')}<script data-relocate="true" src="{@$__wcf->getPath()}js/WCF.Attachment{if !ENABLE_DEBUG_MODE}.min{/if}.js?v={@$__wcfVersion}"></script>{/if}
<script data-relocate="true" src="{$__wcf->getPath('chat')}js/be.bastelstu.Chat{if !ENABLE_DEBUG_MODE}.min{/if}.js?version={PACKAGE_VERSION|rawurlencode}"></script> <script data-relocate="true" src="{$__wcf->getPath('chat')}js/be.bastelstu.Chat{if !ENABLE_DEBUG_MODE}.min{/if}.js?version={PACKAGE_VERSION|rawurlencode}"></script>
{event name='javascript'} {event name='javascript'}

View File

@ -1,19 +1,26 @@
{literal} {literal}
<div class="messageIcon"> {if $message.type == $messageTypes.LEAVE || $message.type == $messageTypes.JOIN}
{if $message.type == $messageTypes.LEAVE || $message.type == $messageTypes.JOIN} <div class="messageIcon">
<span class="icon icon16 icon-{if $message.type == $messageTypes.LEAVE}signout{else}signin{/if}"></span> <span class="icon icon16 icon-{if $message.type == $messageTypes.LEAVE}signout{elseif $message.type == $messageTypes.JOIN}signin{/if}"></span>
{/if} </div>
</div> {/if}
<div class="innerMessageContainer{if $message.type == $messageTypes.NORMAL || $message.type == $messageTypes.WHISPER || $message.type == $messageTypes.INFORMATION} bubble{/if}{if $message.type == $messageTypes.WHISPER && $message.sender != $__wcf.User.userID} right{/if}"> <div class="innerMessageContainer{if $message.type == $messageTypes.NORMAL || $message.type == $messageTypes.WHISPER || $message.type == $messageTypes.INFORMATION || $message.type == $messageTypes.ATTACHMENT} bubble{/if}{if $message.type == $messageTypes.WHISPER && $message.sender != $__wcf.User.userID} right{/if}">
<div class="userAvatar framed"> <div class="avatarContainer">
{if $message.type != $messageTypes.INFORMATION} <div class="userAvatar framed">
{if $message.type == $messageTypes.NORMAL || $message.type == $messageTypes.WHISPER} {if $message.type != $messageTypes.INFORMATION}
{@$message.avatar[32]} {if $message.type == $messageTypes.NORMAL || $message.type == $messageTypes.WHISPER || $message.type == $messageTypes.ATTACHMENT}
{@$message.avatar[32]}
{else}
{@$message.avatar[16]}
{/if}
{else} {else}
{@$message.avatar[16]} <span class="icon icon32 icon-info-sign"></span>
{/if} {/if}
{else} </div>
<span class="icon icon32 icon-info-sign"></span> {if $message.type == $messageTypes.ATTACHMENT}
<small class="framed avatarExtra">
<span class="icon icon16 icon-paperclip"></span>
</small>
{/if} {/if}
</div> </div>
<div class="innerMessage"> <div class="innerMessage">
@ -36,7 +43,8 @@
<time>{@$message.formattedTime}</time> <time>{@$message.formattedTime}</time>
{if $message.type == $messageTypes.NORMAL || $message.type == $messageTypes.WHISPER} {if $message.type == $messageTypes.NORMAL || $message.type == $messageTypes.WHISPER || $message.type == $messageTypes.ATTACHMENT}
{if $message.type == $messageTypes.ATTACHMENT}<span>{lang}chat.message.{$messageTypes.ATTACHMENT}{/lang}</span>{/if}
<ul class="text"> <ul class="text">
<li> <li>
{if $message.isFollowUp} <time>{@$message.formattedTime}</time>{/if} {if $message.isFollowUp} <time>{@$message.formattedTime}</time>{/if}

View File

@ -38,6 +38,34 @@
<defaultvalue>none</defaultvalue> <defaultvalue>none</defaultvalue>
<admindefaultvalue>all</admindefaultvalue> <admindefaultvalue>all</admindefaultvalue>
</option> </option>
<option name="user.chat.canUploadAttachment">
<categoryname>user.chat</categoryname>
<optiontype>boolean</optiontype>
<defaultvalue>1</defaultvalue>
<enableoptions>user.chat.maxAttachmentSize,user.chat.allowedAttachmentExtensions</enableoptions>
<options>module_attachment</options>
</option>
<option name="user.chat.maxAttachmentSize">
<categoryname>user.chat</categoryname>
<optiontype>fileSize</optiontype>
<defaultvalue>1000000</defaultvalue>
<options>module_attachment</options>
<minvalue>10000</minvalue>
</option>
<option name="user.chat.allowedAttachmentExtensions">
<categoryname>user.chat</categoryname>
<optiontype>textarea</optiontype>
<defaultvalue><![CDATA[gif
jpg
jpeg
png
bmp
zip
txt
pdf]]></defaultvalue>
<options>module_attachment</options>
<wildcard><![CDATA[*]]></wildcard>
</option>
<option name="mod.chat.canAlwaysEnter"> <option name="mod.chat.canAlwaysEnter">
<categoryname>mod.chat</categoryname> <categoryname>mod.chat</categoryname>
<optiontype>boolean</optiontype> <optiontype>boolean</optiontype>