mirror of
https://github.com/wbbaddons/Tims-Chat.git
synced 2024-12-21 21:30:08 +00:00
Implement attachment upload UI skeleton
This commit is contained in:
parent
d07d18a0cb
commit
d5195c0562
@ -25,6 +25,13 @@
|
|||||||
class RoomPage extends \wcf\page\AbstractPage {
|
class RoomPage extends \wcf\page\AbstractPage {
|
||||||
use TConfiguredPage;
|
use TConfiguredPage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Almost dummy attachment handler (used in language variable)
|
||||||
|
*
|
||||||
|
* @var \wcf\system\attachment\AttachmentHandler
|
||||||
|
*/
|
||||||
|
public $attachmentHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
@ -65,7 +72,7 @@ public function readParameters() {
|
|||||||
*/
|
*/
|
||||||
public function checkPermissions() {
|
public function checkPermissions() {
|
||||||
parent::checkPermissions();
|
parent::checkPermissions();
|
||||||
|
|
||||||
$package = \wcf\data\package\PackageCache::getInstance()->getPackageByIdentifier('be.bastelstu.chat');
|
$package = \wcf\data\package\PackageCache::getInstance()->getPackageByIdentifier('be.bastelstu.chat');
|
||||||
if (stripos($package->packageVersion, 'Alpha') !== false) {
|
if (stripos($package->packageVersion, 'Alpha') !== false) {
|
||||||
$sql = "SELECT COUNT(*) FROM wcf".WCF_N."_user";
|
$sql = "SELECT COUNT(*) FROM wcf".WCF_N."_user";
|
||||||
@ -91,6 +98,9 @@ public function readData() {
|
|||||||
|
|
||||||
parent::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 = \wcf\system\push\PushHandler::getInstance();
|
||||||
$pushHandler->joinChannel('be.bastelstu.chat');
|
$pushHandler->joinChannel('be.bastelstu.chat');
|
||||||
$pushHandler->joinChannel('be.bastelstu.chat.room-'.$this->room->roomID);
|
$pushHandler->joinChannel('be.bastelstu.chat.room-'.$this->room->roomID);
|
||||||
@ -104,6 +114,7 @@ public function assignVariables() {
|
|||||||
|
|
||||||
WCF::getTPL()->assign([ 'room' => $this->room
|
WCF::getTPL()->assign([ 'room' => $this->room
|
||||||
, 'config' => $this->getConfig()
|
, 'config' => $this->getConfig()
|
||||||
|
, 'attachmentHandler' => $this->attachmentHandler
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ define([ './Chat/console'
|
|||||||
, './Chat/ProfileStore'
|
, './Chat/ProfileStore'
|
||||||
, './Chat/Room'
|
, './Chat/Room'
|
||||||
, './Chat/Template'
|
, './Chat/Template'
|
||||||
|
, './Chat/Ui/Attachment/Upload'
|
||||||
, './Chat/Ui/AutoAway'
|
, './Chat/Ui/AutoAway'
|
||||||
, './Chat/Ui/Chat'
|
, './Chat/Ui/Chat'
|
||||||
, './Chat/Ui/ConnectionWarning'
|
, './Chat/Ui/ConnectionWarning'
|
||||||
@ -43,7 +44,7 @@ define([ './Chat/console'
|
|||||||
, './Chat/Ui/UserActionDropdownHandler'
|
, './Chat/Ui/UserActionDropdownHandler'
|
||||||
, './Chat/Ui/UserList'
|
, './Chat/Ui/UserList'
|
||||||
], function (console, Bottle, Push, Core, Language, RepeatingTimer, CoreUser, Autocompleter,
|
], 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,
|
UiConnectionWarning, ErrorDialog, UiInput, UiInputAutocompleter, UiMessageStream, UiMessageActionDelete, UiMobile, UiNotification,
|
||||||
UiReadMarker, UiSettings, UiTopic, UiUserActionDropdownHandler, UiUserList) {
|
UiReadMarker, UiSettings, UiTopic, UiUserActionDropdownHandler, UiUserList) {
|
||||||
"use strict";
|
"use strict";
|
||||||
@ -85,6 +86,7 @@ define([ './Chat/console'
|
|||||||
this.service('UiTopic', UiTopic)
|
this.service('UiTopic', UiTopic)
|
||||||
this.service('UiUserActionDropdownHandler', UiUserActionDropdownHandler)
|
this.service('UiUserActionDropdownHandler', UiUserActionDropdownHandler)
|
||||||
this.service('UiUserList', UiUserList)
|
this.service('UiUserList', UiUserList)
|
||||||
|
this.service('UiAttachmentUpload', UiAttachmentUpload)
|
||||||
|
|
||||||
// Register Models
|
// Register Models
|
||||||
this.bottle.instanceFactory('Message', (container, m) => {
|
this.bottle.instanceFactory('Message', (container, m) => {
|
||||||
|
195
files_wcf/js/Bastelstu.be/Chat/Ui/Attachment/Upload.js
Normal file
195
files_wcf/js/Bastelstu.be/Chat/Ui/Attachment/Upload.js
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* 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 = [ 'Room' ];
|
||||||
|
class UiAttachmentUpload extends Upload {
|
||||||
|
constructor(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.room = room
|
||||||
|
this.previewContainer = previewContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(event) {
|
||||||
|
event.preventDefault()
|
||||||
|
const parameters = { promise: Promise.resolve() }
|
||||||
|
this.emit('send', parameters)
|
||||||
|
|
||||||
|
try {
|
||||||
|
await parameters.promise
|
||||||
|
this.closeDialog()
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
// TODO: Error handling
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createButtonGroup(uploadId, objectID) {
|
||||||
|
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.dataset.objectId = objectID
|
||||||
|
sendButton.innerText = Language.get('wcf.global.button.submit')
|
||||||
|
sendButton.addEventListener('click', (e) => this.send(e))
|
||||||
|
li.appendChild(sendButton)
|
||||||
|
buttonGroup.appendChild(li)
|
||||||
|
|
||||||
|
const target = this._fileElements[uploadId][0]
|
||||||
|
target.appendChild(buttonGroup)
|
||||||
|
|
||||||
|
DomChangeListener.trigger()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see WoltLabSuite/Core/Upload#_getParameters
|
||||||
|
*/
|
||||||
|
_getParameters() {
|
||||||
|
const hash = [ ...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: hash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UiAttachmentUpload.DEPENDENCIES = DEPENDENCIES
|
||||||
|
EventEmitter(UiAttachmentUpload.prototype)
|
||||||
|
|
||||||
|
return UiAttachmentUpload
|
||||||
|
})
|
@ -14,7 +14,8 @@
|
|||||||
define([ '../Ui' ], function (Ui) {
|
define([ '../Ui' ], function (Ui) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const DEPENDENCIES = [ 'UiAutoAway'
|
const DEPENDENCIES = [ 'UiAttachmentUpload'
|
||||||
|
, 'UiAutoAway'
|
||||||
, 'UiConnectionWarning'
|
, 'UiConnectionWarning'
|
||||||
, 'UiInput'
|
, 'UiInput'
|
||||||
, 'UiInputAutocompleter'
|
, 'UiInputAutocompleter'
|
||||||
@ -29,7 +30,7 @@ define([ '../Ui' ], function (Ui) {
|
|||||||
, 'UiUserList'
|
, 'UiUserList'
|
||||||
]
|
]
|
||||||
class Chat extends Ui {
|
class Chat extends Ui {
|
||||||
constructor(autoAway, connectionWarning, input, autocompleter, messageStream, messageActionDelete, mobile, notification, readMarker, settings, topic, userActionDropdownHandler, userList) {
|
constructor(attachmentUpload, autoAway, connectionWarning, input, autocompleter, messageStream, messageActionDelete, mobile, notification, readMarker, settings, topic, userActionDropdownHandler, userList) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
this.actionDropdownHandler = userActionDropdownHandler
|
this.actionDropdownHandler = userActionDropdownHandler
|
||||||
@ -45,6 +46,7 @@ define([ '../Ui' ], function (Ui) {
|
|||||||
this.settings = settings
|
this.settings = settings
|
||||||
this.topic = topic
|
this.topic = topic
|
||||||
this.userList = userList
|
this.userList = userList
|
||||||
|
this.attachmentUpload = attachmentUpload
|
||||||
}
|
}
|
||||||
|
|
||||||
bootstrap() {
|
bootstrap() {
|
||||||
@ -61,6 +63,7 @@ define([ '../Ui' ], function (Ui) {
|
|||||||
this.settings.bootstrap()
|
this.settings.bootstrap()
|
||||||
this.topic.bootstrap()
|
this.topic.bootstrap()
|
||||||
this.userList.bootstrap()
|
this.userList.bootstrap()
|
||||||
|
this.attachmentUpload.bootstrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Chat.DEPENDENCIES = DEPENDENCIES
|
Chat.DEPENDENCIES = DEPENDENCIES
|
||||||
|
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>
|
@ -4,6 +4,9 @@
|
|||||||
<li><a class="button" href="#" data-module="Bastelstu.be/Chat/Ui/Settings/FullscreenButton"><span class="icon icon16 fa-arrows-alt"></span> <span>{lang}chat.room.button.fullscreen{/lang}</span></a></li>
|
<li><a class="button" href="#" data-module="Bastelstu.be/Chat/Ui/Settings/FullscreenButton"><span class="icon icon16 fa-arrows-alt"></span> <span>{lang}chat.room.button.fullscreen{/lang}</span></a></li>
|
||||||
<li><a class="button" href="#" data-module="Bastelstu.be/Chat/Ui/Settings/NotificationsButton"><span class="icon icon16 fa-bell-o"></span> <span>{lang}chat.room.button.notifications{/lang}</span></a></li>
|
<li><a class="button" href="#" data-module="Bastelstu.be/Chat/Ui/Settings/NotificationsButton"><span class="icon icon16 fa-bell-o"></span> <span>{lang}chat.room.button.notifications{/lang}</span></a></li>
|
||||||
<li><a class="button" href="#" data-module="Bastelstu.be/Chat/Ui/Settings/AutoscrollButton"><span class="icon icon16 fa-arrow-down"></span> <span>{lang}chat.room.button.autoscroll{/lang}</span></a></li>
|
<li><a class="button" href="#" data-module="Bastelstu.be/Chat/Ui/Settings/AutoscrollButton"><span class="icon icon16 fa-arrow-down"></span> <span>{lang}chat.room.button.autoscroll{/lang}</span></a></li>
|
||||||
|
{if $__wcf->getSession()->getPermission('user.chat.canAttach')}
|
||||||
|
<li><a id="chatAttachmentUploadButton" class="button" href="#"><span class="icon icon16 fa-paperclip"></span> <span>{lang}wcf.attachment.attachments{/lang}</span></a>
|
||||||
|
{/if}
|
||||||
{event name='buttons'}
|
{event name='buttons'}
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -71,6 +71,7 @@
|
|||||||
{include file='messageTypes' application='chat'}
|
{include file='messageTypes' application='chat'}
|
||||||
{include file='userList' application='chat'}
|
{include file='userList' application='chat'}
|
||||||
{include file='userListDropdownMenuItems' application='chat'}
|
{include file='userListDropdownMenuItems' application='chat'}
|
||||||
|
{include file='__attachmentDialog' application='chat'}
|
||||||
|
|
||||||
{if !ENABLE_DEBUG_MODE}{js application='wcf' file='Bastelstu.be.Chat'}{/if}
|
{if !ENABLE_DEBUG_MODE}{js application='wcf' file='Bastelstu.be.Chat'}{/if}
|
||||||
<script data-relocate="true">
|
<script data-relocate="true">
|
||||||
|
Loading…
Reference in New Issue
Block a user