1
0
mirror of https://github.com/wbbaddons/Tims-Chat.git synced 2024-12-22 21:40:08 +00:00

Merge remote-tracking branch 'origin/privateChannels'

This commit is contained in:
Tim Düsterhus 2013-07-24 16:22:20 +02:00
commit 0be6efa345
4 changed files with 216 additions and 21 deletions

View File

@ -33,13 +33,17 @@ exposed by a function if necessary.
newMessageCount = 0 newMessageCount = 0
scrollUpNotifications = off scrollUpNotifications = off
chatSession = Date.now() chatSession = Date.now()
userList =
current: {}
allTime: {}
currentRoom = {}
errorVisible = false errorVisible = false
inputErrorHidingTimer = null inputErrorHidingTimer = null
lastMessage = null lastMessage = null
openChannel = 0 openChannel = 0
remainingFailures = 3 remainingFailures = 3
events = events =
@ -113,6 +117,11 @@ Insert the appropriate smiley code into the input when a smiley is clicked.
$('#smilies').on 'click', 'img', -> $('#smilies').on 'click', 'img', ->
insertText " #{$(@).attr('alt')} " insertText " #{$(@).attr('alt')} "
Handle private channel menu
$('#privateChannelsMenu').on 'click', '.privateChannel', ->
openPrivateChannel $(@).data 'privateChannelID'
Handle submitting the form. The message will be validated by some basic checks, passed to the `submit` eventlisteners Handle submitting the form. The message will be validated by some basic checks, passed to the `submit` eventlisteners
and afterwards sent to the server by an AJAX request. and afterwards sent to the server by an AJAX request.
@ -125,7 +134,7 @@ and afterwards sent to the server by an AJAX request.
return false if text.length is 0 return false if text.length is 0
unless openChannel is 0 unless openChannel is 0
text = "/whisper #{$("#timsChatMessageContainer#{openChannel}").data 'username'}, #{text}" text = "/whisper #{userList.allTime[openChannel].username}, #{text}"
# Free the fish! # Free the fish!
do freeTheFish if text.toLowerCase() is '/free the fish' do freeTheFish if text.toLowerCase() is '/free the fish'
@ -190,7 +199,10 @@ The the word the caret is in will be passed to `autocomplete` and replaced if a
toComplete = '/' + commands[autocomplete.offset++ % commands.length] + ' ' if commands.length isnt 0 toComplete = '/' + commands[autocomplete.offset++ % commands.length] + ' ' if commands.length isnt 0
else else
regex = new RegExp "^#{WCF.String.escapeRegExp toComplete}", "i" regex = new RegExp "^#{WCF.String.escapeRegExp toComplete}", "i"
users = (username for user in $('.timsChatUser') when regex.test(username = $(user).data('username')))
users = [ ]
for userID, user of userList.current
users.push user.username if regex.test user.username
toComplete = users[autocomplete.offset++ % users.length] + ', ' if users.length isnt 0 toComplete = users[autocomplete.offset++ % users.length] + ', ' if users.length isnt 0
@ -267,8 +279,11 @@ Toggle checkboxes.
Hide topic container. Hide topic container.
$('.jsTopicCloser').on 'click', -> $('.jsTopicCloser').on 'click', ->
$('#timsChatTopic').addClass 'hidden' if $('.timsChatMessageContainer.active').data('userID') is 0
$('#timsChatTopic').addClass 'hidden'
else
closePrivateChannel $('.timsChatMessageContainer.active').data('userID')
Visibly mark the message once the associated checkbox is checked. Visibly mark the message once the associated checkbox is checked.
$(document).on 'click', '.timsChatMessage :checkbox', (event) -> $(document).on 'click', '.timsChatMessage :checkbox', (event) ->
@ -438,10 +453,10 @@ Insert the given messages into the chat stream.
$('.timsChatMessageContainer.active').trigger 'scroll' $('.timsChatMessageContainer.active').trigger 'scroll'
for message in messages for message in messages
message.isInPrivateChannel = (String(message.type) is v.config.messageTypes.WHISPER) and ($.wcfIsset("timsChatMessageContainer#{message.receiver}") or $.wcfIsset("timsChatMessageContainer#{message.sender}"))
events.newMessage.fire message events.newMessage.fire message
message.isInPrivateChannel = (String(message.type) is v.config.messageTypes.WHISPER) and ($.wcfIsset("timsChatMessageContainer#{message.receiver}") or $.wcfIsset("timsChatMessageContainer#{message.sender}"))
createNewMessage = yes createNewMessage = yes
if $('.timsChatMessage:last-child .text').is('ul') and lastMessage isnt null and lastMessage.type in [ 0, 7 ] if $('.timsChatMessage:last-child .text').is('ul') and lastMessage isnt null and lastMessage.type in [ 0, 7 ]
if lastMessage.type is message.type and lastMessage.sender is message.sender and lastMessage.receiver is message.receiver and lastMessage.isInPrivateChannel is message.isInPrivateChannel if lastMessage.type is message.type and lastMessage.sender is message.sender and lastMessage.receiver is message.receiver and lastMessage.isInPrivateChannel is message.isInPrivateChannel
@ -488,9 +503,12 @@ Rebuild the userlist based on the given `users`.
handleUsers = (users) -> handleUsers = (users) ->
foundUsers = { } foundUsers = { }
userList.current = { }
for user in users for user in users
do (user) -> do (user) ->
userList.current[user.userID] = userList.allTime[user.userID] = user
id = "timsChatUser#{user.userID}" id = "timsChatUser#{user.userID}"
Move the user to the new position if he was found in the old list. Move the user to the new position if he was found in the old list.
@ -583,6 +601,17 @@ Send out notifications for the given `message`. The number of unread messages wi
if scrollUpNotifications if scrollUpNotifications
$('.timsChatMessageContainer.active').addClass 'notification' $('.timsChatMessageContainer.active').addClass 'notification'
if message.isInPrivateChannel
if message.sender is WCF.User.userID
privateChannelID = message.receiver
else
privateChannelID = message.sender
if $('.timsChatMessageContainer.active').data('userID') isnt privateChannelID
$("#privateChannel#{privateChannelID}").addClass 'notify'
else if $('.timsChatMessageContainer.active').data('userID') isnt 0
$("#privateChannel0").addClass 'notify'
return if isActive or $('#timsChatNotify').data('status') is 0 return if isActive or $('#timsChatNotify').data('status') is 0
document.title = v.titleTemplate.fetch document.title = v.titleTemplate.fetch
@ -678,45 +707,97 @@ Joins a room.
loading = false loading = false
$('#timsChatTopic').removeClass 'hidden' $('#timsChatTopic').removeClass 'hidden'
currentRoom = data.returnValues
currentRoom.roomID = roomID
$('#timsChatTopic > .topic').text data.returnValues.topic $('#timsChatTopic > .topic').text currentRoom.topic
if data.returnValues.topic.trim() is '' if currentRoom.topic.trim() is ''
$('#timsChatTopic').addClass 'empty' $('#timsChatTopic').addClass 'empty'
else else
$('#timsChatTopic').removeClass 'empty' $('#timsChatTopic').removeClass 'empty'
$('.timsChatMessage').addClass 'unloaded' $('.timsChatMessage').addClass 'unloaded'
document.title = v.titleTemplate.fetch data.returnValues document.title = v.titleTemplate.fetch currentRoom
handleMessages data.returnValues.messages handleMessages currentRoom.messages
do getMessages do getMessages
do refreshRoomList do refreshRoomList
failure: -> failure: ->
showError WCF.Language.get 'chat.error.join' showError WCF.Language.get 'chat.error.join'
Open private channel Open private channel
openPrivateChannel = (userID) -> openPrivateChannel = (userID) ->
userID = parseInt userID
console.log "Opening private channel #{userID}"
unless $.wcfIsset "timsChatMessageContainer#{userID}" unless $.wcfIsset "timsChatMessageContainer#{userID}"
return unless $.wcfIsset "timsChatUser#{userID}" return unless userList.allTime[userID]?
div = $('<div>') div = $ '<div>'
div.attr 'id', "timsChatMessageContainer#{userID}" div.attr 'id', "timsChatMessageContainer#{userID}"
div.data 'userID', userID
div.addClass 'timsChatMessageContainer' div.addClass 'timsChatMessageContainer'
div.addClass 'marginTop' div.addClass 'marginTop'
div.addClass 'container' div.addClass 'container'
div.data 'username', $("#timsChatUser#{userID}").data 'username'
div.wrapInner '<ul>' div.wrapInner '<ul>'
$('#timsChatMessageContainer0').after div $('#timsChatMessageContainer0').after div
$('.privateChannel').removeClass 'active'
if userID isnt 0
$('#timsChatTopic').removeClass 'hidden empty'
$('#timsChatTopic > .topic').text 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}"
li = $ '<li>'
li.attr 'id', "privateChannel#{userID}"
li.data 'privateChannelID', userID
li.addClass 'privateChannel'
span = $ '<span class="userAvatar framed" />'
avatar = $ userList.allTime[userID].avatar[16]
avatar.addClass 'jsTooltip'
avatar.attr 'title', userList.allTime[userID].username
avatar.wrap span
li.append avatar.parent().addClass 'small'
avatar = $ userList.allTime[userID].avatar[32]
avatar.addClass 'jsTooltip'
avatar.attr 'title', userList.allTime[userID].username
avatar.wrap span
li.append avatar.parent().addClass 'large'
$('#privateChannelsMenu ul').append li
$('#privateChannelsMenu').addClass 'shown'
else
$('#timsChatTopic > .topic').text currentRoom.topic
$('#timsChatTopic > .jsTopicCloser').attr 'title', WCF.Language.get 'chat.general.closeTopic'
if currentRoom.topic.trim() is ''
$('#timsChatTopic').addClass 'empty'
else
$('#timsChatTopic').removeClass 'empty'
do WCF.DOMNodeInsertedHandler.execute
$('.timsChatMessageContainer').removeClass 'active' $('.timsChatMessageContainer').removeClass 'active'
$("#timsChatMessageContainer#{userID}").addClass 'active' $("#timsChatMessageContainer#{userID}").addClass 'active'
$("#privateChannel#{userID}").addClass('active').removeClass 'notify'
openChannel = userID openChannel = userID
Close private channel Close private channel
closePrivateChannel = (userID) -> closePrivateChannel = (userID) ->
do $("#timsChatMessageContainer#{userID}").remove unless userID is 0 unless userID is 0
do $("#privateChannel#{userID}").remove
do $("#timsChatMessageContainer#{userID}").remove
if $('#privateChannelsMenu li').length <= 1
$('#privateChannelsMenu').removeClass 'shown'
openPrivateChannel 0 openPrivateChannel 0
Bind the given callback to the given event. Bind the given callback to the given event.
@ -749,7 +830,7 @@ And finally export the public methods and variables.
listener: listener:
add: addListener add: addListener
remove: removeListener remove: removeListener
window.be ?= {} window.be ?= {}
be.bastelstu ?= {} be.bastelstu ?= {}
window.be.bastelstu.Chat = Chat window.be.bastelstu.Chat = Chat

