1
0
mirror of https://github.com/wbbaddons/Tims-Chat.git synced 2024-10-31 14:10:08 +00:00

Improve attachment system

Now it's possible to upload attachments and generate an attachment
message. The attachments are registered in the database correctly and
can be viewed WCF's attachment list in ACP.

TODO: Proper design in frontend and some backend functions.
This commit is contained in:
Maximilian Mader 2013-10-06 02:59:13 +02:00
parent 06882254a0
commit 7581490345
6 changed files with 315 additions and 25 deletions

View File

@ -37,6 +37,7 @@ exposed by a function if necessary.
current: {}
allTime: {}
currentRoom = {}
fileUploaded = no
errorVisible = false
inputErrorHidingTimer = null
@ -810,34 +811,217 @@ Remove the given callback from the given event.
true
if WCF?.Attachment?.Upload?
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'), $('<ul>').appendTo('#content'), 'be.bastelstu.chat.message', 0, 0, 0, 1, null
@_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 type="file" name="#{@_name}" />"""
@_fileUpload.change =>
do @_upload
button = $ """<a id="timsChatUpload" class="button uploadButton jsTooltip" title="#{WCF.Language.get("wcf.global.button.upload")}"><span class="icon icon16 icon-upload-alt"></span><span class="invisible">#{WCF.Language.get("wcf.global.button.upload")}</span></a>"""
button.prepend @_fileUpload
else
button = $ """<a id="timsChatUpload" class="button uploadFallbackButton jsTooltip" title="#{WCF.Language.get("wcf.global.button.upload")}"><span class="icon icon16 icon-upload-alt"></span><span class="invisible">#{WCF.Language.get("wcf.global.button.upload")}</span></a>"""
button.click =>
do @_showOverlay
@_fileUpload = $ """<input id="timsChatUploadInput" type="file" name="#{@_name}" />"""
@_fileUpload.change => do @_upload
@_fileUpload.appendTo 'body'
@_insertButton button
_removeButton: ->
do @_fileUpload.remove
_insertButton: (button) ->
@_super(button)
@_buttonSelector.removeClass 'invisible'
See WCF.Attachment.Upload._getParameters()
_upload: ->
_getParameters: ->
@_tmpHash = do Math.random
@_objectID = be.bastelstu.Chat.currentRoomID
@_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
$('#timsChatUploadContainer').append """<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'
if data.returnValues and data.returnValues.attachments[filename]
if data.returnValues.attachments[filename].tinyURL
li.find('.box32 > div.attachmentImageContainer > .icon-paper-clip').replaceWith $("""<img src="#{data.returnValues.attachments[filename].tinyURL}'" alt="" class="attachmentTinyThumbnail" style="width: 32px; height: 32px;" />""")
link = $ '<a href="" class="jsTooltip"></a>'
link.attr {'href': data.returnValues.attachments[filename].url, 'title': filename}
unless parseInt(data.returnValues.attachments[filename].isImage) is 0
link.addClass('jsImageViewer')
if !data.returnValues.attachments[filename].tinyURL
li.find('.box32 > div.attachmentImageContainer > .icon-paper-clip').replaceWith $("""<img src="#{data.returnValues.attachments[filename].url}'" alt="" class="attachmentTinyThumbnail" style="width: 32px; height: 32px;" />""")
li.find('.attachmentTinyThumbnail').wrap link
li.find('small').append data.returnValues.attachments[filename].formattedFilesize
li.data 'objectID', data.returnValues.attachments[filename].attachmentID
deleteButton = $ """
<li>
<span class="jsDeleteButton" data-object-id="#{data.returnValues.attachments[filename].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
else
$('#timsChatUpload .icon-spinner').removeClass('icon-spinner').addClass 'icon-ban-circle'
if data.returnValues and data.returnValues.errors[filename]
errorMessage = data.returnValues.errors[filename].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
do WCF.DOMNodeInsertedHandler.execute
fileUploaded = yes
$('#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'
$('#timsChatUpload').addClass('uploadFailed').after """<small class="innerError">#{WCF.Language.get('wcf.attachment.upload.error.uploadFailed')}</small>"""
do $('#timsChatUploadDropdownMenu .uploadProgress').remove
do $('#timsChatUploadDropdownMenu .uploadButton').show
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 =
@ -847,11 +1031,11 @@ And finally export the public methods and variables.
insertText: insertText
freeTheFish: freeTheFish
join: join
currentRoomID: currentRoom.roomID
listener:
add: addListener
remove: removeListener
Chat.Attachment = Attachment if Attachment?
Chat.Action = Action if Attachment?
window.be ?= {}
be.bastelstu ?= {}

View File

@ -3,6 +3,7 @@
use \chat\util\ChatUtil;
use \wcf\system\Regex;
use \wcf\system\WCF;
use \wcf\system\bbcode\AttachmentBBCode;
/**
* Represents a chat message.
@ -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('[attach]'. $message .'[/attach]', 0, 0, true, false);
break;
case self::TYPE_WHISPER:
case self::TYPE_NORMAL:
case self::TYPE_ME:

View File

@ -197,4 +197,76 @@ 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,
'receiver' => null,
'time' => TIME_NOW,
'type' => Message::TYPE_ATTACHMENT,
'message' => $this->parameters['objectID'],
'enableSmilies' => 0,
'enableHTML' => 0,
'color1' => $this->parameters['userData']['color1'],
'color2' => $this->parameters['userData']['color2'],
'additionalData' => null
)
));
$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

@ -37,12 +37,19 @@ public function getMaxCount() {
* @see wcf\system\attachment\IAttachmentObjectType::canDownload()
*/
public function canDownload($objectID) {
if ($objectID) {
// TODO get the room ID
/*if ($objectID) {
$room = \chat\data\room\RoomCache::getInstance()->getRoom($objectID);
if ($room && $room->canEnter()) return true;
}
return false;
return false;*/
return true;
}
public function canPreview($objectID) {
return $this->canDownload($objectID);
}
/**
@ -61,6 +68,7 @@ public function canUpload($objectID, $parentObjectID = 0) {
* @see wcf\system\attachment\IAttachmentObjectType::canDelete()
*/
public function canDelete($objectID) {
// TODO Allow attachments to be deleted in ACP
return false;
}
}

View File

@ -34,7 +34,10 @@
// Boot the chat
{if MODULE_SMILEY}WCF.TabMenu.init();{/if}
{if MODULE_ATTACHMENT}new be.bastelstu.Chat.Attachment();{/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}
@ -127,7 +130,18 @@
*}<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 id="timsChatUploadContainer" class="invisible" data-max-size="{$attachmentHandler->getMaxSize()}"></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.global.button.upload{/lang}" data-toggle="timsChatUploadContainer">
<span class="icon icon16 icon-paper-clip"></span>
<span class="invisible">{lang}wcf.global.button.upload{/lang}</span>
</a>
<ul id="timsChatUploadDropdownMenu" class="dropdownMenu">
<li class="uploadButton" style="margin-top: 0;">
<span><label for="timsChatUploadInput">Upload file</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>{*

View File

@ -1,3 +1,3 @@
{if MODULE_ATTACHMENT}<script data-relocate="true" src="{@$__wcf->getPath()}js/WCF.Attachment{if !ENABLE_DEBUG_MODE}.min{/if}.js?v={@$__wcfVersion}"></script>{/if}
{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'}