mirror of
https://github.com/wbbaddons/Tims-Chat.git
synced 2024-12-21 21:30:08 +00:00
Merge branch 'attachment'
This commit is contained in:
commit
b49ac97e10
@ -1,11 +1,11 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (c) 2010-2018 Tim Düsterhus.
|
||||
* Copyright (c) 2010-2020 Tim Düsterhus.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License
|
||||
* included in the LICENSE file.
|
||||
*
|
||||
* Change Date: 2024-10-20
|
||||
* Change Date: 2024-11-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source
|
||||
* License, use of this software will be governed by version 2
|
||||
@ -17,6 +17,7 @@
|
||||
use \chat\data\command\CommandCache;
|
||||
use \chat\data\room\RoomCache;
|
||||
use \wcf\data\object\type\ObjectTypeCache;
|
||||
use \wcf\system\attachment\AttachmentHandler;
|
||||
use \wcf\system\exception\PermissionDeniedException;
|
||||
use \wcf\system\exception\UserInputException;
|
||||
use \wcf\system\user\activity\point\UserActivityPointHandler;
|
||||
@ -304,4 +305,66 @@ public function push() {
|
||||
$processor->validate($this->parameters['parameters'], $room);
|
||||
$processor->execute($this->parameters['parameters'], $room);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates parameters and permissions.
|
||||
*/
|
||||
public function validatePushAttachment() {
|
||||
$this->readInteger('roomID');
|
||||
|
||||
$room = RoomCache::getInstance()->getRoom($this->parameters['roomID']);
|
||||
if ($room === null) throw new UserInputException('roomID');
|
||||
if (!$room->canSee($user = null, $reason)) throw $reason;
|
||||
$user = new \chat\data\user\User(WCF::getUser());
|
||||
if (!$user->isInRoom($room)) throw new PermissionDeniedException();
|
||||
|
||||
$this->readString('tmpHash');
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes a new attachment into the given room.
|
||||
*/
|
||||
public function pushAttachment() {
|
||||
$objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName('be.bastelstu.chat.messageType', 'be.bastelstu.chat.messageType.attachment');
|
||||
if (!$objectTypeID) throw new \LogicException('Missing object type');
|
||||
|
||||
$room = RoomCache::getInstance()->getRoom($this->parameters['roomID']);
|
||||
if ($room === null) throw new UserInputException('roomID');
|
||||
|
||||
$attachmentHandler = new AttachmentHandler('be.bastelstu.chat.message', 0, $this->parameters['tmpHash'], $room->roomID);
|
||||
$attachments = $attachmentHandler->getAttachmentList();
|
||||
$attachmentIDs = [];
|
||||
foreach ($attachments as $attachment) {
|
||||
$attachmentIDs[] = $attachment->attachmentID;
|
||||
}
|
||||
|
||||
$processor = new \wcf\system\html\input\HtmlInputProcessor();
|
||||
$processor->process(implode(' ', array_map(function ($attachmentID) {
|
||||
return '[attach='.$attachmentID.',none,true][/attach]';
|
||||
}, $attachmentIDs)), 'be.bastelstu.chat.message', 0);
|
||||
|
||||
WCF::getDB()->beginTransaction();
|
||||
/** @var Message $message */
|
||||
$message = (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => $room->roomID
|
||||
, 'userID' => WCF::getUser()->userID
|
||||
, 'username' => WCF::getUser()->username
|
||||
, 'time' => TIME_NOW
|
||||
, 'objectTypeID' => $objectTypeID
|
||||
, 'payload' => serialize([ 'attachmentIDs' => $attachmentIDs
|
||||
, 'message' => $processor->getHtml()
|
||||
])
|
||||
]
|
||||
]
|
||||
)
|
||||
)->executeAction()['returnValues'];
|
||||
|
||||
$attachmentHandler->updateObjectID($message->messageID);
|
||||
$processor->setObjectID($message->messageID);
|
||||
if (\wcf\system\message\embedded\object\MessageEmbeddedObjectManager::getInstance()->registerObjects($processor)) {
|
||||
(new MessageEditor($message))->update([
|
||||
'hasEmbeddedObjects' => 1
|
||||
]);
|
||||
}
|
||||
WCF::getDB()->commitTransaction();
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (c) 2010-2018 Tim Düsterhus.
|
||||
* Copyright (c) 2010-2020 Tim Düsterhus.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License
|
||||
* included in the LICENSE file.
|
||||
*
|
||||
* Change Date: 2024-10-20
|
||||
* Change Date: 2024-11-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source
|
||||
* License, use of this software will be governed by version 2
|
||||
@ -14,6 +14,9 @@
|
||||
|
||||
namespace chat\data\message;
|
||||
|
||||
use \wcf\system\attachment\AttachmentHandler;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Represents a chat message editor.
|
||||
*/
|
||||
@ -22,4 +25,20 @@ class MessageEditor extends \wcf\data\DatabaseObjectEditor {
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected static $baseClass = Message::class;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function deleteAll(array $messageIDs = []) {
|
||||
WCF::getDB()->beginTransaction();
|
||||
|
||||
$result = parent::deleteAll($messageIDs);
|
||||
if (!empty($messageIDs)) {
|
||||
AttachmentHandler::removeAttachments('be.bastelstu.chat.message', $messageIDs);
|
||||
}
|
||||
|
||||
WCF::getDB()->commitTransaction();
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,13 @@
|
||||
class RoomPage extends \wcf\page\AbstractPage {
|
||||
use TConfiguredPage;
|
||||
|
||||
/**
|
||||
* Almost dummy attachment handler (used in language variable)
|
||||
*
|
||||
* @var \wcf\system\attachment\AttachmentHandler
|
||||
*/
|
||||
public $attachmentHandler;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@ -65,7 +72,7 @@ public function readParameters() {
|
||||
*/
|
||||
public function checkPermissions() {
|
||||
parent::checkPermissions();
|
||||
|
||||
|
||||
$package = \wcf\data\package\PackageCache::getInstance()->getPackageByIdentifier('be.bastelstu.chat');
|
||||
if (stripos($package->packageVersion, 'Alpha') !== false) {
|
||||
$sql = "SELECT COUNT(*) FROM wcf".WCF_N."_user";
|
||||
@ -91,6 +98,9 @@ public function readData() {
|
||||
|
||||
parent::readData();
|
||||
|
||||
// This attachment handler gets only used for the language variable `wcf.attachment.upload.limits`!
|
||||
$this->attachmentHandler = new \wcf\system\attachment\AttachmentHandler('be.bastelstu.chat.message', 0, 'DEADC0DE00000000DEADC0DE00000000DEADC0DE', $this->room->roomID);
|
||||
|
||||
$pushHandler = \wcf\system\push\PushHandler::getInstance();
|
||||
$pushHandler->joinChannel('be.bastelstu.chat');
|
||||
$pushHandler->joinChannel('be.bastelstu.chat.room-'.$this->room->roomID);
|
||||
@ -104,6 +114,7 @@ public function assignVariables() {
|
||||
|
||||
WCF::getTPL()->assign([ 'room' => $this->room
|
||||
, 'config' => $this->getConfig()
|
||||
, 'attachmentHandler' => $this->attachmentHandler
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (c) 2010-2020 Tim Düsterhus.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License
|
||||
* included in the LICENSE file.
|
||||
*
|
||||
* Change Date: 2024-10-31
|
||||
*
|
||||
* On the date above, in accordance with the Business Source
|
||||
* License, use of this software will be governed by version 2
|
||||
* or later of the General Public License.
|
||||
*/
|
||||
|
||||
namespace chat\system\attachment;
|
||||
|
||||
use \chat\data\message\Message;
|
||||
use \chat\data\message\MessageList;
|
||||
use \chat\data\room\RoomCache;
|
||||
use \wcf\system\WCF;
|
||||
|
||||
/**
|
||||
* Attachment object type implementation for messages.
|
||||
*/
|
||||
class MessageAttachmentObjectType extends \wcf\system\attachment\AbstractAttachmentObjectType {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function canDownload($objectID) {
|
||||
if ($objectID) {
|
||||
$message = new Message($objectID);
|
||||
|
||||
if ($message->getMessageType()->objectType !== 'be.bastelstu.chat.messageType.attachment') {
|
||||
throw new \LogicException('Unreachable');
|
||||
}
|
||||
$room = $message->getRoom();
|
||||
|
||||
return $room->canSee();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function canUpload($objectID, $parentObjectID = 0) {
|
||||
if ($objectID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!WCF::getSession()->getPermission('user.chat.canAttach')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$room = null;
|
||||
if ($parentObjectID) {
|
||||
$room = RoomCache::getInstance()->getRoom($parentObjectID);
|
||||
}
|
||||
|
||||
if ($room !== null) {
|
||||
return $room->canSee();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function canDelete($objectID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getMaxCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getAllowedExtensions() {
|
||||
return [ 'png'
|
||||
, 'gif'
|
||||
, 'jpg'
|
||||
, 'jpeg'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function cacheObjects(array $objectIDs) {
|
||||
$messageList = new MessageList();
|
||||
$messageList->setObjectIDs($objectIDs);
|
||||
$messageList->readObjects();
|
||||
|
||||
foreach ($messageList->getObjects() as $objectID => $object) {
|
||||
$this->cachedObjects[$objectID] = $object;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (c) 2010-2020 Tim Düsterhus.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License
|
||||
* included in the LICENSE file.
|
||||
*
|
||||
* Change Date: 2024-10-31
|
||||
*
|
||||
* On the date above, in accordance with the Business Source
|
||||
* License, use of this software will be governed by version 2
|
||||
* or later of the General Public License.
|
||||
*/
|
||||
|
||||
namespace chat\system\message\type;
|
||||
|
||||
/**
|
||||
* AttachmentMessageType represents a message with an attached file.
|
||||
*/
|
||||
class AttachmentMessageType implements IMessageType, IDeletableMessageType {
|
||||
use TCanSeeInSameRoom;
|
||||
|
||||
/**
|
||||
* HtmlOutputProcessor to use.
|
||||
* @var \wcf\system\html\output\HtmlOutputProcessor
|
||||
*/
|
||||
protected $processor = null;
|
||||
|
||||
public function __construct() {
|
||||
$this->processor = new \wcf\system\html\output\HtmlOutputProcessor();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getJavaScriptModuleName() {
|
||||
return 'Bastelstu.be/Chat/MessageType/Plain';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function canDelete(\chat\data\message\Message $message, \wcf\data\user\UserProfile $user = null) {
|
||||
if ($user === null) $user = new \wcf\data\user\UserProfile(\wcf\system\WCF::getUser());
|
||||
|
||||
return $user->getPermission('mod.chat.canDelete');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \chat\system\message\type\IMessageType::getPayload()
|
||||
*/
|
||||
public function getPayload(\chat\data\message\Message $message, \wcf\data\user\UserProfile $user = null) {
|
||||
if ($user === null) $user = new \wcf\data\user\UserProfile(\wcf\system\WCF::getUser());
|
||||
|
||||
$payload = $message->payload;
|
||||
$payload['formattedMessage'] = null;
|
||||
$payload['plaintextMessage'] = null;
|
||||
|
||||
$parameters = [ 'message' => $message
|
||||
, 'user' => $user
|
||||
, 'payload' => $payload
|
||||
];
|
||||
\wcf\system\event\EventHandler::getInstance()->fireAction($this, 'getPayload', $parameters);
|
||||
|
||||
if ($parameters['payload']['formattedMessage'] === null) {
|
||||
$this->processor->setOutputType('text/html');
|
||||
$this->processor->process($parameters['payload']['message'], 'be.bastelstu.chat.message', $message->messageID);
|
||||
$parameters['payload']['formattedMessage'] = $this->processor->getHtml();
|
||||
}
|
||||
if ($parameters['payload']['plaintextMessage'] === null) {
|
||||
$this->processor->setOutputType('text/plain');
|
||||
$this->processor->process($parameters['payload']['message'], 'be.bastelstu.chat.message', $message->messageID);
|
||||
$parameters['payload']['plaintextMessage'] = $this->processor->getHtml();
|
||||
}
|
||||
|
||||
return $parameters['payload'];
|
||||
}
|
||||
}
|
@ -57,6 +57,7 @@ #tpl_chat_log {
|
||||
}
|
||||
|
||||
#content {
|
||||
margin-left: 20px;
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
@ -378,15 +379,46 @@ #tpl_chat_log {
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> .flexibleTextarea {
|
||||
flex: 1 0 auto;
|
||||
max-width: 100%;
|
||||
> div.chatAttachButton {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
margin-right: 5px;
|
||||
|
||||
@include screen-xs {
|
||||
> .disabled {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.icon16 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@include screen-lg {
|
||||
.icon16 {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.icon24 {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> #chatQuickSettings {
|
||||
flex: 0 0 auto;
|
||||
> div.chatInputWrapper {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> .flexibleTextarea {
|
||||
flex: 1 0 auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
> #chatQuickSettings {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License
|
||||
* included in the LICENSE file.
|
||||
*
|
||||
* Change Date: 2024-10-31
|
||||
* Change Date: 2024-11-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source
|
||||
* License, use of this software will be governed by version 2
|
||||
@ -27,6 +27,7 @@ define([ './Chat/console'
|
||||
, './Chat/ProfileStore'
|
||||
, './Chat/Room'
|
||||
, './Chat/Template'
|
||||
, './Chat/Ui/Attachment/Upload'
|
||||
, './Chat/Ui/AutoAway'
|
||||
, './Chat/Ui/Chat'
|
||||
, './Chat/Ui/ConnectionWarning'
|
||||
@ -43,7 +44,7 @@ define([ './Chat/console'
|
||||
, './Chat/Ui/UserActionDropdownHandler'
|
||||
, './Chat/Ui/UserList'
|
||||
], function (console, Bottle, Push, Core, Language, RepeatingTimer, CoreUser, Autocompleter,
|
||||
CommandHandler, Throttle, Message, Messenger, ParseError, ProfileStore, Room, Template, UiAutoAway, Ui,
|
||||
CommandHandler, Throttle, Message, Messenger, ParseError, ProfileStore, Room, Template, UiAttachmentUpload, UiAutoAway, Ui,
|
||||
UiConnectionWarning, ErrorDialog, UiInput, UiInputAutocompleter, UiMessageStream, UiMessageActionDelete, UiMobile, UiNotification,
|
||||
UiReadMarker, UiSettings, UiTopic, UiUserActionDropdownHandler, UiUserList) {
|
||||
"use strict";
|
||||
@ -85,6 +86,7 @@ define([ './Chat/console'
|
||||
this.service('UiTopic', UiTopic)
|
||||
this.service('UiUserActionDropdownHandler', UiUserActionDropdownHandler)
|
||||
this.service('UiUserList', UiUserList)
|
||||
this.service('UiAttachmentUpload', UiAttachmentUpload)
|
||||
|
||||
// Register Models
|
||||
this.bottle.instanceFactory('Message', (container, m) => {
|
||||
@ -176,8 +178,11 @@ define([ './Chat/console'
|
||||
this.ui = this.bottle.container.Ui
|
||||
this.ui.bootstrap()
|
||||
|
||||
this.bottle.container.UiInput.on('submit', this.onSubmit.bind(this))
|
||||
this.bottle.container.UiInput.on('autocomplete', this.onAutocomplete.bind(this))
|
||||
this.ui.input.on('submit', this.onSubmit.bind(this))
|
||||
this.ui.input.on('autocomplete', this.onAutocomplete.bind(this))
|
||||
this.ui.attachmentUpload.on('send', (event) => {
|
||||
event.detail.promise = this.onSendAttachment(event)
|
||||
})
|
||||
|
||||
await this.bottle.container.Room.join()
|
||||
|
||||
@ -328,6 +333,10 @@ define([ './Chat/console'
|
||||
}
|
||||
}
|
||||
|
||||
async onSendAttachment(event) {
|
||||
return this.bottle.container.Messenger.pushAttachment(event.detail.tmpHash)
|
||||
}
|
||||
|
||||
onAutocomplete(event) {
|
||||
const input = event.target
|
||||
const value = input.getText(true)
|
||||
|
@ -1,10 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2018 Tim Düsterhus.
|
||||
* Copyright (c) 2010-2020 Tim Düsterhus.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License
|
||||
* included in the LICENSE file.
|
||||
*
|
||||
* Change Date: 2024-10-20
|
||||
* Change Date: 2024-11-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source
|
||||
* License, use of this software will be governed by version 2
|
||||
@ -56,6 +56,14 @@ define([ './console'
|
||||
return Ajax.api(this, payload)
|
||||
}
|
||||
|
||||
async pushAttachment(tmpHash) {
|
||||
const payload = { actionName: 'pushAttachment'
|
||||
, parameters: { tmpHash }
|
||||
}
|
||||
|
||||
return Ajax.api(this, payload)
|
||||
}
|
||||
|
||||
_ajaxSetup() {
|
||||
return { silent: true
|
||||
, ignoreError: true
|
||||
|
207
files_wcf/js/Bastelstu.be/Chat/Ui/Attachment/Upload.js
Normal file
207
files_wcf/js/Bastelstu.be/Chat/Ui/Attachment/Upload.js
Normal file
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2020 Tim Düsterhus.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License
|
||||
* included in the LICENSE file.
|
||||
*
|
||||
* Change Date: 2024-11-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source
|
||||
* License, use of this software will be governed by version 2
|
||||
* or later of the General Public License.
|
||||
*/
|
||||
|
||||
define([ 'WoltLabSuite/Core/Language'
|
||||
, 'WoltLabSuite/Core/Upload'
|
||||
, 'WoltLabSuite/Core/Dom/Change/Listener'
|
||||
, 'WoltLabSuite/Core/Dom/Util'
|
||||
, 'WoltLabSuite/Core/Ui/Dialog'
|
||||
, '../../DataStructure/EventEmitter'
|
||||
], function(Language, Upload, DomChangeListener, DomUtil, Dialog, EventEmitter) {
|
||||
"use strict";
|
||||
|
||||
const DIALOG_BUTTON_ID = 'chatAttachmentUploadButton'
|
||||
const DIALOG_CONTAINER_ID = 'chatAttachmentUploadDialog'
|
||||
|
||||
const DEPENDENCIES = [ 'UiInput', 'Room' ];
|
||||
class UiAttachmentUpload extends Upload {
|
||||
constructor(input, room) {
|
||||
const buttonContainer = document.querySelector(`#${DIALOG_CONTAINER_ID} > .upload`)
|
||||
const buttonContainerId = DomUtil.identify(buttonContainer)
|
||||
|
||||
const previewContainer = document.querySelector(`#${DIALOG_CONTAINER_ID} > .attachmentPreview`)
|
||||
const previewContainerId = DomUtil.identify(previewContainer)
|
||||
|
||||
super(buttonContainerId, previewContainerId, {
|
||||
className: 'wcf\\data\\attachment\\AttachmentAction',
|
||||
acceptableFiles: [ '.png', '.gif', '.jpg', '.jpeg' ]
|
||||
})
|
||||
|
||||
this.input = input
|
||||
this.room = room
|
||||
this.previewContainer = previewContainer
|
||||
this.tmpHash = undefined
|
||||
}
|
||||
|
||||
bootstrap() {
|
||||
this.uploadDescription = document.querySelector(`#${DIALOG_CONTAINER_ID} > small`)
|
||||
|
||||
const button = document.getElementById(DIALOG_BUTTON_ID)
|
||||
const container = document.getElementById(DIALOG_CONTAINER_ID)
|
||||
|
||||
elHide(container)
|
||||
container.classList.remove('jsStaticDialogContent')
|
||||
container.dataset.isStaticDialog = 'true'
|
||||
|
||||
if (button) {
|
||||
button.addEventListener('click', (event) => {
|
||||
event.preventDefault()
|
||||
|
||||
Dialog.openStatic(container.id, null, {
|
||||
title: elData(container, 'title'),
|
||||
onShow: () => this.showDialog()
|
||||
})
|
||||
})
|
||||
|
||||
const deleteAction = new WCF.Action.Delete('wcf\\data\\attachment\\AttachmentAction', `#${this.previewContainer.id} > p`)
|
||||
deleteAction.setCallback(() => this.closeDialog())
|
||||
|
||||
this.input.on('input', (event) => {
|
||||
if (event.target.input.value.length == 0) {
|
||||
button.classList.remove('disabled')
|
||||
}
|
||||
else {
|
||||
button.classList.add('disabled')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
closeDialog() {
|
||||
if (Dialog.getDialog(DIALOG_CONTAINER_ID)) {
|
||||
Dialog.close(DIALOG_CONTAINER_ID)
|
||||
}
|
||||
}
|
||||
|
||||
showDialog() {
|
||||
if (this._button.parentNode) {
|
||||
this._removeButton()
|
||||
}
|
||||
|
||||
this._target.innerHTML = ''
|
||||
this._createButton()
|
||||
elShow(this.uploadDescription)
|
||||
}
|
||||
|
||||
async send(tmpHash, event) {
|
||||
event.preventDefault()
|
||||
const parameters = { promise: Promise.resolve()
|
||||
, tmpHash
|
||||
}
|
||||
this.emit('send', parameters)
|
||||
|
||||
try {
|
||||
await parameters.promise
|
||||
this.closeDialog()
|
||||
}
|
||||
catch (error) {
|
||||
// TODO: Error handling
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
createButtonGroup(uploadId, objectId, tmpHash) {
|
||||
const buttonGroup = document.createElement('ul')
|
||||
buttonGroup.classList.add('buttonGroup')
|
||||
|
||||
let li = document.createElement('li')
|
||||
const cancelButton = document.createElement('span')
|
||||
cancelButton.classList.add('button', 'jsDeleteButton')
|
||||
cancelButton.dataset.objectId = objectId
|
||||
cancelButton.dataset.eventName = 'attachment'
|
||||
cancelButton.innerText = Language.get('wcf.global.button.cancel')
|
||||
li.appendChild(cancelButton)
|
||||
buttonGroup.appendChild(li)
|
||||
|
||||
li = document.createElement('li')
|
||||
const sendButton = document.createElement('span')
|
||||
sendButton.classList.add('button')
|
||||
sendButton.innerText = Language.get('wcf.global.button.submit')
|
||||
sendButton.addEventListener('click', (e) => this.send(tmpHash, e))
|
||||
li.appendChild(sendButton)
|
||||
buttonGroup.appendChild(li)
|
||||
|
||||
const target = this._fileElements[uploadId][0]
|
||||
target.appendChild(buttonGroup)
|
||||
|
||||
DomChangeListener.trigger()
|
||||
}
|
||||
|
||||
/**
|
||||
* @see WoltLabSuite/Core/Upload#_getParameters
|
||||
*/
|
||||
_getParameters() {
|
||||
this.tmpHash = [ ...crypto.getRandomValues(new Uint8Array(20)) ]
|
||||
.map(m => ('0' + m.toString(16)).slice(-2))
|
||||
.join('')
|
||||
|
||||
return { objectType: "be.bastelstu.chat.message"
|
||||
, parentObjectID: this.room.roomID
|
||||
, tmpHash: this.tmpHash
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see WoltLabSuite/Core/Upload#_success
|
||||
*/
|
||||
_success(uploadId, data, responseText, xhr, requestOptions) {
|
||||
if (data.returnValues?.errors?.[0]) {
|
||||
const error = data.returnValues.errors[0]
|
||||
|
||||
elInnerError(this._button, Language.get(`wcf.attachment.upload.error.${error.errorType}`, {
|
||||
filename: error.filename
|
||||
}))
|
||||
}
|
||||
else {
|
||||
elInnerError(this._button, '')
|
||||
}
|
||||
|
||||
if (data.returnValues?.attachments?.[uploadId]) {
|
||||
this._removeButton()
|
||||
elHide(this.uploadDescription)
|
||||
|
||||
const attachment = data.returnValues.attachments[uploadId]
|
||||
const url = attachment.thumbnailURL || attachment.tinyURL || attachment.url
|
||||
|
||||
if (!url) {
|
||||
throw new Error('Missing image URL')
|
||||
}
|
||||
|
||||
const target = this._fileElements[uploadId][0]
|
||||
const progress = target.querySelector(':scope > progress')
|
||||
|
||||
const img = document.createElement('img')
|
||||
img.setAttribute('src', url)
|
||||
img.setAttribute('alt', '')
|
||||
|
||||
if (url === attachment.thumbnailURL) {
|
||||
img.classList.add('attachmentThumbnail')
|
||||
}
|
||||
else if (url === attachment.tinyURL) {
|
||||
img.classList.add('attachmentTinyThumbnail')
|
||||
}
|
||||
|
||||
img.dataset.width = attachment.width
|
||||
img.dataset.height = attachment.height
|
||||
|
||||
DomUtil.replaceElement(progress, img)
|
||||
|
||||
this.createButtonGroup(uploadId, attachment.attachmentID, this.tmpHash)
|
||||
}
|
||||
}
|
||||
}
|
||||
UiAttachmentUpload.DEPENDENCIES = DEPENDENCIES
|
||||
EventEmitter(UiAttachmentUpload.prototype)
|
||||
|
||||
return UiAttachmentUpload
|
||||
})
|
@ -14,12 +14,13 @@
|
||||
define([ '../Ui' ], function (Ui) {
|
||||
"use strict";
|
||||
|
||||
const DEPENDENCIES = [ 'UiAutoAway'
|
||||
const DEPENDENCIES = [ 'UiAttachmentUpload'
|
||||
, 'UiAutoAway'
|
||||
, 'UiConnectionWarning'
|
||||
, 'UiInput'
|
||||
, 'UiInputAutocompleter'
|
||||
, 'UiMessageStream'
|
||||
, 'UiMessageActionDelete'
|
||||
, 'UiMessageStream'
|
||||
, 'UiMobile'
|
||||
, 'UiNotification'
|
||||
, 'UiReadMarker'
|
||||
@ -29,16 +30,17 @@ define([ '../Ui' ], function (Ui) {
|
||||
, 'UiUserList'
|
||||
]
|
||||
class Chat extends Ui {
|
||||
constructor(autoAway, connectionWarning, input, autocompleter, messageStream, messageActionDelete, mobile, notification, readMarker, settings, topic, userActionDropdownHandler, userList) {
|
||||
constructor(attachmentUpload, autoAway, connectionWarning, input, autocompleter, messageActionDelete, messageStream, mobile, notification, readMarker, settings, topic, userActionDropdownHandler, userList) {
|
||||
super()
|
||||
|
||||
this.actionDropdownHandler = userActionDropdownHandler
|
||||
this.attachmentUpload = attachmentUpload
|
||||
this.autoAway = autoAway
|
||||
this.autocompleter = autocompleter
|
||||
this.connectionWarning = connectionWarning
|
||||
this.input = input
|
||||
this.messageStream = messageStream
|
||||
this.messageActionDelete = messageActionDelete
|
||||
this.messageStream = messageStream
|
||||
this.mobile = mobile
|
||||
this.notification = notification
|
||||
this.readMarker = readMarker
|
||||
@ -49,12 +51,13 @@ define([ '../Ui' ], function (Ui) {
|
||||
|
||||
bootstrap() {
|
||||
this.actionDropdownHandler.bootstrap()
|
||||
this.attachmentUpload.bootstrap()
|
||||
this.autoAway.bootstrap()
|
||||
this.autocompleter.bootstrap()
|
||||
this.connectionWarning.bootstrap()
|
||||
this.input.bootstrap()
|
||||
this.messageStream.bootstrap()
|
||||
this.messageActionDelete.bootstrap()
|
||||
this.messageStream.bootstrap()
|
||||
this.mobile.bootstrap()
|
||||
this.notification.bootstrap()
|
||||
this.readMarker.bootstrap()
|
||||
|
@ -63,7 +63,7 @@ define([ './ToggleButton'
|
||||
*/
|
||||
setupMobile() {
|
||||
this.shadowToggleButton = document.createElement('span')
|
||||
this.shadowToggleButton.classList.add('smiliesToggleMobileButton')
|
||||
this.shadowToggleButton.classList.add('smiliesToggleMobileButton', 'button', 'small')
|
||||
this.shadowToggleButton.innerHTML = '<span class="icon icon24 fa-smile-o"></span>'
|
||||
this.shadowToggleButton.addEventListener('mousedown', this.onClick.bind(this))
|
||||
|
||||
|
@ -198,6 +198,7 @@
|
||||
<item name="wcf.acp.group.option.mod.chat.canMute"><![CDATA[Kann knebeln]]></item>
|
||||
<item name="wcf.acp.group.option.mod.chat.canMute.description"><![CDATA[Achtung: Diese Berechtigung kann nicht über Raumspezifische Rechte entzogen werden.]]></item>
|
||||
<item name="wcf.acp.group.option.mod.chat.canTeam"><![CDATA[Kann Teamnachrichten versenden]]></item>
|
||||
<item name="wcf.acp.group.option.user.chat.canAttach"><![CDATA[Kann Dateianhänge hochladen]]></item>
|
||||
<item name="wcf.acp.group.option.user.chat.canSee"><![CDATA[Kann Chaträume sehen]]></item>
|
||||
<item name="wcf.acp.group.option.user.chat.canSeeLog"><![CDATA[Kann das Protokoll sehen]]></item>
|
||||
<item name="wcf.acp.group.option.user.chat.canSetColor"><![CDATA[Kann den Benutzernamen färben]]></item>
|
||||
|
@ -198,6 +198,7 @@
|
||||
<item name="wcf.acp.group.option.mod.chat.canMute"><![CDATA[Can mute]]></item>
|
||||
<item name="wcf.acp.group.option.mod.chat.canMute.description"><![CDATA[Note: If this permission is granted it cannot be revoked in the room specific permissions.]]></item>
|
||||
<item name="wcf.acp.group.option.mod.chat.canTeam"><![CDATA[Can use team internal messages]]></item>
|
||||
<item name="wcf.acp.group.option.user.chat.canAttach"><![CDATA[Can upload attachments]]></item>
|
||||
<item name="wcf.acp.group.option.user.chat.canSee"><![CDATA[Can see chat rooms]]></item>
|
||||
<item name="wcf.acp.group.option.user.chat.canSeeLog"><![CDATA[Can see chat log]]></item>
|
||||
<item name="wcf.acp.group.option.user.chat.canSetColor"><![CDATA[Can choose to color their name]]></item>
|
||||
|
@ -132,6 +132,12 @@
|
||||
<definitionname>be.bastelstu.chat.messageType</definitionname>
|
||||
<classname>chat\system\message\type\WhisperMessageType</classname>
|
||||
</type>
|
||||
|
||||
<type>
|
||||
<name>be.bastelstu.chat.messageType.attachment</name>
|
||||
<definitionname>be.bastelstu.chat.messageType</definitionname>
|
||||
<classname>chat\system\message\type\AttachmentMessageType</classname>
|
||||
</type>
|
||||
<!-- /message types -->
|
||||
|
||||
<!-- suspensions -->
|
||||
@ -168,5 +174,13 @@
|
||||
<points>1</points>
|
||||
</type>
|
||||
<!-- /activity points -->
|
||||
|
||||
<!-- attachments -->
|
||||
<type>
|
||||
<name>be.bastelstu.chat.message</name>
|
||||
<definitionname>com.woltlab.wcf.attachment.objectType</definitionname>
|
||||
<classname>chat\system\attachment\MessageAttachmentObjectType</classname>
|
||||
</type>
|
||||
<!-- attachments -->
|
||||
</import>
|
||||
</data>
|
||||
|
19
templates/__attachmentDialog.tpl
Normal file
19
templates/__attachmentDialog.tpl
Normal file
@ -0,0 +1,19 @@
|
||||
<div id="chatAttachmentUploadDialog" class="jsStaticDialogContent" data-title="{lang}wcf.attachment.attachments{/lang}">
|
||||
<div class="attachmentPreview"></div>
|
||||
|
||||
{* placeholder for the upload button *}
|
||||
<div class="upload"></div>
|
||||
<small>{lang}wcf.attachment.upload.limits{/lang}</small>
|
||||
</div>
|
||||
<script data-relocate="true">
|
||||
require([ 'Language' ], function (Language) {
|
||||
Language.addObject({
|
||||
'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.attachment.upload.error.uploadPhpLimit': '{lang}wcf.attachment.upload.error.uploadPhpLimit{/lang}',
|
||||
})
|
||||
})
|
||||
</script>
|
@ -433,6 +433,37 @@
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="x-text/template" data-application="be.bastelstu.chat" data-template-name="be-bastelstu-chat-messageType-attachment" data-template-includes="DeleteButton">
|
||||
<div class="chatMessageContainer">
|
||||
<div class="chatMessageSide">
|
||||
<div class="chatUserAvatar jsUserActionDropdown" data-user-id="{$author.userID}">
|
||||
<a href="{$author.link}">{@$author.image32}</a>
|
||||
</div>
|
||||
<time><a href="{$message.link}">{$message.formattedTime}</a></time>
|
||||
</div>
|
||||
<div class="chatMessageContent">
|
||||
<div class="chatMessageHeader">
|
||||
<span class="username">
|
||||
<a href="{$author.link}" class="jsUserActionDropdown" data-user-id="{$author.userID}">
|
||||
{@$author.coloredUsername}
|
||||
</a>
|
||||
</span>
|
||||
<small class="separatorLeft">
|
||||
<time><a href="{$message.link}">{$message.formattedTime}</a></time>
|
||||
</small>
|
||||
</div>
|
||||
<div class="chatMessage htmlContent">{@$message.payload.formattedMessage}</div>
|
||||
</div>
|
||||
<ul class="buttonGroup buttonList smallButtons">
|
||||
{/literal}
|
||||
{if $__wcf->session->getPermission('mod.chat.canDelete')}
|
||||
{ldelim}include file=$t.DeleteButton}
|
||||
{/if}
|
||||
{literal}
|
||||
</ul>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="x-text/template" data-application="be.bastelstu.chat" data-template-name="be-bastelstu-chat-messageType-color">
|
||||
<div class="chatMessageContainer inline">
|
||||
<div class="chatMessageSide">
|
||||
|
@ -54,10 +54,20 @@
|
||||
|
||||
<div id="chatInputContainer">
|
||||
<div>
|
||||
<textarea maxlength="{CHAT_MAX_LENGTH}" class="long"></textarea>
|
||||
<span id="chatQuickSettings">
|
||||
<span class="icon icon24 fa-ellipsis-v"></span>
|
||||
</span>
|
||||
{if $__wcf->getSession()->getPermission('user.chat.canAttach')}
|
||||
<div class="chatAttachButton">
|
||||
<span id="chatAttachmentUploadButton" class="button small" title="{lang}wcf.attachment.attachments{/lang}">
|
||||
<span class="icon icon16 fa-paperclip"></span>
|
||||
<span class="icon icon24 fa-paperclip"></span>
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="chatInputWrapper">
|
||||
<textarea maxlength="{CHAT_MAX_LENGTH}" class="long"></textarea>
|
||||
<span id="chatQuickSettings">
|
||||
<span class="icon icon24 fa-ellipsis-v"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<small class="innerError" style="display: none"></small>
|
||||
<span class="charCounter dimmed"></span>
|
||||
@ -71,6 +81,7 @@
|
||||
{include file='messageTypes' application='chat'}
|
||||
{include file='userList' application='chat'}
|
||||
{include file='userListDropdownMenuItems' application='chat'}
|
||||
{include file='__attachmentDialog' application='chat'}
|
||||
|
||||
{if !ENABLE_DEBUG_MODE}{js application='wcf' file='Bastelstu.be.Chat'}{/if}
|
||||
<script data-relocate="true">
|
||||
|
@ -49,6 +49,12 @@
|
||||
<admindefaultvalue>1</admindefaultvalue>
|
||||
<usersonly>1</usersonly>
|
||||
</option>
|
||||
<option name="user.chat.canAttach">
|
||||
<categoryname>user.chat</categoryname>
|
||||
<optiontype>boolean</optiontype>
|
||||
<defaultvalue>1</defaultvalue>
|
||||
<usersonly>1</usersonly>
|
||||
</option>
|
||||
<option name="user.chat.disallowedBBCodes">
|
||||
<categoryname>user.chat</categoryname>
|
||||
<optiontype>BBCodeSelect</optiontype>
|
||||
|
Loading…
Reference in New Issue
Block a user