View File

@ -58,6 +58,100 @@
} }
} }
#privateChannelsMenu {
.transition(opacity, .2s);
.marginTop;
z-index: -1;
position: absolute;
opacity: 0;
&.shown {
opacity: 1;
z-index: 130;
~ .timsChatMessageContainer {
margin-left: 35px;
border-top-left-radius: 0;
}
}
> ul {
text-align: right;
> li:first-child {
> .userAvatar.framed {
img, > canvas, > .icon {
border-radius: @wcfContainerBorderRadius 0 0 0;
}
}
}
> li:last-child {
> .userAvatar.framed {
img, > canvas, > .icon {
border-radius: 0 0 0 @wcfContainerBorderRadius;
}
}
}
> li {
margin-bottom: -1px;
background-color: @wcfContainerBackgroundColor;
> .userAvatar, .userAvatar > .icon {
cursor: pointer;
}
> .userAvatar {
&.large {
display: none;
}
&.small {
display: block;
}
&.framed {
> .icon {
background-color: @wcfContentBackgroundColor;
border: 1px solid @wcfContainerBorderColor;
padding: 1px;
}
}
}
&.active {
> .userAvatar {
&.large {
display: block;
}
&.small {
display: none;
}
&.framed {
> img, > canvas, > .icon {
border-right-color: @wcfContentBackgroundColor;
border-radius: @wcfContainerBorderRadius 0 0 @wcfContainerBorderRadius;
}
}
}
}
&.notify {
> .userAvatar {
> * {
// TODO
opacity: .4;
}
}
}
}
}
}
.timsChatMessageContainer { .timsChatMessageContainer {
height: 320px; height: 320px;
overflow-y: scroll; overflow-y: scroll;

View File

@ -137,6 +137,10 @@
<item name="chat.general.information"><![CDATA[Information]]></item> <item name="chat.general.information"><![CDATA[Information]]></item>
<item name="chat.general.information.chatUpdate"><![CDATA[Der Chat wurde aktualisiert. Bitte laden Sie die Seite neu, da es sonst zu Fehlern kommen kann.]]></item> <item name="chat.general.information.chatUpdate"><![CDATA[Der Chat wurde aktualisiert. Bitte laden Sie die Seite neu, da es sonst zu Fehlern kommen kann.]]></item>
<item name="chat.general.information.suspension"><![CDATA[{lang}chat.suspension.{$suspension->type}{/lang} ({if $room}{$room}{else}{lang}chat.room.global{/lang}{/if})]]></item> <item name="chat.general.information.suspension"><![CDATA[{lang}chat.suspension.{$suspension->type}{/lang} ({if $room}{$room}{else}{lang}chat.room.global{/lang}{/if})]]></item>
<item name="chat.general.privateChannelTopic"><![CDATA[{literal}Sie befinden sich in einem privaten Kanal mit „{$username}“, um diesen zu schließen, klicken Sie einfach auf das Kreuz rechts.{/literal}]]></item>
<item name="chat.general.closePrivateChannel"><![CDATA[Privaten Kanal schließen]]></item>
<item name="chat.general.closeTopic"><![CDATA[Thema ausblenden]]></item>
</category> </category>
<category name="chat.header"> <category name="chat.header">

View File

@ -15,6 +15,9 @@
'chat.general.ban': '{lang}chat.general.ban{/lang}', 'chat.general.ban': '{lang}chat.general.ban{/lang}',
'chat.general.profile': '{lang}chat.general.profile{/lang}', 'chat.general.profile': '{lang}chat.general.profile{/lang}',
'chat.general.notify.title': '{lang}chat.general.notify.title{/lang}', 'chat.general.notify.title': '{lang}chat.general.notify.title{/lang}',
'chat.general.privateChannelTopic': '{lang}chat.general.privateChannelTopic{/lang}',
'chat.general.closePrivateChannel': '{lang}chat.general.closePrivateChannel{/lang}',
'chat.general.closeTopic': '{lang}chat.general.closeTopic{/lang}',
'chat.error.onMessageLoad': '{lang}chat.error.onMessageLoad{/lang}', 'chat.error.onMessageLoad': '{lang}chat.error.onMessageLoad{/lang}',
'chat.error.duplicateTab': '{lang}chat.error.duplicateTab{/lang}', 'chat.error.duplicateTab': '{lang}chat.error.duplicateTab{/lang}',
'chat.error.join': '{lang}chat.error.join{/lang}', 'chat.error.join': '{lang}chat.error.join{/lang}',
@ -71,11 +74,24 @@
{include file='header' sandbox=false sidebarOrientation='right'} {include file='header' sandbox=false sidebarOrientation='right'}
<div id="timsChatTopic" class="container{if $room->topic|language === ''} empty{/if}"> <div id="timsChatTopic" class="container{if $room->topic|language === ''} empty{/if}">
<span class="icon icon16 icon-remove jsTopicCloser"></span> <span class="icon icon16 icon-remove jsTopicCloser jsTooltip" title="{lang}chat.general.closeTopic{/lang}"></span>
<span class="topic">{$room->topic|language}</span> <span class="topic">{$room->topic|language}</span>
</div> </div>
<div id="timsChatMessageContainer0" class="timsChatMessageContainer marginTop container active"> <div id="privateChannelsMenu">
<ul>
<li id="privateChannel0" class="privateChannel active" data-private-channel-id="0">
<span class="userAvatar framed small">
<span class="icon icon16 icon-comment-alt jsTooltip" title="{lang}chat.general.room{/lang}"></span>
</span>
<span class="userAvatar framed large">
<span class="icon icon32 icon-comment-alt jsTooltip" title="{lang}chat.general.room{/lang}"></span>
</span>
</li>
</ul>
</div>
<div id="timsChatMessageContainer0" class="timsChatMessageContainer marginTop container active" data-user-id="0">
<p class="error noJsOnly" style="display: none;">{lang}chat.general.noJs{/lang}</p> <p class="error noJsOnly" style="display: none;">{lang}chat.general.noJs{/lang}</p>
<ul> <ul>
</ul> </ul>