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

Merge branch 'frontend'

Conflicts:
	template/chat.tpl

Closes #52
Closes #54
Closes #55
See #57
Closes #68
Closes #70
This commit is contained in:
Tim Düsterhus 2014-02-27 22:40:45 +01:00
commit fff9b18cc3
16 changed files with 889 additions and 722 deletions

View File

@ -3,7 +3,7 @@
<thead> <thead>
<tr> <tr>
<th>{lang}wcf.global.objectID{/lang}</th> <th>{lang}wcf.global.objectID{/lang}</th>
<th>{lang}chat.general.time{/lang}</th> <th>{lang}chat.global.time{/lang}</th>
<th colspan="2">{lang}wcf.user.username{/lang}</th> <th colspan="2">{lang}wcf.user.username{/lang}</th>
<th>{lang}chat.acp.log.message{/lang}</th> <th>{lang}chat.acp.log.message{/lang}</th>
</tr> </tr>

View File

@ -66,7 +66,7 @@
</dl> </dl>
<dl> <dl>
<dt><label for="roomID">{lang}chat.general.room{/lang}</label></dt> <dt><label for="roomID">{lang}chat.global.room{/lang}</label></dt>
<dd> <dd>
<select id="roomID" name="roomID"> <select id="roomID" name="roomID">
<option value="-1"{if $roomID == -1} selected="selected"{/if}></option> <option value="-1"{if $roomID == -1} selected="selected"{/if}></option>
@ -120,10 +120,10 @@
<tr> <tr>
<th class="columnID{if $sortField == 'suspensionID'} active {@$sortOrder}{/if}" colspan="2"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=suspensionID&sortOrder={if $sortField == 'suspensionID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}wcf.global.objectID{/lang}</a></th> <th class="columnID{if $sortField == 'suspensionID'} active {@$sortOrder}{/if}" colspan="2"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=suspensionID&sortOrder={if $sortField == 'suspensionID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}wcf.global.objectID{/lang}</a></th>
<th class="columnUsername{if $sortField == 'username'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=username&sortOrder={if $sortField == 'username' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}wcf.user.username{/lang}</a></th> <th class="columnUsername{if $sortField == 'username'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=username&sortOrder={if $sortField == 'username' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}wcf.user.username{/lang}</a></th>
<th class="columnRoomID{if $sortField == 'roomID'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=roomID&sortOrder={if $sortField == 'roomID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.general.room{/lang}</a></th> <th class="columnRoomID{if $sortField == 'roomID'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=roomID&sortOrder={if $sortField == 'roomID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.global.room{/lang}</a></th>
<th class="columnSuspensionType{if $sortField == 'type'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=type&sortOrder={if $sortField == 'type' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.acp.suspension.type{/lang}</a></th> <th class="columnSuspensionType{if $sortField == 'type'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=type&sortOrder={if $sortField == 'type' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.acp.suspension.type{/lang}</a></th>
<th class="columnTime{if $sortField == 'time'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=time&sortOrder={if $sortField == 'time' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.general.time{/lang}</a></th> <th class="columnTime{if $sortField == 'time'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=time&sortOrder={if $sortField == 'time' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.global.time{/lang}</a></th>
<th class="columnExpires{if $sortField == 'expires'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=expires&sortOrder={if $sortField == 'expires' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.general.expires{/lang}</a></th> <th class="columnExpires{if $sortField == 'expires'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=expires&sortOrder={if $sortField == 'expires' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.global.expires{/lang}</a></th>
<th class="columnIssuer{if $sortField == 'issuer'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=issuer&sortOrder={if $sortField == 'issuer' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.acp.suspension.issuer{/lang}</a></th> <th class="columnIssuer{if $sortField == 'issuer'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=issuer&sortOrder={if $sortField == 'issuer' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.acp.suspension.issuer{/lang}</a></th>
<th class="columnMessage{if $sortField == 'reason'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=reason&sortOrder={if $sortField == 'reason' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.acp.suspension.reason{/lang}</a></th> <th class="columnMessage{if $sortField == 'reason'} active {@$sortOrder}{/if}"><a href="{link application='chat' controller='ChatSuspensionList'}pageNo={@$pageNo}&sortField=reason&sortOrder={if $sortField == 'reason' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$additionalParameters}{/link}">{lang}chat.acp.suspension.reason{/lang}</a></th>

View File

@ -27,7 +27,7 @@
<legend>{lang}wcf.global.filter{/lang}</legend> <legend>{lang}wcf.global.filter{/lang}</legend>
<dl> <dl>
<dt><label for="id">{lang}chat.general.room{/lang}</label></dt> <dt><label for="id">{lang}chat.global.room{/lang}</label></dt>
<dd> <dd>
<select id="id" name="id"> <select id="id" name="id">
{foreach from=$rooms item='roomBit'} {foreach from=$rooms item='roomBit'}
@ -38,7 +38,7 @@
</dl> </dl>
<dl{if $errorField == 'date'} class="formError"{/if}> <dl{if $errorField == 'date'} class="formError"{/if}>
<dt><label for="date">{lang}chat.general.time{/lang}</label></dt> <dt><label for="date">{lang}chat.global.time{/lang}</label></dt>
<dd> <dd>
<input id="date" type="date" name="date" min="{TIME_NOW-CHAT_LOG_ARCHIVETIME*60|date:'Y-m-d'}" max="{TIME_NOW|date:'Y-m-d'}" value="{$date|date:'Y-m-d'}" /> <input id="date" type="date" name="date" min="{TIME_NOW-CHAT_LOG_ARCHIVETIME*60|date:'Y-m-d'}" max="{TIME_NOW|date:'Y-m-d'}" value="{$date|date:'Y-m-d'}" />
{if $errorField == 'date'} {if $errorField == 'date'}

View File

@ -41,7 +41,7 @@ public function execute() {
'roomID' => $room->roomID, 'roomID' => $room->roomID,
'time' => TIME_NOW, 'time' => TIME_NOW,
'type' => \chat\data\message\Message::TYPE_INFORMATION, 'type' => \chat\data\message\Message::TYPE_INFORMATION,
'message' => \wcf\system\WCF::getLanguage()->get('chat.general.information.chatUpdate') 'message' => \wcf\system\WCF::getLanguage()->get('chat.global.information.chatUpdate')
) )
)); ));
$messageAction->executeAction(); $messageAction->executeAction();

View File

@ -6,7 +6,7 @@ everything that happens in the GUI of **Tims Chat**.
### Copyright Information ### Copyright Information
# @author Tim Düsterhus # @author Tim Düsterhus
# @copyright 2010-2013 Tim Düsterhus # @copyright 2010-2014 Tim Düsterhus
# @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode> # @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
# @package be.bastelstu.chat # @package be.bastelstu.chat
### ###
@ -25,7 +25,7 @@ enabling EMCAScript 5 strict mode and overwriting console to prepend the name of
window.console.warn "[be.bastelstu.Chat] #{message}" window.console.warn "[be.bastelstu.Chat] #{message}"
error: (message) -> error: (message) ->
window.console.error "[be.bastelstu.Chat] #{message}" window.console.error "[be.bastelstu.Chat] #{message}"
Continue with defining the needed variables. All variables are local to our closure and will be Continue with defining the needed variables. All variables are local to our closure and will be
exposed by a function if necessary. exposed by a function if necessary.
@ -45,6 +45,9 @@ exposed by a function if necessary.
lastMessage = null lastMessage = null
openChannel = 0 openChannel = 0
messageContainerSize = 0
userListSize = 0
remainingFailures = 3 remainingFailures = 3
events = events =
@ -73,14 +76,18 @@ exposed by a function if necessary.
Initialize **Tims Chat**. Bind needed DOM events and initialize data structures. Initialize **Tims Chat**. Bind needed DOM events and initialize data structures.
initialized = false initialized = false
init = (roomID, config, titleTemplate, messageTemplate, userTemplate) -> init = (roomID, config, titleTemplate, messageTemplate, userTemplate, userMenuTemplate) ->
return false if initialized return false if initialized
initialized = true initialized = true
messageContainerSize = $('.timsChatMessageContainer').height()
userListSize = $('#timsChatUserList').height()
v.config = config v.config = config
v.titleTemplate = titleTemplate v.titleTemplate = titleTemplate
v.messageTemplate = messageTemplate v.messageTemplate = messageTemplate
v.userTemplate = userTemplate v.userTemplate = userTemplate
v.userMenuTemplate = userMenuTemplate
console.log 'Initializing' console.log 'Initializing'
@ -110,14 +117,40 @@ Make the user leave the chat when **Tims Chat** is about to be unloaded.
async: false async: false
suppressErrors: true suppressErrors: true
undefined undefined
$(window).resize ->
# TODO
return if WCF.System.Mobile.UX._enabled
return unless $('html').hasClass 'fullscreen'
do ->
verticalContentPadding = $('#content').innerHeight() - $('#content').height()
verticalSizeOfContentElements = do ->
height = 0
$('#content > *:visible').each (k, v) -> height += $(v).outerHeight()
height
freeSpace = $('body').height() - verticalContentPadding - verticalSizeOfContentElements
$('.timsChatMessageContainer').height $('.timsChatMessageContainer').height() + freeSpace
do ->
verticalUserListContainerPadding = $('#timsChatUserListContainer').innerHeight() - $('#timsChatUserListContainer').height()
sidebarHeight = $('.sidebar > div').height()
freeSpace = $('body').height() - verticalUserListContainerPadding - sidebarHeight
$('#timsChatUserList').height $('#timsChatUserList').height() + freeSpace
Insert the appropriate smiley code into the input when a smiley is clicked. Insert the appropriate smiley code into the input when a smiley is clicked.
$('#smilies').on 'click', 'img', -> insertText " #{$(@).attr('alt')} " $('#smilies').on 'click', 'img', -> insertText " #{$(@).attr('alt')} "
Handle private channel menu Handle private channel menu
$('#privateChannelsMenu').on 'click', '.privateChannel', -> openPrivateChannel $(@).data 'privateChannelID' $('#timsChatMessageTabMenu > .tabMenu').on 'click', '.timsChatMessageTabMenuAnchor', ->
openPrivateChannel $(@).data 'userID'
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.
@ -217,9 +250,24 @@ Reset autocompleter to default status, when the input is `click`ed, as the posit
value: null value: null
caret: null caret: null
Bind user menu functions
$('#dropdownMenuContainer').on 'click', '.jsTimsChatUserMenuWhisper', ->
command = "/whisper #{userList.current[$(@).parents('ul').data 'userID'].username}, "
return if $('#timsChatInput').val().match(new RegExp WCF.String.escapeRegExp("^#{command}"), 'i')
insertText command, prepend: yes
$('#dropdownMenuContainer').on 'click', '.jsTimsChatUserMenuQuery', -> openPrivateChannel $(@).parents('ul').data 'userID'
$('#dropdownMenuContainer').on 'click', '.jsTimsChatUserMenuBan', ->
command = "/ban #{userList.current[$(@).parents('ul').data 'userID'].username}, "
return if $('#timsChatInput').val().match(new RegExp WCF.String.escapeRegExp("^#{command}"), 'i')
insertText command, prepend: yes
Refresh the room list when the associated button is `click`ed. Refresh the room list when the associated button is `click`ed.
$('#timsChatRoomList button').click -> do refreshRoomList $('#timsChatRoomListReloadButton').click -> do refreshRoomList
Clear the chat by removing every single message once the clear button is `clicked`. Clear the chat by removing every single message once the clear button is `clicked`.
@ -247,9 +295,9 @@ Mark smilies as disabled when they are disabled.
$('#timsChatSmilies').click (event) -> $('#timsChatSmilies').click (event) ->
if $(@).data 'status' if $(@).data 'status'
$('#smilies').removeClass 'disabled' $('#smilies').removeClass 'invisible'
else else
$('#smilies').addClass 'disabled' $('#smilies').addClass 'invisible'
Toggle fullscreen mode. Toggle fullscreen mode.
@ -259,7 +307,10 @@ Toggle fullscreen mode.
if $(@).data 'status' if $(@).data 'status'
$('html').addClass 'fullscreen' $('html').addClass 'fullscreen'
do $(window).resize
else else
$('.timsChatMessageContainer').height messageContainerSize
$('#timsChatUserList').height userListSize
$('html').removeClass 'fullscreen' $('html').removeClass 'fullscreen'
Toggle checkboxes. Toggle checkboxes.
@ -272,12 +323,14 @@ Toggle checkboxes.
Hide topic container. Hide topic container.
$('.jsTopicCloser').on 'click', -> $('#timsChatTopicCloser').on 'click', ->
if $('.timsChatMessageContainer.active').data('userID') is 0 $('#timsChatTopic').addClass 'invisible'
$('#timsChatTopic').addClass 'hidden' do $(window).resize
else
closePrivateChannel $('.timsChatMessageContainer.active').data('userID') Close private channels
$('#timsChatMessageTabMenu').on 'click', '.jsChannelCloser', -> closePrivateChannel $(@).parent().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) ->
@ -289,27 +342,20 @@ Visibly mark the message once the associated checkbox is checked.
Scroll down when autoscroll is being activated. Scroll down when autoscroll is being activated.
$('#timsChatAutoscroll').click (event) -> $('#timsChatAutoscroll').click (event) ->
if $('#timsChatAutoscroll').data 'status' if $(@).data 'status'
$('.timsChatMessageContainer.active').scrollTop $('.timsChatMessageContainer.active').prop 'scrollHeight' $('.timsChatMessageContainer.active').scrollTop $('.timsChatMessageContainer.active').prop 'scrollHeight'
scrollUpNotifications = off
$("#timsChatMessageTabMenu > .tabMenu > ul > li.ui-state-active").removeClass 'notify'
$(".timsChatMessageContainer.active").removeClass 'notify'
else
scrollUpNotifications = on
Bind scroll event on predefined message containers
$('.timsChatMessageContainer.active').on 'scroll', (event) -> $('.timsChatMessageContainer.active').on 'scroll', (event) ->
event.stopPropagation(); do event.stopPropagation
handleScroll event
element = $ @
scrollTop = element.scrollTop()
scrollHeight = element.prop 'scrollHeight'
height = element.height()
if scrollTop < scrollHeight - height - 25
if $('#timsChatAutoscroll').data('status') is 1
scrollUpNotifications = on
do $('#timsChatAutoscroll').click
if scrollTop > scrollHeight - height - 10
if $('#timsChatAutoscroll').data('status') is 0
scrollUpNotifications = off
$(@).removeClass 'notification'
do $('#timsChatAutoscroll').click
Enable duplicate tab detection. Enable duplicate tab detection.
@ -387,35 +433,85 @@ Free the fish.
freeTheFish = -> freeTheFish = ->
return if $.wcfIsset 'fish' return if $.wcfIsset 'fish'
console.warn 'Freeing the fish' console.warn 'Freeing the fish'
fish = $ """<div id="fish">#{WCF.String.escapeHTML('><((((\u00B0>')}</div>""" fish = $ """<div id="fish"><span></span></div>"""
fish.direction = 'right'
fish.css fish.css
position: 'fixed' position: 'fixed'
top: '50%' top: '50%'
left: '50%' left: '50%'
color: 'black' zIndex: 0x7FFFFFFF
textShadow: '1px 1px white' textShadow: '1px 1px rgb(0, 0, 0)'
zIndex: 9999
fish.appendTo $ 'body' fish.appendTo $ 'body'
pe.fish = new WCF.PeriodicalExecuter ->
left = Math.random() * 100 - 50 fish.colors = ['78C5D6', '459ba8', '79C267', 'C5D647', 'F5D63D', 'F28C33', 'E868A2', 'BF62A6']
top = Math.random() * 100 - 50 fish.colorIndex = 0
fish = $ '#fish'
fish.texts =
right: '><((((\u00B0>'
left: '<\u00B0))))><'
fish.fishes = {}
Pre build fishes, this allows for faster animation
$.each fish.texts, (key, value) ->
fish.fishes[key] = []
index = 0
left *= -1 unless fish.width() < (fish.position().left + left) < ($(window).width() - fish.width()) while index < value.length
top *= -1 unless fish.height() < (fish.position().top + top) < ($(window).height() - fish.height()) html = $ '<span/>'
i = 0
if left > 0 $(value.split '').each (key, value) ->
fish.text '><((((\u00B0>' if left > 0 $("<span>#{value}</span>").css
else if left < 0 color: '#' + fish.colors[(i++ + index) % fish.colors.length]
fish.text '<\u00B0))))><' textShadow: '1px 1px rgb(0, 0, 0)'
.appendTo html
fish.fishes[key][index++] = html
return
fish.find('> span').replaceWith fish.fishes[fish.direction][0]
fish.updateRainbowText = (key, value) ->
key = key || fish.direction
return unless fish.fishes[key]? || not fish.texts[key]?
value = value || fish.colorIndex++ % fish.texts[key].length
fish.find('> span').replaceWith fish.fishes[key][value]
fish.pePos = new WCF.PeriodicalExecuter ->
loops = 0
loop
++loops
left = Math.random() * 300 - 150
top = Math.random() * 300 - 150
if (fish.position().top + top) > 0 and (fish.position().left + left + fish.width()) < $(window).width() and (fish.position().top + top + fish.height()) < $(window).height() and (fish.position().left + left) > 0
break
else if loops is 10
console.log 'Magicarp used Splash for the 10th time in a row - it fainted!'
fish.css
'top': '50%'
'left': '50%'
break
if left > 0 and fish.text() isnt '><((((\u00B0>'
fish.direction = 'right'
fish.updateRainbowText null, fish.colorIndex % fish.texts.right.length
else if left < 0 and fish.text() isnt '<\u00B0))))><'
fish.direction = 'left'
fish.updateRainbowText null, fish.colorIndex % fish.texts.left.length
fish.animate fish.animate
top: (fish.position().top + top) top: (fish.position().top + top)
left: (fish.position().left + left) left: (fish.position().left + left)
, 1e3 , 1e3
, 1.5e3 , 1.2e3
fish.peColor = new WCF.PeriodicalExecuter ->
do fish.updateRainbowText
, .125e3
Fetch new messages from the server and pass them to `handleMessages`. The userlist will be passed to `handleUsers`. Fetch new messages from the server and pass them to `handleMessages`. The userlist will be passed to `handleUsers`.
`remainingFailures` will be decreased on failure and message loading will be entirely disabled once it reaches zero. `remainingFailures` will be decreased on failure and message loading will be entirely disabled once it reaches zero.
@ -449,15 +545,13 @@ Prevent loading messages in parallel.
Insert the given messages into the chat stream. Insert the given messages into the chat stream.
handleMessages = (messages) -> handleMessages = (messages) ->
$('.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}")) message.isInPrivateChannel = (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
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 .timsChatText').is('ul') and lastMessage isnt null and lastMessage.type in [ v.config.messageTypes.NORMAL, v.config.messageTypes.WHISPER ]
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
createNewMessage = no createNewMessage = no
@ -493,11 +587,34 @@ Insert the given messages into the chat stream.
else else
messageContainerID = 0 messageContainerID = 0
$("#timsChatMessageContainer#{messageContainerID} .timsChatMessage:last-child .text").append $(output).find('.text li:last-child') $("#timsChatMessageContainer#{messageContainerID} .timsChatMessage:last-child .timsChatText").append $(output).find('.timsChatText li:last-child')
lastMessage = message lastMessage = message
$('.timsChatMessageContainer.active').scrollTop $('.timsChatMessageContainer.active').prop('scrollHeight') if $('#timsChatAutoscroll').data('status') is 1 $('.timsChatMessageContainer.active').scrollTop $('.timsChatMessageContainer.active').prop('scrollHeight') if $('#timsChatAutoscroll').data('status') is 1
Handles scroll event of message containers
handleScroll = (event) ->
element = $ event.target
if element.hasClass 'active'
scrollTop = element.scrollTop()
scrollHeight = element.prop 'scrollHeight'
height = element.innerHeight()
if scrollTop < scrollHeight - height - 25
if $('#timsChatAutoscroll').data('status') is 1
scrollUpNotifications = on
do $('#timsChatAutoscroll').click
if scrollTop > scrollHeight - height - 10
if $('#timsChatAutoscroll').data('status') is 0
scrollUpNotifications = off
$("#timsChatMessageTabMenu > .tabMenu > ul > li.ui-state-active").removeClass 'notify'
$(".timsChatMessageContainer.active").removeClass 'notify'
do $('#timsChatAutoscroll').click
Rebuild the userlist based on the given `users`. Rebuild the userlist based on the given `users`.
handleUsers = (users) -> handleUsers = (users) ->
@ -548,14 +665,7 @@ Build HTML of the user and insert it into the list, if the users was not found i
li.append v.userTemplate.fetch user li.append v.userTemplate.fetch user
menu = $ '<ul></ul>' menu = $(v.userMenuTemplate.fetch user)
unless user.userID is WCF.User.userID
menu.append $("<li><a>#{WCF.Language.get('chat.general.query')}</a></li>").click -> openPrivateChannel user.userID
menu.append $ "<li><a>#{WCF.Language.get('chat.general.kick')}</a></li>"
menu.append $ "<li><a>#{WCF.Language.get('chat.general.ban')}</a></li>"
menu.append $ """<li><a href="#{user.link}">#{WCF.Language.get('chat.general.profile')}</a></li>"""
events.userMenu.fire user, menu
if menu.find('li').length if menu.find('li').length
li.append menu li.append menu
@ -563,7 +673,6 @@ Build HTML of the user and insert it into the list, if the users was not found i
li.addClass 'dropdown' li.addClass 'dropdown'
li.appendTo $ '#timsChatUserList > ul' li.appendTo $ '#timsChatUserList > ul'
foundUsers[id] = true foundUsers[id] = true
Remove all users that left the chat. Remove all users that left the chat.
@ -581,12 +690,17 @@ Insert the given `text` into the input. If `options.append` is true the given `t
the existing text. If `options.submit` is true the message will be sent to the server afterwards. the existing text. If `options.submit` is true the message will be sent to the server afterwards.
insertText = (text, options = { }) -> insertText = (text, options = { }) ->
options.append = false if options.prepend? and options.prepend and not options.append?
options = $.extend options = $.extend
prepend: false
append: true append: true
submit: false submit: false
, options , options
text = text + $('#timsChatInput').val() if options.prepend
text = $('#timsChatInput').val() + text if options.append text = $('#timsChatInput').val() + text if options.append
$('#timsChatInput').val text $('#timsChatInput').val text
do $('#timsChatInput').keyup do $('#timsChatInput').keyup
@ -598,26 +712,28 @@ the existing text. If `options.submit` is true the message will be sent to the s
Send out notifications for the given `message`. The number of unread messages will be prepended to `document.title` and if available desktop notifications will be sent. Send out notifications for the given `message`. The number of unread messages will be prepended to `document.title` and if available desktop notifications will be sent.
notify = (message) -> notify = (message) ->
if scrollUpNotifications return if message.sender is WCF.User.userID
$('.timsChatMessageContainer.active').addClass 'notification'
if message.isInPrivateChannel if scrollUpNotifications
if message.sender is WCF.User.userID $("#timsChatMessageTabMenu > .tabMenu > ul > li.ui-state-active").addClass 'notify'
privateChannelID = message.receiver $(".timsChatMessageContainer.active").addClass 'notify'
else
privateChannelID = message.sender
if $('.timsChatMessageContainer.active').data('userID') isnt privateChannelID if message.isInPrivateChannel
$("#privateChannel#{privateChannelID}").addClass 'notify' id = if message.sender is WCF.User.userID then message.receiver else message.sender
if $('.timsChatMessageContainer.active').data('userID') isnt id
$("#timsChatMessageTabMenuAnchor#{id}").parent().addClass 'notify'
$("#timsChatMessageContainer#{id}").addClass 'notify'
else if $('.timsChatMessageContainer.active').data('userID') isnt 0 else if $('.timsChatMessageContainer.active').data('userID') isnt 0
$("#privateChannel0").addClass 'notify' $("#timsChatMessageTabMenuAnchor0").parent().addClass 'notify'
$("#timsChatMessageContainer0").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 $.extend {}, currentRoom, document.title = v.titleTemplate.fetch $.extend {}, currentRoom,
newMessageCount: ++newMessageCount newMessageCount: ++newMessageCount
title = WCF.Language.get 'chat.general.notify.title' title = WCF.Language.get 'chat.global.notify.title'
content = "#{message.username}#{message.separator} #{message.message}" content = "#{message.username}#{message.separator} #{message.message}"
if window.Notification?.permission is 'granted' if window.Notification?.permission is 'granted'
@ -648,8 +764,9 @@ Fetch the roomlist from the server and update it in the GUI.
for room in data.returnValues for room in data.returnValues
li = $ '<li></li>' li = $ '<li></li>'
li.addClass('timsChatRoom').data('roomID', room.roomID)
li.addClass 'active' if room.active li.addClass 'active' if room.active
$("""<a href="#{room.link}">#{WCF.String.escapeHTML(room.title)} <span class="badge">#{WCF.String.formatNumeric room.userCount}</span></a>""").addClass('timsChatRoom').data('roomID', room.roomID).appendTo li $("""<a href="#{room.link}">#{WCF.String.escapeHTML(room.title)}</a> <span class="badge">#{WCF.String.formatNumeric room.userCount}</span>""").appendTo li
$('#timsChatRoomList ul').append li $('#timsChatRoomList ul').append li
if window.history?.replaceState? if window.history?.replaceState?
@ -705,7 +822,7 @@ Joins a room.
success: (data) -> success: (data) ->
loading = false loading = false
$('#timsChatTopic').removeClass 'hidden' $('#timsChatTopic').removeClass 'invisible'
currentRoom = data.returnValues currentRoom = data.returnValues
currentRoom.roomID = roomID currentRoom.roomID = roomID
@ -737,66 +854,74 @@ Open private channel
div = $ '<div>' div = $ '<div>'
div.attr 'id', "timsChatMessageContainer#{userID}" div.attr 'id', "timsChatMessageContainer#{userID}"
div.data 'userID', userID div.data 'userID', userID
div.addClass 'tabMenuContent'
div.addClass 'timsChatMessageContainer' div.addClass 'timsChatMessageContainer'
div.addClass 'marginTop'
div.addClass 'container' div.addClass 'container'
div.wrapInner '<ul>' div.addClass 'containerPadding'
div.wrapInner "<ul></ul>"
div.on 'scroll', (event) ->
do event.stopPropagation
handleScroll event
$('#timsChatMessageContainer0').after div $('#timsChatMessageContainer0').after div
$('.timsChatMessageContainer').height $('.timsChatMessageContainer').height()
$('.privateChannel').removeClass 'active'
if userID isnt 0 if userID isnt 0
$('#timsChatTopic').removeClass 'hidden empty' $('#timsChatTopic').removeClass 'empty'
$('#timsChatTopic > .topic').html WCF.Language.get 'chat.general.privateChannelTopic', {username: userList.allTime[userID].username} $('#timsChatTopic > .topic').html WCF.Language.get 'chat.global.privateChannelTopic', {username: userList.allTime[userID].username}
$('#timsChatTopic > .jsTopicCloser').attr 'title', WCF.Language.get 'chat.general.closePrivateChannel' $('#timsChatMessageTabMenu').removeClass 'singleTab'
unless $.wcfIsset "privateChannel#{userID}" unless $.wcfIsset "timsChatMessageTabMenuAnchor#{userID}"
li = $ '<li>' li = $ '<li>'
li.attr 'id', "privateChannel#{userID}"
li.data 'privateChannelID', userID
li.addClass 'privateChannel'
span = $ '<span class="userAvatar framed" />' anchor = $ """<a id="timsChatMessageTabMenuAnchor#{userID}" class="timsChatMessageTabMenuAnchor" href="#{window.location.toString().replace /#.+$/, ''}#timsChatMessageContainer#{userID}" />"""
anchor.data 'userID', userID
avatar = $ userList.allTime[userID].avatar[16] avatar = $ userList.allTime[userID].avatar[16]
avatar.addClass 'jsTooltip' avatar = $('<span class="userAvatar framed" />').wrapInner avatar
avatar.attr 'title', userList.allTime[userID].username avatar.append "<span>#{userList.allTime[userID].username}</span>"
avatar.wrap span
li.append avatar.parent().addClass 'small'
avatar = $ userList.allTime[userID].avatar[32] anchor.wrapInner avatar
avatar.addClass 'jsTooltip' anchor.prepend '<span class="icon icon16 icon-warning-sign notifyIcon"></span>'
avatar.attr 'title', userList.allTime[userID].username anchor.append """<span class="jsChannelCloser icon icon16 icon-remove jsTooltip" title="#{WCF.Language.get('chat.global.closePrivateChannel')}" />"""
avatar.wrap span
li.append avatar.parent().addClass 'large'
$('#privateChannelsMenu ul').append li li.append anchor
$('#privateChannelsMenu').addClass 'shown' $('#timsChatMessageTabMenu > .tabMenu > ul').append li
$('#timsChatMessageTabMenu').wcfTabs 'refresh'
WCF.System.FlexibleMenu.rebuild $('#timsChatMessageTabMenu > .tabMenu').attr 'id'
else else
$('#timsChatTopic > .topic').text currentRoom.topic $('#timsChatTopic > .topic').text currentRoom.topic
$('#timsChatTopic > .jsTopicCloser').attr 'title', WCF.Language.get 'chat.general.closeTopic'
if currentRoom.topic.trim() is '' if currentRoom.topic.trim() is ''
$('#timsChatTopic').addClass 'empty' $('#timsChatTopic').addClass 'empty'
else else
$('#timsChatTopic').removeClass 'empty' $('#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' $("#timsChatMessageTabMenuAnchor#{userID}").parent().removeClass 'notify'
$("#timsChatMessageContainer#{userID}").removeClass 'notify'
if $('#timsChatAutoscroll').data('status')
do $('#timsChatAutoscroll').click
scrollUpNotifications = on
$('#timsChatMessageTabMenu').wcfTabs 'select', $("#timsChatMessageTabMenuAnchor#{userID}").parent().index()
do WCF.DOMNodeInsertedHandler.execute
do $(window).resize
openChannel = userID openChannel = userID
Close private channel Close private channel
closePrivateChannel = (userID) -> closePrivateChannel = (userID) ->
unless userID is 0 unless userID is 0
do $("#privateChannel#{userID}").remove do $("#timsChatMessageTabMenuAnchor#{userID}").parent().remove
do $("#timsChatMessageContainer#{userID}").remove do $("#timsChatMessageContainer#{userID}").remove
$('#timsChatMessageTabMenu').wcfTabs 'refresh'
WCF.System.FlexibleMenu.rebuild $('#timsChatMessageTabMenu > .tabMenu').wcfIdentify()
if $('#privateChannelsMenu li').length <= 1 if $('#timsChatMessageTabMenu > .tabMenu > ul > li').length <= 1
$('#privateChannelsMenu').removeClass 'shown' $('#timsChatMessageTabMenu').addClass 'singleTab'
openPrivateChannel 0 openPrivateChannel 0
@ -968,7 +1093,7 @@ Create a message containing the uploaded attachment
unless parseInt(data.returnValues.attachments[internalFileID].isImage) is 0 unless parseInt(data.returnValues.attachments[internalFileID].isImage) is 0
link.addClass('jsImageViewer') link.addClass('jsImageViewer')
if !data.returnValues.attachments[internalFileID].tinyURL unless data.returnValues.attachments[internalFileID].tinyURL
li.find('.box32 > div.attachmentImageContainer > .icon-paper-clip').replaceWith $("""<img src="#{data.returnValues.attachments[internalFileID].url}'" alt="" class="attachmentTinyThumbnail" style="width: 32px; height: 32px;" />""") li.find('.box32 > div.attachmentImageContainer > .icon-paper-clip').replaceWith $("""<img src="#{data.returnValues.attachments[internalFileID].url}'" alt="" class="attachmentTinyThumbnail" style="width: 32px; height: 32px;" />""")
li.find('.attachmentTinyThumbnail').wrap link li.find('.attachmentTinyThumbnail').wrap link

View File

@ -121,7 +121,7 @@ public function getFormattedMessage($type = 'text/html') {
*/ */
public function getUsername($colored = false) { public function getUsername($colored = false) {
$username = $this->username; $username = $this->username;
if ($this->type == self::TYPE_INFORMATION) return WCF::getLanguage()->get('chat.general.information'); if ($this->type == self::TYPE_INFORMATION) return WCF::getLanguage()->get('chat.global.information');
if ($colored) { if ($colored) {
$username = \chat\util\ChatUtil::gradient($username, $this->color1, $this->color2); $username = \chat\util\ChatUtil::gradient($username, $this->color1, $this->color2);

View File

@ -39,7 +39,7 @@ public function __construct(\chat\system\command\CommandHandler $commandHandler)
// Room // Room
$room = \chat\data\room\RoomCache::getInstance()->getRoom($this->user->chatRoomID); $room = \chat\data\room\RoomCache::getInstance()->getRoom($this->user->chatRoomID);
if ($room !== null && $room->canEnter()) { if ($room !== null && $room->canEnter()) {
$this->lines[WCF::getLanguage()->get('chat.general.room')] = $room->getTitle(); $this->lines[WCF::getLanguage()->get('chat.global.room')] = $room->getTitle();
} }
// Suspensions // Suspensions
@ -50,7 +50,7 @@ public function __construct(\chat\system\command\CommandHandler $commandHandler)
if (!$typeSuspension->isVisible()) continue; if (!$typeSuspension->isVisible()) continue;
$dateTime = DateUtil::getDateTimeByTimestamp($typeSuspension->expires); $dateTime = DateUtil::getDateTimeByTimestamp($typeSuspension->expires);
$name = WCF::getLanguage()->getDynamicVariable('chat.general.information.suspension', array( $name = WCF::getLanguage()->getDynamicVariable('chat.global.information.suspension', array(
'suspension' => $typeSuspension, 'suspension' => $typeSuspension,
'room' => \chat\data\room\RoomCache::getInstance()->getRoom($typeSuspension->roomID) 'room' => \chat\data\room\RoomCache::getInstance()->getRoom($typeSuspension->roomID)
)); ));

View File

@ -1,11 +1,42 @@
/** /**
* Styles for Tims Chat * Styles for Tims Chat
* *
* @author Tim Düsterhus, Maximilian Mader * @author Tim Düsterhus, Maximilian Mader
* @copyright 2010-2013 Tim Düsterhus * @copyright 2010-2014 Tim Düsterhus
* @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode> * @license Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>
* @package be.bastelstu.chat * @package be.bastelstu.chat
*/ */
@-webkit-keyframes timsChatNotify {
from {
border-color: @wcfContainerBorderColor;
}
to {
border-color: @wcfInputHoverBorderColor;
}
}
@-moz-keyframes timsChatNotify {
from {
border-color: @wcfContainerBorderColor;
}
to {
border-color: @wcfInputHoverBorderColor;
}
}
@-o-keyframes timsChatNotify {
from {
border-color: @wcfContainerBorderColor;
}
to {
border-color: @wcfInputHoverBorderColor;
}
}
@keyframes timsChatNotify { @keyframes timsChatNotify {
from { from {
border-color: @wcfContainerBorderColor; border-color: @wcfContainerBorderColor;
@ -16,365 +47,398 @@
} }
} }
.__bubbleArrow { // only apply styles to Tims Chat
border-color: transparent @wcfContainerBorderColor;
left: -6px;
top: 5px;
border-width: 6px 6px 6px 0;
border-style: solid;
content: "";
display: block;
position: absolute;
width: 0;
}
#tplChat { #tplChat {
#timsChatTopic { #content {
padding: @wcfGapTiny; // styles related to the topic container
.transition(height, .2s); #timsChatTopic {
.transition(padding-top, .2s); position: relative;
.transition(padding-bottom, .2s);
&.empty, &.hidden {
height: 0px;
overflow: hidden;
border: 0px;
padding: 0px;
margin: 0px;
}
.jsTopicCloser {
cursor: pointer;
float: right;
}
}
#privateChannelsMenu {
.transition(opacity, .2s);
.marginTop;
z-index: -1;
position: absolute;
opacity: 0;
&.shown {
opacity: 1;
z-index: 130;
~ .timsChatMessageContainer { #timsChatTopicCloser {
margin-left: 35px; position: absolute;
border-top-left-radius: 0; top: @wcfGapSmall;
right: @wcfGapSmall;
cursor: pointer;
&:hover {
color: @wcfLinkColor;
}
} }
} }
> ul { #timsChatMessageTabMenu {
text-align: right; &.singleTab {
> nav.tabMenu {
> li:first-child { // hide tab menu when single tabbed
> .userAvatar.framed { // this is “a bit” hacky
img, > canvas, > .icon { display: none !important;
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 { // overwrite WCF margin overwrite on tab menu content with WCF marginTop like margin
&.large { // this is “a bit” hacky
display: none; margin-top: @wcfGapMedium !important;
}
> .tabMenuContent {
&.small {
display: block;
}
} }
&.active { .timsChatMessageContainer {
> .userAvatar { &.notify {
&.large { -webkit-animation-duration: .2s;
display: block; -webkit-animation-name: timsChatNotify;
} -webkit-animation-iteration-count: 5;
-webkit-animation-direction: alternate;
-webkit-animation-timing-function: linear;
&.small { -moz-animation-duration: .2s;
display: none; -moz-animation-name: timsChatNotify;
} -moz-animation-iteration-count: 5;
-moz-animation-direction: alternate;
-moz-animation-timing-function: linear;
&.framed { -o-animation-duration: .2s;
> img, > canvas, > .icon { -o-animation-name: timsChatNotify;
border-right-color: @wcfContentBackgroundColor; -o-animation-iteration-count: 5;
-o-animation-direction: alternate;
border-radius: @wcfContainerBorderRadius 0 0 @wcfContainerBorderRadius; -o-animation-timing-function: linear;
animation-duration: .2s;
animation-name: timsChatNotify;
animation-iteration-count: 5;
animation-direction: alternate;
animation-timing-function: linear;
border-color: @wcfInputHoverBorderColor;
}
}
}
> nav.tabMenu {
> ul {
> li {
> a {
.notifyIcon {
display: none;
} }
}
}
}
&.notify {
> .userAvatar {
> * {
// TODO
opacity: .4;
}
}
}
}
}
}
.timsChatMessageContainer {
height: 320px;
overflow-y: scroll;
overflow-x: hidden;
display: none;
&.active {
display: block;
}
&.markEnabled {
ul {
.timsChatMessage {
&.jsMarked {
background-color: @wcfSelectedBackgroundColor;
color: @wcfSelectedColor;
}
> .innerMessageContainer {
.markContainer {
display: block;
}
}
}
}
}
ul {
.timsChatMessage {
min-height: 20px;
clear: both;
.transition(opacity, .2s);
&.unloaded {
opacity: .5;
}
&:nth-child(even) {
> .innerMessageContainer.bubble .innerMessage {
background-color: @wcfContainerAccentBackgroundColor;
&:after {
border-color: transparent @wcfContainerAccentBackgroundColor !important;
}
}
}
.messageIcon {
float: left;
padding: 8px 0 0 4px;
margin-right: -16px;
}
> .innerMessageContainer {
padding: 5px 20px 5px 5px;
position: relative;
> div.avatarContainer {
position: relative;
float: left;
margin-left: 16px;
> .avatarExtra {
box-shadow: 0 0 3px 0 rgba(0, 0, 0, 0.3);
position: absolute;
left: 24px;
bottom: -2px;
width: 16px;
height: 16px;
}
}
.innerMessage {
margin-left: 46px;
padding: 2px 5px 5px;
time {
float: right;
}
.username {
font-weight: bold;
}
> .text {
img {
max-width: 100%;
height: auto;
width: auto;
}
}
}
&.bubble {
> div.avatarContainer {
margin-left: 0;
}
.innerMessage {
border-width: 1px;
border-style: solid;
border-color: @wcfContainerBorderColor;
border-radius: @wcfContainerBorderRadius;
background-color: @wcfContainerBackgroundColor;
position: relative;
> ul.text { > .icon, img {
li { // fix vertical alignment of images in tabs
.clearfix; vertical-align: middle;
border-style: solid; margin-right: @wcfGapTiny;
border-width: 0 0 1px 0; }
border-color: @wcfContainerBorderColor;
padding: 3px 0 4px; // styles related to the close button of private channels in tabs
.jsChannelCloser {
&:last-child { &:hover {
border-style: none; color: @wcfLinkColor;
padding: 3px 0 0 0; }
} }
}
&.notify {
.notifyIcon {
display: inline;
}
}
}
}
}
}
.timsChatMessageContainer {
height: 300px;
overflow-y: scroll;
overflow-x: hidden;
.timsChatMarkContainer {
display: none;
}
> ul {
> .timsChatMessage {
clear: both;
&.unloaded {
opacity: 0.5;
}
> .timsChatMessageIcon {
float: left;
margin-right: -16px;
}
> .timsChatInnerMessageContainer {
position: relative;
> .timsChatAvatarContainer {
position: relative;
float: left;
margin-left: 16px;
> .timsChatAvatarExtraIcon {
position: absolute;
bottom: -8px;
right: -8px;
}
}
.timsChatInnerMessage {
margin-left: 32 + @wcfGapMedium; // size of avatars + a small gap
padding-right: @wcfGapSmall;
.timsChatUsernameContainer {
// sender username
> span:first-child {
font-weight: bold;
} }
} }
&:before { time {
.__bubbleArrow; float: right;
}
&:after {
.__bubbleArrow;
border-color: transparent @wcfContainerBackgroundColor;
left: -5px;
top: 6px;
border-width: 5px 5px 5px 0;
} }
} }
&.right { &.bubble {
.avatarContainer { > .timsChatAvatarContainer {
float: right; margin-left: 0px;
} }
.innerMessage { .timsChatInnerMessage {
margin-right: 46px; position: relative;
margin-left: 0px;
&:before { padding: @wcfGapSmall;
.__bubbleArrow; border-radius: @wcfContainerBorderRadius;
left: auto; border-style: solid;
right: -6px; border-width: 1px;
border-width: 6px 0 6px 6px; border-color: @wcfContainerBorderColor;
> .timsChatText {
li {
border-style: solid;
border-width: 0 0 1px 0;
border-color: @wcfContainerBorderColor;
padding: (@wcfGapTiny - 1) 0 @wcfGapTiny;
&:last-child {
border-style: none;
padding: (@wcfGapTiny - 1) 0 0 0;
}
}
}
// :before and :after are used to create the little arrows on the “speech bubble containers”
&:before, &:after {
content: "";
display: block;
position: absolute;
width: 0;
border-style: solid;
}
&:before{
border-color: transparent @wcfContainerBorderColor;
left: -@wcfGapSmall;
top: @wcfGapSmall;
border-width: @wcfGapSmall @wcfGapSmall @wcfGapSmall 0;
} }
&:after { &:after {
.__bubbleArrow;
border-color: transparent @wcfContainerBackgroundColor; border-color: transparent @wcfContainerBackgroundColor;
left: auto; left: -@wcfGapSmall + 1;
right: -5px; top: @wcfGapSmall + 1;
top: 6px; border-width: (@wcfGapSmall - 1) (@wcfGapSmall - 1) (@wcfGapSmall - 1) 0;
border-width: 5px 0 5px 5px; }
}
&.right {
> .timsChatAvatarContainer {
float: right;
}
.timsChatInnerMessage {
margin-right: 32 + @wcfGapMedium;
margin-left: 0;
&:before{
border-color: transparent @wcfContainerBorderColor;
left: auto;
right: -@wcfGapSmall;
top: @wcfGapSmall;
border-width: @wcfGapSmall 0 @wcfGapSmall @wcfGapSmall;
}
&:after {
border-color: transparent @wcfContainerBackgroundColor;
left: auto;
right: -@wcfGapSmall + 1;
top: @wcfGapSmall + 1;
border-width: (@wcfGapSmall - 1) 0 (@wcfGapSmall - 1) (@wcfGapSmall - 1);
}
} }
} }
} }
} }
> .markContainer { &:nth-child(even) {
display: none; > .timsChatInnerMessageContainer {
position: absolute; &.bubble {
right: 0px; .timsChatInnerMessage {
top: 6px; background-color: @wcfContainerAccentBackgroundColor;
&:after {
border-color: transparent @wcfContainerAccentBackgroundColor;
}
}
}
}
}
> .timsChatInnerMessageContainer {
margin-bottom: @wcfGapSmall;
} }
} }
} }
&.markEnabled {
> ul {
> .timsChatMessage {
&.jsMarked {
> .timsChatInnerMessageContainer {
.timsChatInnerMessage {
background-color: @wcfSelectedBackgroundColor;
color: @wcfSelectedColor;
}
&.bubble {
.timsChatInnerMessage {
&:after {
border-color: transparent @wcfSelectedBackgroundColor;
}
}
&.right {
.timsChatInnerMessage {
&:after {
border-color: transparent @wcfSelectedBackgroundColor;
}
}
}
}
}
}
> .timsChatInnerMessageContainer {
.timsChatMarkContainer {
display: inline-block;
position: absolute;
right: -@wcfGapLarge;
top: 0;
}
}
}
}
}
}
#smilies {
.marginTop();
// don't display the smiley box on low resolution devices as a button will be shown instead
@media only screen and (max-width: 800px) {
display: none;
}
&, &.invisible {
-webkit-transition: opacity .2s ease-in-out;
-moz-transition: opacity .2s ease-in-out;
-ms-transition: opacity .2s ease-in-out;
-o-transition: opacity .2s ease-in-out;
transition: opacity .2s ease-in-out;
}
&.invisible {
opacity: .5;
}
}
#timsChatOptions {
float: right;
// styles related to the smiley button that replaces the smiley box on low resolution devices
#timsChatSmileyPopupButton {
display: none;
@media only screen and (max-width: 800px) {
display: inline-block;
}
}
// fix option buttons on low resolution devices, it will become a dropup not a dropdown
> nav.buttonGroupNavigation {
position: relative;
display: inline-block;
vertical-align: middle;
@media only screen and (max-width: 800px) {
margin-right: @wcfGapSmall;
> ul {
right: 1px;
top: auto;
bottom: 24px;
}
}
}
// clear the float on the first element after the option container, maybe someone alters their templates and puts an element down there ;)
+ * {
clear: right;
}
} }
} }
.sidebar { .sidebar {
padding-top: 0px !important;
> div { > div {
height: 400px; > fieldset{
overflow: auto !important; padding-right: @wcfGapTiny;
> .chatTabMenuContainer {
padding: 14px 0 21px;
> .chatSidebarMenu { > div {
background: @wcfContentBackgroundColor; overflow-y: auto;
margin: -14px 0 0;
border-radius: 0px; > ul {
padding-right: @wcfGapSmall;
}
}
&#timsChatUserListContainer {
> div {
height: 250px;
}
}
&#timsChatRoomListContainer {
> div#timsChatRoomList {
height: 150px;
}
} }
} }
} }
#sidebarContent { #timsChatUserList {
fieldset { > ul {
padding-top: 0px;
padding-bottom: 0px;
}
nav {
ul {
> li {
> a {
padding: @wcfGapTiny @wcfGapMedium @wcfGapTiny @wcfGapLarge;
height: 24px; // height of avatar image
}
> a:before {
display: inline-block;
content: "";
height: 100%;
vertical-align: middle;
}
> &.active {
margin-top: @wcfGapSmall;
}
}
}
}
ul:not(.dropdownMenu) {
> li { > li {
margin-top: @wcfGapSmall; &.you {
} a {
} &:hover {
text-decoration: none;
#timsChatUserList { cursor: default;
.timsChatUser { }
> a {
background: @wcfContentBackgroundColor;
img {
margin-right: @wcfGapSmall;
} }
} }
&.away { a {
opacity: .5; img {
} margin-right: @wcfGapTiny;
}
&.suspended a {
text-decoration: line-through;
} }
} }
} }
@ -391,116 +455,53 @@
} }
} }
#timsChatRoomList { #timsChatCopyrightDialog {
> div { > div {
> div { background-repeat: no-repeat;
text-align: center; background-position: right top;
}
} }
} }
#smilies { #fish {
margin-top: @wcfGapMedium; font-size: 2rem;
li {
.transition(opacity, .2s);
}
&.disabled {
li {
opacity: .5;
}
}
}
#timsChatOptions {
> ul {
text-align: right;
}
}
#timsChatCopyrightDialog > div {
background-position: right center;
background-repeat: no-repeat;
min-height: 150px;
}
.notification {
animation-duration: .2s;
animation-name: timsChatNotify;
animation-iteration-count: 5;
animation-direction: alternate;
animation-timing-function: linear;
border-color: @wcfInputHoverBorderColor;
}
@media only screen and (max-width: 800px) {
.timsChatMessage .text li > time, #smilies {
display: none !important;
}
} }
} }
// TODO
html.fullscreen { html.fullscreen {
#top { html, body {
height: 0px; padding: 0;
margin: 0;
} }
height: 100%; &,
overflow: hidden; body,
#tplChat #main,
#content { #tplChat #main > div,
#tplChat #main > div > div,
#tplChat #content {
width: 100%;
height: 100%; height: 100%;
max-width: 100%;
-moz-box-sizing: border-box; max-height: 100%;
-webkit-box-sizing: border-box;
box-sizing: border-box;
display: -moz-box;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-moz-box-orient: vertical;
-webkit-box-direction: normal;
-moz-box-direction: normal;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
.timsChatMessageContainer {
-webkit-box-flex: 1;
-moz-box-flex: 1;
-webkit-flex: 1 0 auto;
-ms-flex: 1 0 auto;
flex: 1 0 auto;
}
} }
#timsChatOptions { #top,
margin-bottom: @wcfGapMedium; #pageHeader,
#pageFooter,
#mainMenu,
#topMenu {
display: none;
} }
#tplChat { .sidebar, #main, #content {
height: 100%; padding-bottom: 0;
overflow: hidden; }
#pageHeader, #pageFooter { #main, #content {
display: none; padding-top: 0;
} border-top: none;
border-bottom: none;
#main { border-radius: 0;
height: 100%;
margin: 0;
padding: 0;
max-width: 100%;
width: 100%;
> div, .sidebar, #sidebarContainer {
height: 100%;
}
}
} }
} }

View File

@ -7,7 +7,6 @@
<item name="chat.acp.room.title"><![CDATA[Titel]]></item> <item name="chat.acp.room.title"><![CDATA[Titel]]></item>
<item name="chat.acp.room.topic"><![CDATA[Thema]]></item> <item name="chat.acp.room.topic"><![CDATA[Thema]]></item>
<item name="chat.acp.room.noneItems"><![CDATA[Es wurden noch keine Chaträume angelegt.]]></item>
<item name="chat.acp.room.delete.sure"><![CDATA[Wollen Sie den Raum „{$chatRoom}“ wirklich löschen?]]></item> <item name="chat.acp.room.delete.sure"><![CDATA[Wollen Sie den Raum „{$chatRoom}“ wirklich löschen?]]></item>
</category> </category>
@ -101,6 +100,8 @@
<item name="wcf.acp.option.chat_max_length"><![CDATA[Maximale Nachrichtenlänge]]></item> <item name="wcf.acp.option.chat_max_length"><![CDATA[Maximale Nachrichtenlänge]]></item>
<item name="wcf.acp.option.chat_command_aliases"><![CDATA[Befehls-Aliase]]></item> <item name="wcf.acp.option.chat_command_aliases"><![CDATA[Befehls-Aliase]]></item>
<item name="wcf.acp.option.chat_command_aliases.description"><![CDATA[Geben Sie zeilenweise eine Kombination aus Alias und Zielbefehl an. Alias und Zielbefehl werden durch einen Doppelpunkt voneinander getrennt.]]></item> <item name="wcf.acp.option.chat_command_aliases.description"><![CDATA[Geben Sie zeilenweise eine Kombination aus Alias und Zielbefehl an. Alias und Zielbefehl werden durch einen Doppelpunkt voneinander getrennt.]]></item>
<item name="wcf.acp.option.chat_force_room_select"><![CDATA[Raumauswahl anzeigen]]></item>
<item name="wcf.acp.option.chat_force_room_select.description"><![CDATA[Zeigt eine Auswahl der verfügbaren Räume an, anstatt den ersten verfügbaren Raum zu betreten.]]></item>
<item name="wcf.acp.option.category.chat.log"><![CDATA[Protokoll]]></item> <item name="wcf.acp.option.category.chat.log"><![CDATA[Protokoll]]></item>
<item name="wcf.acp.option.chat_log_archivetime"><![CDATA[Speicherzeit]]></item> <item name="wcf.acp.option.chat_log_archivetime"><![CDATA[Speicherzeit]]></item>
@ -135,46 +136,50 @@ Probieren Sie, den Chat neu zu laden<!-- , bei Risiken und Nebenwirkungen fragen
<item name="chat.error.whisper.ignoresYou"><![CDATA[„{$user}“ hat Sie blockiert.]]></item> <item name="chat.error.whisper.ignoresYou"><![CDATA[„{$user}“ hat Sie blockiert.]]></item>
</category> </category>
<category name="chat.general"> <category name="chat.global">
<item name="chat.general.expires"><![CDATA[Ablaufzeitpunkt]]></item> <item name="chat.global.expires"><![CDATA[Ablaufzeitpunkt]]></item>
<item name="chat.general.time"><![CDATA[Datum]]></item> <item name="chat.global.time"><![CDATA[Datum]]></item>
<item name="chat.general.title"><![CDATA[{lang}chat.header.menu.chat{/lang}]]></item>
<item name="chat.general.protocol"><![CDATA[Protokoll]]></item>
<item name="chat.general.room"><![CDATA[Chatraum]]></item> <item name="chat.global.title"><![CDATA[{lang}chat.header.menu.chat{/lang}]]></item>
<item name="chat.general.rooms"><![CDATA[Chaträume]]></item> <item name="chat.global.protocol"><![CDATA[Protokoll]]></item>
<item name="chat.general.users"><![CDATA[Nutzer]]></item>
<item name="chat.general.copyright"><![CDATA[<a href="http://tims.bastelstu.be"><strong>Tims Chat</strong>{if SHOW_VERSION_NUMBER} {PACKAGE_VERSION}{/if}, entwickelt in <strong>Tims Bastelstube</strong></a>]]></item> <item name="chat.global.room"><![CDATA[Chatraum]]></item>
<item name="chat.general.copyright.leader"><![CDATA[Projektleiter]]></item> <item name="chat.global.rooms"><![CDATA[Chaträume]]></item>
<item name="chat.general.copyright.developer"><![CDATA[Entwickler]]></item> <item name="chat.global.users"><![CDATA[Nutzer]]></item>
<item name="chat.general.copyright.graphics"><![CDATA[Grafisches]]></item>
<item name="chat.general.copyright.translation"><![CDATA[Übersetzung]]></item>
<item name="chat.general.copyright.thanks"><![CDATA[Weiteren Dank an]]></item>
<item name="chat.general.submit.default"><![CDATA[Zum Senden Enter drücken]]></item> <item name="chat.global.copyright"><![CDATA[<a href="http://tims.bastelstu.be"{if EXTERNAL_LINK_TARGET_BLANK} target="_blank"{/if}><strong>Tims Chat</strong>{if SHOW_VERSION_NUMBER} {PACKAGE_VERSION}{/if}, entwickelt in <strong>Tims Bastelstube</strong></a>]]></item>
<item name="chat.general.scroll"><![CDATA[Scrollen]]></item> <item name="chat.global.copyright.leader"><![CDATA[Projektleiter]]></item>
<item name="chat.general.notify"><![CDATA[Benachrichtigen]]></item> <item name="chat.global.copyright.developer"><![CDATA[Entwickler]]></item>
<item name="chat.general.notify.title"><![CDATA[Neue Nachrichten]]></item> <item name="chat.global.copyright.graphics"><![CDATA[Grafisches]]></item>
<item name="chat.general.smilies"><![CDATA[Smilies]]></item> <item name="chat.global.copyright.translation"><![CDATA[Übersetzung]]></item>
<item name="chat.general.clear"><![CDATA[Chat leeren]]></item> <item name="chat.global.copyright.thanks"><![CDATA[Weiteren Dank an]]></item>
<item name="chat.general.mark"><![CDATA[Markieren]]></item>
<item name="chat.general.fullscreen"><![CDATA[Vollbild]]></item>
<item name="chat.general.forceRefresh"><![CDATA[Räume neu laden]]></item>
<item name="chat.general.query"><![CDATA[Privates Gespräch]]></item> <item name="chat.global.submit.default"><![CDATA[Zum Senden Enter drücken]]></item>
<item name="chat.general.kick"><![CDATA[Kicken]]></item> <item name="chat.global.scroll"><![CDATA[Scrollen]]></item>
<item name="chat.general.ban"><![CDATA[Bannen]]></item> <item name="chat.global.notify"><![CDATA[Benachrichtigen]]></item>
<item name="chat.general.profile"><![CDATA[Profil]]></item> <item name="chat.global.notify.title"><![CDATA[Neue Nachrichten]]></item>
<item name="chat.global.smilies"><![CDATA[Smilies]]></item>
<item name="chat.global.clear"><![CDATA[Chat leeren]]></item>
<item name="chat.global.mark"><![CDATA[Markieren]]></item>
<item name="chat.global.fullscreen"><![CDATA[Vollbild]]></item>
<item name="chat.global.forceRefresh"><![CDATA[Räume neu laden]]></item>
<item name="chat.general.information"><![CDATA[Information]]></item> <item name="chat.global.whisper"><![CDATA[Flüstern]]></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.global.query"><![CDATA[Privates Gespräch]]></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.global.kick"><![CDATA[Kicken]]></item>
<item name="chat.global.ban"><![CDATA[Bannen]]></item>
<item name="chat.global.profile"><![CDATA[Profil]]></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.global.message"><![CDATA[Nachricht]]></item>
<item name="chat.general.closePrivateChannel"><![CDATA[Privaten Kanal schließen]]></item> <item name="chat.global.whispers"><![CDATA[Flüstert]]></item>
<item name="chat.general.closeTopic"><![CDATA[Thema ausblenden]]></item>
<item name="chat.global.information"><![CDATA[Information]]></item>
<item name="chat.global.information.chatUpdate"><![CDATA[Der Chat wurde aktualisiert. Bitte laden Sie die Seite neu, da es sonst zu Fehlern kommen kann.]]></item>
<item name="chat.global.information.suspension"><![CDATA[{lang}chat.suspension.{$suspension->type}{/lang} ({if $room}{$room}{else}{lang}chat.room.global{/lang}{/if})]]></item>
<item name="chat.global.privateChannelTopic"><![CDATA[{literal}Sie befinden sich in einem privaten Kanal mit „{$username}“, um diesen zu schließen.{/literal}]]></item>
<item name="chat.global.closePrivateChannel"><![CDATA[Privaten Kanal schließen]]></item>
<item name="chat.global.closeTopic"><![CDATA[Thema ausblenden]]></item>
</category> </category>
<category name="chat.header"> <category name="chat.header">
@ -211,7 +216,7 @@ Probieren Sie, den Chat neu zu laden<!-- , bei Risiken und Nebenwirkungen fragen
<category name="chat.suspension"> <category name="chat.suspension">
<item name="chat.suspension.mute"><![CDATA[Knebel]]></item> <item name="chat.suspension.mute"><![CDATA[Knebel]]></item>
<item name="chat.suspension.ban"><![CDATA[Bann]]></item> <item name="chat.suspension.ban"><![CDATA[Bann]]></item>
<item name="chat.suspension.exists"><![CDATA[Es existiert bereits eine längere Sanktion der gleichen Art.]]></item> <item name="chat.suspension.exists"><![CDATA[Es existiert bereits eine länger andauernde Sanktion der gleichen Art.]]></item>
<item name="chat.suspension.notExists"><![CDATA[Es existiert keine Sanktion dieser Art.]]></item> <item name="chat.suspension.notExists"><![CDATA[Es existiert keine Sanktion dieser Art.]]></item>
</category> </category>

View File

@ -6,7 +6,7 @@
<packagedescription><![CDATA[Tims Chat is a capable chat software for your community. It convices by a seamless integration into your community, advanced permissions, it is feature rich and easily customized via the templates!]]></packagedescription> <packagedescription><![CDATA[Tims Chat is a capable chat software for your community. It convices by a seamless integration into your community, advanced permissions, it is feature rich and easily customized via the templates!]]></packagedescription>
<packagedescription language="de"><![CDATA[Tims Chat ist ein leistungsfähiges Chatsystem für Ihre Community. Er überzeugt durch eine nahtlose Integration in das Design Ihrer Community, ein umfangreiches Rechtesystem, Funktionsreichtum und ist über die Templates kinderleicht zu verändern!]]></packagedescription> <packagedescription language="de"><![CDATA[Tims Chat ist ein leistungsfähiges Chatsystem für Ihre Community. Er überzeugt durch eine nahtlose Integration in das Design Ihrer Community, ein umfangreiches Rechtesystem, Funktionsreichtum und ist über die Templates kinderleicht zu verändern!]]></packagedescription>
<isapplication>1</isapplication> <isapplication>1</isapplication>
<version>3.0.0 Alpha 90</version><!-- Codename: Codenames are overrated --> <version>3.0.0 Alpha 110</version><!-- Codename: Codenames are overrated -->
<date>2011-11-26</date> <date>2011-11-26</date>
<license><![CDATA[Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>]]></license> <license><![CDATA[Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>]]></license>
</packageinformation> </packageinformation>

View File

@ -1,47 +1,47 @@
{if $__chat->isActiveApplication()} {if $__chat->isActiveApplication()}
{if $templateName != '__copyright'}<address id="timsChatCopyright" class="copyright marginTop">{lang}chat.general.copyright{/lang}</address> {if $templateName != '__copyright'}<address id="timsChatCopyright" class="copyright marginTop">{lang}chat.global.copyright{/lang}</address>
{elseif $templateName == '__copyright'} {elseif $templateName == '__copyright'}
<div style="background-image: url('data:image/png;base64,{$background}');"> <div style="background-image: url('data:image/png;base64,{$background}');">
<dl> <dl>
<dt>{lang}chat.general.copyright.leader{/lang}</dt> <dt>{lang}chat.global.copyright.leader{/lang}</dt>
<dd> <dd>
<ul> <ul>
<li><a href="http://tims.bastelstu.be/" class="externalURL" {if EXTERNAL_LINK_TARGET_BLANK}target="_blank"{/if}>Tim D&uuml;sterhus</a></li> <li><a href="http://tims.bastelstu.be/" class="externalURL"{if EXTERNAL_LINK_TARGET_BLANK} target="_blank"{/if}>Tim D&uuml;sterhus</a></li>
</ul> </ul>
</dd> </dd>
</dl> </dl>
<dl> <dl>
<dt>{lang}chat.general.copyright.developer{/lang}</dt> <dt>{lang}chat.global.copyright.developer{/lang}</dt>
<dd> <dd>
<ul> <ul>
<li><a href="http://tims.bastelstu.be/" class="externalURL" {if EXTERNAL_LINK_TARGET_BLANK}target="_blank"{/if}>Tim D&uuml;sterhus</a></li> <li><a href="http://tims.bastelstu.be/" class="externalURL"{if EXTERNAL_LINK_TARGET_BLANK} target="_blank"{/if}>Tim D&uuml;sterhus</a></li>
<li><a href="https://github.com/max-m" class="externalURL" {if EXTERNAL_LINK_TARGET_BLANK}target="_blank"{/if}>Maximilian Mader</a></li> <li><a href="https://github.com/max-m" class="externalURL"{if EXTERNAL_LINK_TARGET_BLANK} target="_blank"{/if}>Maximilian Mader</a></li>
</ul> </ul>
</dd> </dd>
</dl> </dl>
{*<dl> {*<dl>
<dt>{lang}chat.general.copyright.graphics{/lang}</dt> <dt>{lang}chat.global.copyright.graphics{/lang}</dt>
<dd> <dd>
</dd> </dd>
</dl> </dl>
<dl> <dl>
<dt>{lang}chat.general.copyright.translation{/lang}</dt> <dt>{lang}chat.global.copyright.translation{/lang}</dt>
<dd> <dd>
</dd> </dd>
</dl>*} </dl>*}
<dl> <dl>
<dt>{lang}chat.general.copyright.thanks{/lang}</dt> <dt>{lang}chat.global.copyright.thanks{/lang}</dt>
<dd> <dd>
<ul> <ul>
<li><a href="http://www.wbbaddons.de/user/2020-noone/" class="externalURL" {if EXTERNAL_LINK_TARGET_BLANK}target="_blank"{/if}>-noone-</a></li> <li><a href="http://www.wbbaddons.de/user/2020-noone/" class="externalURL"{if EXTERNAL_LINK_TARGET_BLANK} target="_blank"{/if}>-noone-</a></li>
<li><a href="https://github.com/Gabbid" class="externalURL" {if EXTERNAL_LINK_TARGET_BLANK}target="_blank"{/if}>Gabi</a></li> <li>Gabi</li>
<li>Alexandra Glass</li> <li>Alexandra Glass</li>
<li><a href="https://github.com/Leon-" class="externalURL" {if EXTERNAL_LINK_TARGET_BLANK} target="_blank"{/if}>Stefan Hahn</a></li> <li><a href="https://github.com/Leon-" class="externalURL"{if EXTERNAL_LINK_TARGET_BLANK} target="_blank"{/if}>Stefan Hahn</a></li>
<li><a href="https://kittblog.com/" class="externalURL" {if EXTERNAL_LINK_TARGET_BLANK}target="_blank"{/if}>Matthias Kittsteiner</a></li> <li><a href="http://kittmedia.com/" class="externalURL"{if EXTERNAL_LINK_TARGET_BLANK} target="_blank"{/if}>Matthias Kittsteiner</a></li>
<li><a href="http://www.wbbaddons.de" class="externalURL" {if EXTERNAL_LINK_TARGET_BLANK}target="_blank"{/if}>Martin Schwendowius</a></li> <li><a href="http://www.wbbaddons.de" class="externalURL"{if EXTERNAL_LINK_TARGET_BLANK} target="_blank"{/if}>Martin Schwendowius</a></li>
<li><a href="http://www.cls-design.com/" class="externalURL" {if EXTERNAL_LINK_TARGET_BLANK}target="_blank"{/if}>Tom</a></li> <li><a href="http://www.cls-design.com/" class="externalURL"{if EXTERNAL_LINK_TARGET_BLANK} target="_blank"{/if}>Tom</a></li>
</ul> </ul>
</dd> </dd>
</dl> </dl>

View File

@ -1,55 +1,60 @@
{include file='documentHeader'} {include file='documentHeader'}
<head> <head>
<title>{if $room}{$room} - {/if}{lang}chat.general.title{/lang} - {PAGE_TITLE|language}</title> <title>{if $room}{$room} - {/if}{lang}chat.global.title{/lang} - {PAGE_TITLE|language}</title>
{include file='headInclude' sandbox=false}
{if $room} {if $room}
{include file='headInclude' sandbox=false}
{include file='javascriptInclude' application='chat'} {include file='javascriptInclude' application='chat'}
<script data-relocate="true"> <script data-relocate="true">
//<![CDATA[ //<![CDATA[
(function ($, window) { (function ($, window) {
$(function(){ $(function(){
WCF.Language.addObject({ WCF.Language.addObject({
'chat.general.query': '{lang}chat.general.query{/lang}', 'chat.global.ban': '{lang}chat.global.ban{/lang}',
'chat.general.kick': '{lang}chat.general.kick{/lang}', 'chat.global.closePrivateChannel': '{lang}chat.global.closePrivateChannel{/lang}',
'chat.general.ban': '{lang}chat.general.ban{/lang}', 'chat.global.closeTopic': '{lang}chat.global.closeTopic{/lang}',
'chat.general.profile': '{lang}chat.general.profile{/lang}', 'chat.global.notify.title': '{lang}chat.global.notify.title{/lang}',
'chat.general.notify.title': '{lang}chat.general.notify.title{/lang}', 'chat.global.privateChannelTopic': '{lang}chat.global.privateChannelTopic{/lang}',
'chat.general.privateChannelTopic': '{lang}chat.general.privateChannelTopic{/lang}', 'chat.global.profile': '{lang}chat.global.profile{/lang}',
'chat.general.closePrivateChannel': '{lang}chat.general.closePrivateChannel{/lang}', 'chat.global.query': '{lang}chat.global.query{/lang}',
'chat.general.closeTopic': '{lang}chat.general.closeTopic{/lang}', 'chat.global.whisper': '{lang}chat.global.whisper{/lang}',
'chat.error.onMessageLoad': '{@"chat.error.onMessageLoad"|language|encodeJS}',
'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}',
'chat.error.onMessageLoad': '{@"chat.error.onMessageLoad"|language|encodeJS}',
'chat.error.reload': '{lang}chat.error.reload{/lang}', 'chat.error.reload': '{lang}chat.error.reload{/lang}',
'chat.message.{$messageTypes[TYPE_ATTACHMENT]}': '{lang}chat.message.{$messageTypes[TYPE_ATTACHMENT]}{/lang}',
'wcf.attachment.insert': '{lang}wcf.attachment.insert{/lang}',
'wcf.attachment.delete.sure': '{lang}wcf.attachment.delete.sure{/lang}',
'wcf.attachment.upload.error.invalidExtension': '{lang}wcf.attachment.upload.error.invalidExtension{/lang}', '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.tooLarge': '{lang}wcf.attachment.upload.error.tooLarge{/lang}',
'wcf.attachment.upload.error.reachedLimit': '{lang}wcf.attachment.upload.error.reachedLimit{/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.reachedRemainingLimit': '{lang}wcf.attachment.upload.error.reachedRemainingLimit{/lang}',
'wcf.attachment.upload.error.uploadFailed': '{lang}wcf.attachment.upload.error.uploadFailed{/lang}', 'wcf.attachment.upload.error.uploadFailed': '{lang}wcf.attachment.upload.error.uploadFailed{/lang}',
'wcf.global.button.upload': '{lang}wcf.global.button.upload{/lang}', 'wcf.global.button.upload': '{lang}wcf.global.button.upload{/lang}'
'wcf.attachment.insert': '{lang}wcf.attachment.insert{/lang}',
'wcf.attachment.delete.sure': '{lang}wcf.attachment.delete.sure{/lang}',
'chat.message.{$messageTypes[TYPE_ATTACHMENT]}': '{lang}chat.message.{$messageTypes[TYPE_ATTACHMENT]}{/lang}'
}); });
// Boot the chat // Boot the chat
{if MODULE_SMILEY}WCF.TabMenu.init();{/if}
{if MODULE_ATTACHMENT && $__wcf->session->getPermission('user.chat.canUploadAttachment')} {if MODULE_ATTACHMENT && $__wcf->session->getPermission('user.chat.canUploadAttachment')}
new be.bastelstu.Chat.Attachment(); new be.bastelstu.Chat.Attachment();
new be.bastelstu.Chat.Action.Delete('wcf\\data\\attachment\\AttachmentAction', '#timsChatUploadDropdownMenu > li'); new be.bastelstu.Chat.Action.Delete('wcf\\data\\attachment\\AttachmentAction', '#timsChatUploadDropdownMenu > li');
{/if} {/if}
new WCF.Message.Smilies();
WCF.TabMenu.init();
{if MODULE_SMILEY}
new WCF.Message.Smilies();
{/if}
{capture assign='messageTemplate'}{include application='chat' file='message'}{/capture} {capture assign='messageTemplate'}{include application='chat' file='message'}{/capture}
{capture assign='userTemplate'}{include application='chat' file='userListUser'}{/capture} {capture assign='userTemplate'}{include application='chat' file='userListUser'}{/capture}
{capture assign='userMenuTemplate'}{include application='chat' file='userListUserMenu'}{/capture}
var config = { var config = {
reloadTime: {@CHAT_RELOADTIME}, reloadTime: {@CHAT_RELOADTIME},
messageURL: '{link application="chat" controller="NewMessages"}{/link}', messageURL: '{link application="chat" controller="NewMessages"}{/link}',
installedCommands: [ {implode from=$commands item='command'}'{$command|encodeJS}'{/implode} ], installedCommands: [ {implode from=$commands item='command'}'{$command|encodeJS}'{/implode} ],
messageTypes: { {implode from=$messageTypes key='name' item='messageType'}'{$name|substr:5|encodeJS}': '{$messageType|encodeJS}'{/implode} } messageTypes: { {implode from=$messageTypes key='name' item='messageType'}'{$name|substr:5|encodeJS}': {$messageType}{/implode} }
}; };
{event name='beforeInit'} {event name='beforeInit'}
@ -57,14 +62,15 @@
be.bastelstu.Chat.init( be.bastelstu.Chat.init(
{$roomID}, {$roomID},
config, config,
new WCF.Template('{literal}{if $newMessageCount}({#$newMessageCount}) {/if}{$title} - {/literal}{"chat.general.title"|language|encodeJS} - {PAGE_TITLE|language|encodeJS}'), new WCF.Template('{literal}{if $newMessageCount}({#$newMessageCount}) {/if}{$title} - {/literal}{"chat.global.title"|language|encodeJS} - {PAGE_TITLE|language|encodeJS}'),
new WCF.Template('{@$messageTemplate|encodeJS}'), new WCF.Template('{@$messageTemplate|encodeJS}'),
new WCF.Template('{@$userTemplate|encodeJS}') new WCF.Template('{@$userTemplate|encodeJS}'),
new WCF.Template('{@$userMenuTemplate|encodeJS}')
); );
{event name='afterInit'} {event name='afterInit'}
$('#timsChatCopyright').click(function (event) { $('#timsChatCopyright a').click(function (event) {
event.preventDefault(); event.preventDefault();
if (!$.wcfIsset('timsChatCopyrightDialog')) $('<div id="timsChatCopyrightDialog"></div>').appendTo('body'); if (!$.wcfIsset('timsChatCopyrightDialog')) $('<div id="timsChatCopyrightDialog"></div>').appendTo('body');
$('#timsChatCopyrightDialog').load('{link application="chat" controller="Copyright"}{/link}').wcfDialog({ $('#timsChatCopyrightDialog').load('{link application="chat" controller="Copyright"}{/link}').wcfDialog({
@ -83,78 +89,118 @@
{capture assign='sidebar'}{include application='chat' file='sidebar'}{/capture} {capture assign='sidebar'}{include application='chat' file='sidebar'}{/capture}
{include file='header' sandbox=false sidebarOrientation='right'} {include file='header' sandbox=false sidebarOrientation='right'}
<div id="timsChatTopic" class="marginTop container{if $room->topic|language === ''} empty{/if}"> <div class="clearfix">
<span class="icon icon16 icon-remove jsTopicCloser jsTooltip" title="{lang}chat.general.closeTopic{/lang}"></span> <div id="timsChatTopic" class="container containerPadding marginTop{if $room->topic|language === ''} empty{/if}">
<span class="topic">{$room->topic|language}</span> <span id="timsChatTopicCloser" class="icon icon16 icon-remove jsTooltip" title="{lang}chat.global.closeTopic{/lang}"></span>
</div> <span class="topic">{$room->topic|language}</span>
</div>
<div id="privateChannelsMenu">
<ul> <div id="timsChatMessageTabMenu" class="tabMenuContainer singleTab" data-active="timsChatMessageContainer0">
<li id="privateChannel0" class="privateChannel active" data-private-channel-id="0"> <nav class="tabMenu">
<span class="userAvatar framed small"> <ul>
<span class="icon icon16 icon-comment-alt jsTooltip" title="{lang}chat.general.room{/lang}"></span> <li>
</span> <a id="timsChatMessageTabMenuAnchor0" href="{$__wcf->getAnchor('timsChatMessageContainer0')}" class="timsChatMessageTabMenuAnchor" data-user-id="0">
<span class="userAvatar framed large"> <span class="icon icon16 icon-warning-sign notifyIcon"></span>{*
<span class="icon icon32 icon-comment-alt jsTooltip" title="{lang}chat.general.room{/lang}"></span> *}<span class="userAvatar framed">
</span> <span class="icon icon16 icon-group"></span>
</li> </span>{*
</ul> *}<span>{$room}</span>
</div> </a>
<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>
<ul>
</ul>
</div>
<form id="timsChatForm" action="{link application='chat' controller='Chat' action='Send'}{/link}" method="post">
<fieldset>
<dl class="wide" id="timsChatInputContainer">
<dt>
{lang}chat.general.message{/lang}
</dt>
<dd>
<input id="timsChatInput" accesskey="w" type="text" class="inputText long" name="text" autocomplete="off" maxlength="{@CHAT_MAX_LENGTH}" disabled="disabled" placeholder="{lang}chat.general.submit.default{/lang}" />
<small class="innerError" style="display: none;">Lorem ipsum dolor sit amet.</small>
</dd>
</dl>
</fieldset>
<button type="submit" class="invisible" accesskey="s"></button>
</form>
{if MODULE_SMILEY && $smileyCategories|count}
{include file='messageFormSmilies' wysiwygSelector=''}
{/if}
<nav id="timsChatOptions" class="marginTop jsMobileNavigation buttonGroupNavigation">
<span class="invisible">{lang}chat.general.controls{/lang}</span>
<ul class="smallButtons buttonGroup">
<li><a id="timsChatAutoscroll" accesskey="d" class="button active timsChatToggle jsTooltip" title="{lang}chat.general.scroll{/lang}" data-status="1"><span class="icon icon16 icon-arrow-down"></span><span class="invisible">{lang}chat.general.scroll{/lang}</span></a></li>{*
*}<li><a id="timsChatFullscreen" accesskey="f" class="button timsChatToggle jsTooltip" title="{lang}chat.general.fullscreen{/lang}" data-status="0"><span class="icon icon16 icon-fullscreen"></span><span class="invisible">{lang}chat.general.fullscreen{/lang}</span></a></li>{*
*}<li><a id="timsChatNotify" accesskey="n" class="button timsChatToggle jsTooltip" title="{lang}chat.general.notify{/lang}" data-status="0"><span class="icon icon16 icon-bell-alt"></span><span class="invisible">{lang}chat.general.notify{/lang}</span></a></li>{*
*}<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>{*
*}{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.attachment.attachments{/lang}" data-toggle="timsChatUploadContainer">
<span class="icon icon16 icon-paper-clip"></span>
<span class="invisible">{lang}wcf.attachment.attachments{/lang}</span>
</a>
<ul id="timsChatUploadDropdownMenu" class="dropdownMenu">
<li class="uploadButton" style="margin-top: 0;">
<span><label for="timsChatUploadInput">{lang}wcf.global.button.upload{/lang}</label></span>
</li> </li>
</ul> </ul>
</li>{/if}{* </nav>
*}<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>{* <div id="timsChatMessageContainer0" class="tabMenuContent timsChatMessageContainer container containerPadding active" data-user-id="0">
<p class="error noJsOnly" style="display: none;">{lang}chat.global.noJs{/lang}</p>
<ul></ul>
</div>
</div>
<form id="timsChatForm" action="{link application='chat' controller='Chat' action='Send'}{/link}" method="post">
<fieldset>
<dl class="wide" id="timsChatInputContainer">
<dt>
{lang}chat.global.message{/lang}
</dt>
<dd>
<input id="timsChatInput" accesskey="w" type="text" class="inputText long" name="text" autocomplete="off" maxlength="{@CHAT_MAX_LENGTH}" disabled="disabled" placeholder="{lang}chat.global.submit.default{/lang}" />
<small class="innerError" style="display: none;">Lorem ipsum dolor sit amet.</small>
</dd>
</dl>
</fieldset>
<button type="submit" class="marginTop invisible" accesskey="s">{lang}wcf.global.button.submit{/lang}</button>
</form>
{if MODULE_SMILEY && $smileyCategories|count}
{include file='messageFormSmilies' wysiwygSelector=''}
{/if}
<div id="timsChatOptions" class="marginTop">
<span id="timsChatSmileyPopupButton" class="button smallButtons">
<span class="icon icon16 icon-smile"></span>
<span>{lang}chat.global.smilies{/lang}</span>
</span>
*}<li><a id="timsChatMark" class="button timsChatToggle jsTooltip" title="{lang}chat.general.mark{/lang}" data-status="0"><span class="icon icon16 icon-check"></span><span class="invisible">{lang}chat.general.mark{/lang}</span></a></li> <nav class="jsMobileNavigation buttonGroupNavigation">
</ul> <ul class="buttonGroup">
</nav> <li>
<a id="timsChatAutoscroll" accesskey="d" class="button active timsChatToggle jsTooltip" title="{lang}chat.global.scroll{/lang}" data-status="1">
<span class="icon icon16 icon-arrow-down"></span>
<span class="invisible">{lang}chat.global.scroll{/lang}</span>
</a>
</li>
<li>
<a id="timsChatFullscreen" accesskey="f" class="button timsChatToggle jsTooltip" title="{lang}chat.global.fullscreen{/lang}" data-status="0">
<span class="icon icon16 icon-fullscreen"></span>
<span class="invisible">{lang}chat.global.fullscreen{/lang}</span>
</a>
</li>
<li>
<a id="timsChatNotify" accesskey="n" class="button timsChatToggle jsTooltip" title="{lang}chat.global.notify{/lang}" data-status="0">
<span class="icon icon16 icon-bell-alt"></span>
<span class="invisible">{lang}chat.global.notify{/lang}</span>
</a>
</li>
{if MODULE_SMILEY && $smileyCategories|count}
<li>
<a id="timsChatSmilies" accesskey="e" class="button{if ENABLE_SMILIES_DEFAULT_VALUE} active{/if} timsChatToggle jsTooltip" title="{lang}chat.global.smilies{/lang}" data-status="{@ENABLE_SMILIES_DEFAULT_VALUE}">
<span class="icon icon16 icon-smile"></span>
<span class="invisible">{lang}chat.global.smilies{/lang}</span>
</a>
</li>
{/if}
{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.attachment.attachments{/lang}" data-toggle="timsChatUploadContainer">
<span class="icon icon16 icon-paper-clip"></span>
<span class="invisible">{lang}wcf.attachment.attachments{/lang}</span>
</a>
<ul id="timsChatUploadDropdownMenu" class="dropdownMenu">
<li class="uploadButton" style="margin-top: 0;">
<span><label for="timsChatUploadInput" class="pointer">{lang}wcf.global.button.upload{/lang}</label></span>
</li>
</ul>
</li>
{/if}
<li>
<a id="timsChatClear" class="button jsTooltip" title="{lang}chat.global.clear{/lang}">
<span class="icon icon16 icon-remove"></span>
<span class="invisible">{lang}chat.global.clear{/lang}</span>
</a>
</li>
<li>
<a id="timsChatMark" class="button timsChatToggle jsTooltip" title="{lang}chat.global.mark{/lang}" data-status="0">
<span class="icon icon16 icon-check"></span>
<span class="invisible">{lang}chat.global.mark{/lang}</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
{else} {else}
{include file='header' sandbox=false} {include file='header' sandbox=false}
<header class="boxHeadline"> <header class="boxHeadline">

View File

@ -1,12 +1,12 @@
{literal} {literal}
{if $message.type == $messageTypes.LEAVE || $message.type == $messageTypes.JOIN} {if $message.type == $messageTypes.JOIN || $message.type == $messageTypes.LEAVE}
<div class="messageIcon"> <div class="timsChatMessageIcon">
<span class="icon icon16 icon-{if $message.type == $messageTypes.LEAVE}signout{elseif $message.type == $messageTypes.JOIN}signin{/if}"></span> <span class="icon icon16 icon-{if $message.type == $messageTypes.JOIN}signin{else}signout{/if}"></span>
</div> </div>
{/if} {/if}
<div class="innerMessageContainer{if $message.type == $messageTypes.NORMAL || $message.type == $messageTypes.WHISPER || $message.type == $messageTypes.INFORMATION || $message.type == $messageTypes.ATTACHMENT} bubble{/if}{if $message.type == $messageTypes.WHISPER && $message.sender != $__wcf.User.userID} right{/if}"> <div class="timsChatInnerMessageContainer{if $message.type == $messageTypes.NORMAL || $message.type == $messageTypes.WHISPER || $message.type == $messageTypes.INFORMATION || $message.type == $messageTypes.ATTACHMENT} bubble{/if}{if $message.type == $messageTypes.WHISPER && $message.sender != $__wcf.User.userID} right{/if}">
<div class="avatarContainer"> <div class="timsChatAvatarContainer">
<div class="userAvatar{if $message.type != $messageTypes.INFORMATION} framed{/if}"> <div class="userAvatar framed">
{if $message.type != $messageTypes.INFORMATION} {if $message.type != $messageTypes.INFORMATION}
{if $message.type == $messageTypes.NORMAL || $message.type == $messageTypes.WHISPER || $message.type == $messageTypes.ATTACHMENT} {if $message.type == $messageTypes.NORMAL || $message.type == $messageTypes.WHISPER || $message.type == $messageTypes.ATTACHMENT}
{@$message.avatar[32]} {@$message.avatar[32]}
@ -18,46 +18,38 @@
{/if} {/if}
</div> </div>
{if $message.type == $messageTypes.ATTACHMENT} {if $message.type == $messageTypes.ATTACHMENT}
<small class="framed avatarExtra"> <small class="framed timsChatAvatarExtraIcon">
<span class="icon icon16 icon-paperclip"></span> <span class="icon icon16 icon-paperclip"></span>
</small> </small>
{/if} {/if}
</div> </div>
<div class="innerMessage"> <div class="timsChatInnerMessage">
<span class="username"> <span class="timsChatUsernameContainer">
{if ($message.type == $messageTypes.WHISPER && $message.sender == WCF.User.userID) || $message.type != $messageTypes.WHISPER}
{@$message.formattedUsername} {@$message.formattedUsername}
{else}
{$message.additionalData.receiverUsername}
{/if}
{if $message.type == $messageTypes.WHISPER} {if $message.type == $messageTypes.WHISPER}
<span class="icon icon16 icon-double-angle-{if $message.sender == WCF.User.userID}right{else}left{/if} jsTooltip" title="{/literal}{lang}chat.ui.whispers{/lang}{literal}" onclick="be.bastelstu.Chat.insertText('/whisper {if $message.receiver == WCF.User.userID}{$message.username.replace("\\", "\\\\").replace("'", "\\'")}{else}{$message.additionalData.receiverUsername.replace("\\", "\\\\").replace("'", "\\'")}{/if}, ', { append: false });"></span> <span class="icon icon16 icon-double-angle-right jsTooltip pointer" title="{/literal}{lang}chat.global.whispers{/lang}{literal}" onclick="be.bastelstu.Chat.insertText('/whisper {if $message.receiver == WCF.User.userID}{$message.username.replace("\\", "\\\\").replace("'", "\\'")}{else}{$message.additionalData.receiverUsername.replace("\\", "\\\\").replace("'", "\\'")}{/if}, ', { append: false });"></span>
{if ($message.type == $messageTypes.WHISPER && $message.sender == WCF.User.userID) || $message.type != $messageTypes.WHISPER} <span class="reciever">{$message.additionalData.receiverUsername}</span>
{$message.additionalData.receiverUsername}
{else}
{@$message.formattedUsername}
{/if} {/if}
{/if}
</span> </span>
<time>{@$message.formattedTime}</time> <time>{@$message.formattedTime}</time>
{if $message.type == $messageTypes.NORMAL || $message.type == $messageTypes.WHISPER || $message.type == $messageTypes.ATTACHMENT} {if $message.type == $messageTypes.NORMAL || $message.type == $messageTypes.WHISPER || $message.type == $messageTypes.ATTACHMENT}
{if $message.type == $messageTypes.ATTACHMENT}<span>{lang}chat.message.{$messageTypes.ATTACHMENT}{/lang}</span>{/if} {if $message.type == $messageTypes.ATTACHMENT}<span>{lang}chat.message.{$messageTypes.ATTACHMENT}{/lang}</span>{/if}
<ul class="text"> <ul class="timsChatText">
<li> <li>
{if $message.isFollowUp} <time>{@$message.formattedTime}</time>{/if} {if $message.isFollowUp} <time>{@$message.formattedTime}</time>{/if}
{@$message.formattedMessage} {@$message.formattedMessage}
</li> </li>
</ul> </ul>
{elseif $message.type == $messageTypes.INFORMATION} {elseif $message.type == $messageTypes.INFORMATION}
<div class="text">{@$message.formattedMessage}</div> <div class="timsChatText">{@$message.formattedMessage}</div>
{else} {else}
<span class="text">{@$message.formattedMessage}</span> <span class="timsChatText">{@$message.formattedMessage}</span>
{/if} {/if}
</div> </div>
<span class="markContainer"> <span class="timsChatMarkContainer">
<input type="checkbox" value="{@$message.messageID}" /> <input type="checkbox" value="{@$message.messageID}" />
</span> </span>
</div> </div>

View File

@ -1,29 +1,19 @@
<div class="tabMenuContainer chatTabMenuContainer containerPadding"> <fieldset id="timsChatUserListContainer">
<nav class="menu chatSidebarMenu"> <legend>{lang}chat.global.users{/lang}</legend>
<ul> <div id="timsChatUserList">
<li id="toggleUsers" class="ui-state-active"><a href="{@$__wcf->getAnchor('timsChatUserList')}" title="{lang}chat.general.users{/lang}">{lang}chat.general.users{/lang} <span class="badge">0</span></a></li> <ul class="sidebarNestedCategoryList">
<li id="toggleRooms"><a href="{@$__wcf->getAnchor('timsChatRoomList')}" title="{lang}chat.general.rooms{/lang}">{lang}chat.general.rooms{/lang} <span class="badge">0</span></a></li>
</ul> </ul>
</nav> </div>
</fieldset>
<section id="sidebarContent" class="tabMenuContent"> <fieldset id="timsChatRoomListContainer">
<fieldset> <legend>{lang}chat.global.rooms{/lang}</legend>
<nav id="timsChatUserList"> <div id="timsChatRoomList">
<ul> <ul class="sidebarNestedCategoryList">
</ul>
</nav> </ul>
</fieldset> </div>
<div class="marginTop">
<fieldset> <a id="timsChatRoomListReloadButton" class="button small jsOnly">{lang}chat.global.forceRefresh{/lang}</a>
<nav id="timsChatRoomList" style="display: none;"> </div>
<div> </fieldset>
<ul>
</ul>
<div class="marginTop">
<button type="button">{lang}chat.general.forceRefresh{/lang}</button>
</div>
</div>
</nav>
</fieldset>
</section>
</div>

View File

@ -1 +1 @@
{literal}<a{if $userID != $__wcf.User.userID} class="dropdownToggle"{/if} data-user-id="{$userID.toString()}">{@$avatar['24']}{$username}</a>{/literal} {literal}<a{if $userID != $__wcf.User.userID} class="dropdownToggle"{/if} data-user-id="{$userID.toString()}"><span class="framed">{@$avatar['24']}</span>{$username}</a>{/literal}

View File

@ -0,0 +1,8 @@
{literal}
<ul data-user-id="{$userID}">
<li><a class="jsTimsChatUserMenuWhisper">{lang}chat.global.whisper{/lang}</a></li>
<li><a class="jsTimsChatUserMenuQuery">{lang}chat.global.query{/lang}</a></li>
<li><a class="jsTimsChatUserMenuBan">{lang}chat.global.ban{/lang}</a></li>
<li><a href="{$link}" class="userLink" data-user-id="{$userID}">{lang}chat.global.profile{/lang}</a></li>
</ul>
{/literal}