1
0
mirror of https://github.com/wbbaddons/Tims-Chat.git synced 2024-10-31 14:10: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: {}
allTime: {}
currentRoom = {}
fileUploaded = no
errorVisible = false
inputErrorHidingTimer = null
@ -643,7 +644,7 @@ Fetch the roomlist from the server and update it in the GUI.
for room in data.returnValues
li = $ '<li></li>'
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
if window.history?.replaceState?
@ -741,7 +742,7 @@ Open private channel
if userID isnt 0
$('#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'
unless $.wcfIsset "privateChannel#{userID}"
@ -809,7 +810,222 @@ Remove the given callback from the given event.
events[event].remove callback
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.
Chat =
@ -822,7 +1038,9 @@ And finally export the public methods and variables.
listener:
add: addListener
remove: removeListener
Chat.Attachment = Attachment if Attachment?
Chat.Action = Action if Attachment?
window.be ?= {}
be.bastelstu ?= {}
window.be.bastelstu.Chat = Chat

View File

@ -1,6 +1,7 @@
<?php
namespace chat\data\message;
use \chat\util\ChatUtil;
use \wcf\system\bbcode\AttachmentBBCode;
use \wcf\system\Regex;
use \wcf\system\WCF;
@ -36,6 +37,7 @@ class Message extends \chat\data\CHATDatabaseObject {
const TYPE_CLEAR = 9;
const TYPE_TEAM = 10;
const TYPE_GLOBALMESSAGE = 11;
const TYPE_ATTACHMENT = 12;
/**
* cache for users
@ -87,6 +89,16 @@ public function getFormattedMessage($type = 'text/html') {
$message = $messageParser->parse($message, false, false, true, false);
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_NORMAL:
case self::TYPE_ME:
@ -137,7 +149,7 @@ public function jsonify($raw = false) {
$array = array(
'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'),
'separator' => $separator,
'message' => $this->getFormattedMessage('text/plain'),

View File

@ -197,4 +197,73 @@ public function validateGetMessages() {
$this->parameters['room'] = room\RoomCache::getInstance()->getRoom($this->parameters['roomID']);
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';
/**
* @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.
*/

View File

@ -203,7 +203,7 @@ public function join() {
}
$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
$messageAction = new message\MessageAction(array(), 'create', array(

View File

@ -73,6 +73,12 @@ class ChatPage extends \wcf\page\AbstractPage {
*/
public $smileyCategories = array();
/**
* attachment handler
* @see \wcf\system\attachment\AttachmentHandler
*/
public $attachmentHandler = null;
/**
* @see wcf\page\AbstractPage::$enableTracking
*/
@ -94,6 +100,7 @@ public function assignVariables() {
'messageTypes' => $reflection->getConstants(),
'defaultSmilies' => $this->defaultSmilies,
'smileyCategories' => $this->smileyCategories,
'attachmentHandler' => $this->attachmentHandler,
'sidebarCollapsed' => \wcf\system\user\collapsible\content\UserCollapsibleContentHandler::getInstance()->isCollapsed('com.woltlab.wcf.collapsibleSidebar', '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);
}
}
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
*/
class InfoCommand extends \chat\system\command\AbstractCommand {
public $enableHTML = self::SETTING_ON;
public $lines = array();
public $user = null;

View File

@ -10,7 +10,7 @@
from {
border-color: @wcfContainerBorderColor;
}
to {
border-color: @wcfInputHoverBorderColor;
}
@ -92,7 +92,7 @@
> .userAvatar, .userAvatar > .icon {
cursor: pointer;
}
> .userAvatar {
&.large {
display: none;
@ -102,7 +102,7 @@
display: block;
}
}
&.active {
> .userAvatar {
&.large {
@ -192,9 +192,24 @@
padding: 5px 20px 5px 5px;
position: relative;
.userAvatar {
float: left;
margin-left: 16px;
> div.avatarContainer {
position: absolute;
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 {
@ -219,11 +234,9 @@
}
&.bubble {
.userAvatar {
margin-left: 0;
.icon {
padding: 2px;
> div.avatarContainer {
.userAvatar {
margin-left: 0;
}
}
@ -388,6 +401,16 @@
}
}
#timsChatUploadInput {
display: none;
}
#timsChatUploadContainer {
.innerError {
position: absolute;
}
}
#timsChatRoomList {
> div {
> div {

View File

@ -22,10 +22,12 @@ CREATE TABLE chat1_message (
color1 INT(10) NOT NULL DEFAULT 0,
color2 INT(10) NOT NULL DEFAULT 0,
additionalData TEXT DEFAULT NULL,
attachmentID INT(10) DEFAULT NULL,
KEY (roomID),
KEY (sender),
KEY (receiver)
KEY (receiver),
KEY (attachmentID)
);
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 (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 (attachmentID) REFERENCES wcf1_attachment (attachmentID) ON DELETE CASCADE;
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.ungmute"><![CDATA[hat {@$link} global entknebelt.]]></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.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>
<languagevariable>chat.user.usersOnline.location.ChatPage</languagevariable>
</type>
<type>
<name>be.bastelstu.chat.message</name>
<definitionname>com.woltlab.wcf.attachment.objectType</definitionname>
<classname>chat\system\attachment\MessageAttachmentObjectType</classname>
</type>
</import>
</data>

View File

@ -21,12 +21,26 @@
'chat.error.onMessageLoad': '{@"chat.error.onMessageLoad"|language|encodeJS}',
'chat.error.duplicateTab': '{lang}chat.error.duplicateTab{/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
{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();
{capture assign='messageTemplate'}{include application='chat' file='message'}{/capture}
{capture assign='userTemplate'}{include application='chat' file='userListUser'}{/capture}
@ -113,10 +127,28 @@
<span class="invisible">{lang}chat.general.controls{/lang}</span>
<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="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{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="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>
</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>
{event name='javascript'}

View File

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

View File

@ -38,6 +38,34 @@
<defaultvalue>none</defaultvalue>
<admindefaultvalue>all</admindefaultvalue>
</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">
<categoryname>mod.chat</categoryname>
<optiontype>boolean</optiontype>