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:
parent
06882254a0
commit
7581490345
@ -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 ?= {}
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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>{*
|
||||
|
||||
|
@ -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'}
|
||||
|
Loading…
Reference in New Issue
Block a user