1
0
mirror of https://github.com/wbbaddons/Tims-Chat.git synced 2024-12-21 21:30: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>
<tr>
<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>{lang}chat.acp.log.message{/lang}</th>
</tr>

View File

@ -66,7 +66,7 @@
</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>
<select id="roomID" name="roomID">
<option value="-1"{if $roomID == -1} selected="selected"{/if}></option>
@ -120,10 +120,10 @@
<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="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="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="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="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.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="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>
<dl>
<dt><label for="id">{lang}chat.general.room{/lang}</label></dt>
<dt><label for="id">{lang}chat.global.room{/lang}</label></dt>
<dd>
<select id="id" name="id">
{foreach from=$rooms item='roomBit'}
@ -38,7 +38,7 @@
</dl>
<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>
<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'}

View File

@ -41,7 +41,7 @@ public function execute() {
'roomID' => $room->roomID,
'time' => TIME_NOW,
'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();

View File

@ -6,7 +6,7 @@ everything that happens in the GUI of **Tims Chat**.
### Copyright Information
# @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>
# @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}"
error: (message) ->
window.console.error "[be.bastelstu.Chat] #{message}"
Continue with defining the needed variables. All variables are local to our closure and will be
exposed by a function if necessary.
@ -45,6 +45,9 @@ exposed by a function if necessary.
lastMessage = null
openChannel = 0
messageContainerSize = 0
userListSize = 0
remainingFailures = 3
events =
@ -73,14 +76,18 @@ exposed by a function if necessary.
Initialize **Tims Chat**. Bind needed DOM events and initialize data structures.
initialized = false
init = (roomID, config, titleTemplate, messageTemplate, userTemplate) ->
init = (roomID, config, titleTemplate, messageTemplate, userTemplate, userMenuTemplate) ->
return false if initialized
initialized = true
messageContainerSize = $('.timsChatMessageContainer').height()
userListSize = $('#timsChatUserList').height()
v.config = config
v.titleTemplate = titleTemplate
v.messageTemplate = messageTemplate
v.userTemplate = userTemplate
v.userMenuTemplate = userMenuTemplate
console.log 'Initializing'
@ -110,14 +117,40 @@ Make the user leave the chat when **Tims Chat** is about to be unloaded.
async: false
suppressErrors: true
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.
$('#smilies').on 'click', 'img', -> insertText " #{$(@).attr('alt')} "
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
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
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.
$('#timsChatRoomList button').click -> do refreshRoomList
$('#timsChatRoomListReloadButton').click -> do refreshRoomList
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) ->
if $(@).data 'status'
$('#smilies').removeClass 'disabled'
$('#smilies').removeClass 'invisible'
else
$('#smilies').addClass 'disabled'
$('#smilies').addClass 'invisible'
Toggle fullscreen mode.
@ -259,7 +307,10 @@ Toggle fullscreen mode.
if $(@).data 'status'
$('html').addClass 'fullscreen'
do $(window).resize
else
$('.timsChatMessageContainer').height messageContainerSize
$('#timsChatUserList').height userListSize
$('html').removeClass 'fullscreen'
Toggle checkboxes.
@ -272,12 +323,14 @@ Toggle checkboxes.
Hide topic container.
$('.jsTopicCloser').on 'click', ->
if $('.timsChatMessageContainer.active').data('userID') is 0
$('#timsChatTopic').addClass 'hidden'
else
closePrivateChannel $('.timsChatMessageContainer.active').data('userID')
$('#timsChatTopicCloser').on 'click', ->
$('#timsChatTopic').addClass 'invisible'
do $(window).resize
Close private channels
$('#timsChatMessageTabMenu').on 'click', '.jsChannelCloser', -> closePrivateChannel $(@).parent().data 'userID'
Visibly mark the message once the associated checkbox is checked.
$(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.
$('#timsChatAutoscroll').click (event) ->
if $('#timsChatAutoscroll').data 'status'
if $(@).data 'status'
$('.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) ->
event.stopPropagation();
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
do event.stopPropagation
handleScroll event
Enable duplicate tab detection.
@ -387,35 +433,85 @@ Free the fish.
freeTheFish = ->
return if $.wcfIsset '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
position: 'fixed'
top: '50%'
left: '50%'
color: 'black'
textShadow: '1px 1px white'
zIndex: 9999
zIndex: 0x7FFFFFFF
textShadow: '1px 1px rgb(0, 0, 0)'
fish.appendTo $ 'body'
pe.fish = new WCF.PeriodicalExecuter ->
left = Math.random() * 100 - 50
top = Math.random() * 100 - 50
fish = $ '#fish'
fish.colors = ['78C5D6', '459ba8', '79C267', 'C5D647', 'F5D63D', 'F28C33', 'E868A2', 'BF62A6']
fish.colorIndex = 0
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())
top *= -1 unless fish.height() < (fish.position().top + top) < ($(window).height() - fish.height())
if left > 0
fish.text '><((((\u00B0>' if left > 0
else if left < 0
fish.text '<\u00B0))))><'
while index < value.length
html = $ '<span/>'
i = 0
$(value.split '').each (key, value) ->
$("<span>#{value}</span>").css
color: '#' + fish.colors[(i++ + index) % fish.colors.length]
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
top: (fish.position().top + top)
left: (fish.position().left + left)
, 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`.
`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.
handleMessages = (messages) ->
$('.timsChatMessageContainer.active').trigger 'scroll'
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
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
createNewMessage = no
@ -493,11 +587,34 @@ Insert the given messages into the chat stream.
else
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
$('.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`.
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
menu = $ '<ul></ul>'
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
menu = $(v.userMenuTemplate.fetch user)
if menu.find('li').length
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.appendTo $ '#timsChatUserList > ul'
foundUsers[id] = true
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.
insertText = (text, options = { }) ->
options.append = false if options.prepend? and options.prepend and not options.append?
options = $.extend
prepend: false
append: true
submit: false
, options
text = text + $('#timsChatInput').val() if options.prepend
text = $('#timsChatInput').val() + text if options.append
$('#timsChatInput').val text
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.
notify = (message) ->
if scrollUpNotifications
$('.timsChatMessageContainer.active').addClass 'notification'
return if message.sender is WCF.User.userID
if message.isInPrivateChannel
if message.sender is WCF.User.userID
privateChannelID = message.receiver
else
privateChannelID = message.sender
if scrollUpNotifications
$("#timsChatMessageTabMenu > .tabMenu > ul > li.ui-state-active").addClass 'notify'
$(".timsChatMessageContainer.active").addClass 'notify'
if $('.timsChatMessageContainer.active').data('userID') isnt privateChannelID
$("#privateChannel#{privateChannelID}").addClass 'notify'
if message.isInPrivateChannel
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
$("#privateChannel0").addClass 'notify'
$("#timsChatMessageTabMenuAnchor0").parent().addClass 'notify'
$("#timsChatMessageContainer0").addClass 'notify'
return if isActive or $('#timsChatNotify').data('status') is 0
document.title = v.titleTemplate.fetch $.extend {}, currentRoom,
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}"
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
li = $ '<li></li>'
li.addClass('timsChatRoom').data('roomID', room.roomID)
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
if window.history?.replaceState?
@ -705,7 +822,7 @@ Joins a room.
success: (data) ->
loading = false
$('#timsChatTopic').removeClass 'hidden'
$('#timsChatTopic').removeClass 'invisible'
currentRoom = data.returnValues
currentRoom.roomID = roomID
@ -737,66 +854,74 @@ Open private channel
div = $ '<div>'
div.attr 'id', "timsChatMessageContainer#{userID}"
div.data 'userID', userID
div.addClass 'tabMenuContent'
div.addClass 'timsChatMessageContainer'
div.addClass 'marginTop'
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
$('.privateChannel').removeClass 'active'
$('.timsChatMessageContainer').height $('.timsChatMessageContainer').height()
if userID isnt 0
$('#timsChatTopic').removeClass 'hidden empty'
$('#timsChatTopic > .topic').html WCF.Language.get 'chat.general.privateChannelTopic', {username: userList.allTime[userID].username}
$('#timsChatTopic > .jsTopicCloser').attr 'title', WCF.Language.get 'chat.general.closePrivateChannel'
$('#timsChatTopic').removeClass 'empty'
$('#timsChatTopic > .topic').html WCF.Language.get 'chat.global.privateChannelTopic', {username: userList.allTime[userID].username}
$('#timsChatMessageTabMenu').removeClass 'singleTab'
unless $.wcfIsset "privateChannel#{userID}"
unless $.wcfIsset "timsChatMessageTabMenuAnchor#{userID}"
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.addClass 'jsTooltip'
avatar.attr 'title', userList.allTime[userID].username
avatar.wrap span
li.append avatar.parent().addClass 'small'
avatar = $('<span class="userAvatar framed" />').wrapInner avatar
avatar.append "<span>#{userList.allTime[userID].username}</span>"
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'
anchor.wrapInner avatar
anchor.prepend '<span class="icon icon16 icon-warning-sign notifyIcon"></span>'
anchor.append """<span class="jsChannelCloser icon icon16 icon-remove jsTooltip" title="#{WCF.Language.get('chat.global.closePrivateChannel')}" />"""
$('#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
$('#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#{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
Close private channel
closePrivateChannel = (userID) ->
unless userID is 0
do $("#privateChannel#{userID}").remove
do $("#timsChatMessageTabMenuAnchor#{userID}").parent().remove
do $("#timsChatMessageContainer#{userID}").remove
$('#timsChatMessageTabMenu').wcfTabs 'refresh'
WCF.System.FlexibleMenu.rebuild $('#timsChatMessageTabMenu > .tabMenu').wcfIdentify()
if $('#privateChannelsMenu li').length <= 1
$('#privateChannelsMenu').removeClass 'shown'
if $('#timsChatMessageTabMenu > .tabMenu > ul > li').length <= 1
$('#timsChatMessageTabMenu').addClass 'singleTab'
openPrivateChannel 0
@ -968,7 +1093,7 @@ Create a message containing the uploaded attachment
unless parseInt(data.returnValues.attachments[internalFileID].isImage) is 0
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('.attachmentTinyThumbnail').wrap link

View File

@ -121,7 +121,7 @@ public function getFormattedMessage($type = 'text/html') {
*/
public function getUsername($colored = false) {
$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) {
$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 = \chat\data\room\RoomCache::getInstance()->getRoom($this->user->chatRoomID);
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
@ -50,7 +50,7 @@ public function __construct(\chat\system\command\CommandHandler $commandHandler)
if (!$typeSuspension->isVisible()) continue;
$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,
'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
* @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>
* @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 {
from {
border-color: @wcfContainerBorderColor;
@ -16,365 +47,398 @@
}
}
.__bubbleArrow {
border-color: transparent @wcfContainerBorderColor;
left: -6px;
top: 5px;
border-width: 6px 6px 6px 0;
border-style: solid;
content: "";
display: block;
position: absolute;
width: 0;
}
// only apply styles to Tims Chat
#tplChat {
#timsChatTopic {
padding: @wcfGapTiny;
.transition(height, .2s);
.transition(padding-top, .2s);
.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;
#content {
// styles related to the topic container
#timsChatTopic {
position: relative;
~ .timsChatMessageContainer {
margin-left: 35px;
border-top-left-radius: 0;
#timsChatTopicCloser {
position: absolute;
top: @wcfGapSmall;
right: @wcfGapSmall;
cursor: pointer;
&:hover {
color: @wcfLinkColor;
}
}
}
> 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;
#timsChatMessageTabMenu {
&.singleTab {
> nav.tabMenu {
// hide tab menu when single tabbed
// this is “a bit” hacky
display: none !important;
}
> .userAvatar {
&.large {
display: none;
}
&.small {
display: block;
}
// overwrite WCF margin overwrite on tab menu content with WCF marginTop like margin
// this is “a bit” hacky
margin-top: @wcfGapMedium !important;
> .tabMenuContent {
}
&.active {
> .userAvatar {
&.large {
display: block;
}
.timsChatMessageContainer {
&.notify {
-webkit-animation-duration: .2s;
-webkit-animation-name: timsChatNotify;
-webkit-animation-iteration-count: 5;
-webkit-animation-direction: alternate;
-webkit-animation-timing-function: linear;
&.small {
display: none;
}
-moz-animation-duration: .2s;
-moz-animation-name: timsChatNotify;
-moz-animation-iteration-count: 5;
-moz-animation-direction: alternate;
-moz-animation-timing-function: linear;
&.framed {
> img, > canvas, > .icon {
border-right-color: @wcfContentBackgroundColor;
border-radius: @wcfContainerBorderRadius 0 0 @wcfContainerBorderRadius;
-o-animation-duration: .2s;
-o-animation-name: timsChatNotify;
-o-animation-iteration-count: 5;
-o-animation-direction: alternate;
-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 {
li {
.clearfix;
border-style: solid;
border-width: 0 0 1px 0;
border-color: @wcfContainerBorderColor;
padding: 3px 0 4px;
&:last-child {
border-style: none;
padding: 3px 0 0 0;
}
> .icon, img {
// fix vertical alignment of images in tabs
vertical-align: middle;
margin-right: @wcfGapTiny;
}
// styles related to the close button of private channels in tabs
.jsChannelCloser {
&:hover {
color: @wcfLinkColor;
}
}
}
&.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 {
.__bubbleArrow;
}
&:after {
.__bubbleArrow;
border-color: transparent @wcfContainerBackgroundColor;
left: -5px;
top: 6px;
border-width: 5px 5px 5px 0;
time {
float: right;
}
}
&.right {
.avatarContainer {
float: right;
&.bubble {
> .timsChatAvatarContainer {
margin-left: 0px;
}
.innerMessage {
margin-right: 46px;
margin-left: 0px;
.timsChatInnerMessage {
position: relative;
&:before {
.__bubbleArrow;
left: auto;
right: -6px;
border-width: 6px 0 6px 6px;
padding: @wcfGapSmall;
border-radius: @wcfContainerBorderRadius;
border-style: solid;
border-width: 1px;
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 {
.__bubbleArrow;
border-color: transparent @wcfContainerBackgroundColor;
left: auto;
right: -5px;
top: 6px;
border-width: 5px 0 5px 5px;
left: -@wcfGapSmall + 1;
top: @wcfGapSmall + 1;
border-width: (@wcfGapSmall - 1) (@wcfGapSmall - 1) (@wcfGapSmall - 1) 0;
}
}
&.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 {
display: none;
position: absolute;
right: 0px;
top: 6px;
&:nth-child(even) {
> .timsChatInnerMessageContainer {
&.bubble {
.timsChatInnerMessage {
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 {
padding-top: 0px !important;
> div {
height: 400px;
overflow: auto !important;
> .chatTabMenuContainer {
padding: 14px 0 21px;
> fieldset{
padding-right: @wcfGapTiny;
> .chatSidebarMenu {
background: @wcfContentBackgroundColor;
margin: -14px 0 0;
border-radius: 0px;
> div {
overflow-y: auto;
> ul {
padding-right: @wcfGapSmall;
}
}
&#timsChatUserListContainer {
> div {
height: 250px;
}
}
&#timsChatRoomListContainer {
> div#timsChatRoomList {
height: 150px;
}
}
}
}
#sidebarContent {
fieldset {
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) {
#timsChatUserList {
> ul {
> li {
margin-top: @wcfGapSmall;
}
}
#timsChatUserList {
.timsChatUser {
> a {
background: @wcfContentBackgroundColor;
img {
margin-right: @wcfGapSmall;
&.you {
a {
&:hover {
text-decoration: none;
cursor: default;
}
}
}
&.away {
opacity: .5;
}
&.suspended a {
text-decoration: line-through;
a {
img {
margin-right: @wcfGapTiny;
}
}
}
}
@ -391,116 +455,53 @@
}
}
#timsChatRoomList {
#timsChatCopyrightDialog {
> div {
> div {
text-align: center;
}
background-repeat: no-repeat;
background-position: right top;
}
}
#smilies {
margin-top: @wcfGapMedium;
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;
}
#fish {
font-size: 2rem;
}
}
// TODO
html.fullscreen {
#top {
height: 0px;
html, body {
padding: 0;
margin: 0;
}
height: 100%;
overflow: hidden;
#content {
&,
body,
#tplChat #main,
#tplChat #main > div,
#tplChat #main > div > div,
#tplChat #content {
width: 100%;
height: 100%;
-moz-box-sizing: border-box;
-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;
}
max-width: 100%;
max-height: 100%;
}
#timsChatOptions {
margin-bottom: @wcfGapMedium;
#top,
#pageHeader,
#pageFooter,
#mainMenu,
#topMenu {
display: none;
}
#tplChat {
height: 100%;
overflow: hidden;
#pageHeader, #pageFooter {
display: none;
}
#main {
height: 100%;
margin: 0;
padding: 0;
max-width: 100%;
width: 100%;
> div, .sidebar, #sidebarContainer {
height: 100%;
}
}
.sidebar, #main, #content {
padding-bottom: 0;
}
#main, #content {
padding-top: 0;
border-top: none;
border-bottom: none;
border-radius: 0;
}
}

View File

@ -7,7 +7,6 @@
<item name="chat.acp.room.title"><![CDATA[Titel]]></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>
</category>
@ -101,6 +100,8 @@
<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.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.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>
</category>
<category name="chat.general">
<item name="chat.general.expires"><![CDATA[Ablaufzeitpunkt]]></item>
<item name="chat.general.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>
<category name="chat.global">
<item name="chat.global.expires"><![CDATA[Ablaufzeitpunkt]]></item>
<item name="chat.global.time"><![CDATA[Datum]]></item>
<item name="chat.general.room"><![CDATA[Chatraum]]></item>
<item name="chat.general.rooms"><![CDATA[Chaträume]]></item>
<item name="chat.general.users"><![CDATA[Nutzer]]></item>
<item name="chat.global.title"><![CDATA[{lang}chat.header.menu.chat{/lang}]]></item>
<item name="chat.global.protocol"><![CDATA[Protokoll]]></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.general.copyright.leader"><![CDATA[Projektleiter]]></item>
<item name="chat.general.copyright.developer"><![CDATA[Entwickler]]></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.global.room"><![CDATA[Chatraum]]></item>
<item name="chat.global.rooms"><![CDATA[Chaträume]]></item>
<item name="chat.global.users"><![CDATA[Nutzer]]></item>
<item name="chat.general.submit.default"><![CDATA[Zum Senden Enter drücken]]></item>
<item name="chat.general.scroll"><![CDATA[Scrollen]]></item>
<item name="chat.general.notify"><![CDATA[Benachrichtigen]]></item>
<item name="chat.general.notify.title"><![CDATA[Neue Nachrichten]]></item>
<item name="chat.general.smilies"><![CDATA[Smilies]]></item>
<item name="chat.general.clear"><![CDATA[Chat leeren]]></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.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.global.copyright.leader"><![CDATA[Projektleiter]]></item>
<item name="chat.global.copyright.developer"><![CDATA[Entwickler]]></item>
<item name="chat.global.copyright.graphics"><![CDATA[Grafisches]]></item>
<item name="chat.global.copyright.translation"><![CDATA[Übersetzung]]></item>
<item name="chat.global.copyright.thanks"><![CDATA[Weiteren Dank an]]></item>
<item name="chat.general.query"><![CDATA[Privates Gespräch]]></item>
<item name="chat.general.kick"><![CDATA[Kicken]]></item>
<item name="chat.general.ban"><![CDATA[Bannen]]></item>
<item name="chat.general.profile"><![CDATA[Profil]]></item>
<item name="chat.global.submit.default"><![CDATA[Zum Senden Enter drücken]]></item>
<item name="chat.global.scroll"><![CDATA[Scrollen]]></item>
<item name="chat.global.notify"><![CDATA[Benachrichtigen]]></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.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.global.whisper"><![CDATA[Flüstern]]></item>
<item name="chat.global.query"><![CDATA[Privates Gespräch]]></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.general.closePrivateChannel"><![CDATA[Privaten Kanal schließen]]></item>
<item name="chat.general.closeTopic"><![CDATA[Thema ausblenden]]></item>
<item name="chat.global.message"><![CDATA[Nachricht]]></item>
<item name="chat.global.whispers"><![CDATA[Flüstert]]></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 name="chat.header">
@ -211,7 +216,7 @@ Probieren Sie, den Chat neu zu laden<!-- , bei Risiken und Nebenwirkungen fragen
<category name="chat.suspension">
<item name="chat.suspension.mute"><![CDATA[Knebel]]></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>
</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 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>
<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>
<license><![CDATA[Creative Commons Attribution-NonCommercial-ShareAlike <http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode>]]></license>
</packageinformation>

View File

@ -1,47 +1,47 @@
{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'}
<div style="background-image: url('data:image/png;base64,{$background}');">
<dl>
<dt>{lang}chat.general.copyright.leader{/lang}</dt>
<dt>{lang}chat.global.copyright.leader{/lang}</dt>
<dd>
<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>
</dd>
</dl>
<dl>
<dt>{lang}chat.general.copyright.developer{/lang}</dt>
<dt>{lang}chat.global.copyright.developer{/lang}</dt>
<dd>
<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="https://github.com/max-m" class="externalURL" {if EXTERNAL_LINK_TARGET_BLANK}target="_blank"{/if}>Maximilian Mader</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>
</ul>
</dd>
</dl>
{*<dl>
<dt>{lang}chat.general.copyright.graphics{/lang}</dt>
<dt>{lang}chat.global.copyright.graphics{/lang}</dt>
<dd>
</dd>
</dl>
<dl>
<dt>{lang}chat.general.copyright.translation{/lang}</dt>
<dt>{lang}chat.global.copyright.translation{/lang}</dt>
<dd>
</dd>
</dl>*}
<dl>
<dt>{lang}chat.general.copyright.thanks{/lang}</dt>
<dt>{lang}chat.global.copyright.thanks{/lang}</dt>
<dd>
<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="https://github.com/Gabbid" class="externalURL" {if EXTERNAL_LINK_TARGET_BLANK}target="_blank"{/if}>Gabi</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>Gabi</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://kittblog.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.cls-design.com/" class="externalURL" {if EXTERNAL_LINK_TARGET_BLANK}target="_blank"{/if}>Tom</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="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.cls-design.com/" class="externalURL"{if EXTERNAL_LINK_TARGET_BLANK} target="_blank"{/if}>Tom</a></li>
</ul>
</dd>
</dl>

View File

@ -1,55 +1,60 @@
{include file='documentHeader'}
<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}
{include file='headInclude' sandbox=false}
{include file='javascriptInclude' application='chat'}
<script data-relocate="true">
//<![CDATA[
(function ($, window) {
$(function(){
WCF.Language.addObject({
'chat.general.query': '{lang}chat.general.query{/lang}',
'chat.general.kick': '{lang}chat.general.kick{/lang}',
'chat.general.ban': '{lang}chat.general.ban{/lang}',
'chat.general.profile': '{lang}chat.general.profile{/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': '{@"chat.error.onMessageLoad"|language|encodeJS}',
'chat.global.ban': '{lang}chat.global.ban{/lang}',
'chat.global.closePrivateChannel': '{lang}chat.global.closePrivateChannel{/lang}',
'chat.global.closeTopic': '{lang}chat.global.closeTopic{/lang}',
'chat.global.notify.title': '{lang}chat.global.notify.title{/lang}',
'chat.global.privateChannelTopic': '{lang}chat.global.privateChannelTopic{/lang}',
'chat.global.profile': '{lang}chat.global.profile{/lang}',
'chat.global.query': '{lang}chat.global.query{/lang}',
'chat.global.whisper': '{lang}chat.global.whisper{/lang}',
'chat.error.duplicateTab': '{lang}chat.error.duplicateTab{/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.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.tooLarge': '{lang}wcf.attachment.upload.error.tooLarge{/lang}',
'wcf.attachment.upload.error.reachedLimit': '{lang}wcf.attachment.upload.error.reachedLimit{/lang}',
'wcf.attachment.upload.error.reachedRemainingLimit': '{lang}wcf.attachment.upload.error.reachedRemainingLimit{/lang}',
'wcf.attachment.upload.error.uploadFailed': '{lang}wcf.attachment.upload.error.uploadFailed{/lang}',
'wcf.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}'
'wcf.global.button.upload': '{lang}wcf.global.button.upload{/lang}'
});
// Boot the chat
{if MODULE_SMILEY}WCF.TabMenu.init();{/if}
{if MODULE_ATTACHMENT && $__wcf->session->getPermission('user.chat.canUploadAttachment')}
new be.bastelstu.Chat.Attachment();
new be.bastelstu.Chat.Action.Delete('wcf\\data\\attachment\\AttachmentAction', '#timsChatUploadDropdownMenu > li');
{/if}
new WCF.Message.Smilies();
WCF.TabMenu.init();
{if MODULE_SMILEY}
new WCF.Message.Smilies();
{/if}
{capture assign='messageTemplate'}{include application='chat' file='message'}{/capture}
{capture assign='userTemplate'}{include application='chat' file='userListUser'}{/capture}
{capture assign='userMenuTemplate'}{include application='chat' file='userListUserMenu'}{/capture}
var config = {
reloadTime: {@CHAT_RELOADTIME},
messageURL: '{link application="chat" controller="NewMessages"}{/link}',
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'}
@ -57,14 +62,15 @@
be.bastelstu.Chat.init(
{$roomID},
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('{@$userTemplate|encodeJS}')
new WCF.Template('{@$userTemplate|encodeJS}'),
new WCF.Template('{@$userMenuTemplate|encodeJS}')
);
{event name='afterInit'}
$('#timsChatCopyright').click(function (event) {
$('#timsChatCopyright a').click(function (event) {
event.preventDefault();
if (!$.wcfIsset('timsChatCopyrightDialog')) $('<div id="timsChatCopyrightDialog"></div>').appendTo('body');
$('#timsChatCopyrightDialog').load('{link application="chat" controller="Copyright"}{/link}').wcfDialog({
@ -83,78 +89,118 @@
{capture assign='sidebar'}{include application='chat' file='sidebar'}{/capture}
{include file='header' sandbox=false sidebarOrientation='right'}
<div id="timsChatTopic" class="marginTop container{if $room->topic|language === ''} empty{/if}">
<span class="icon icon16 icon-remove jsTopicCloser jsTooltip" title="{lang}chat.general.closeTopic{/lang}"></span>
<span class="topic">{$room->topic|language}</span>
</div>
<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>
<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>
<div class="clearfix">
<div id="timsChatTopic" class="container containerPadding marginTop{if $room->topic|language === ''} empty{/if}">
<span id="timsChatTopicCloser" class="icon icon16 icon-remove jsTooltip" title="{lang}chat.global.closeTopic{/lang}"></span>
<span class="topic">{$room->topic|language}</span>
</div>
<div id="timsChatMessageTabMenu" class="tabMenuContainer singleTab" data-active="timsChatMessageContainer0">
<nav class="tabMenu">
<ul>
<li>
<a id="timsChatMessageTabMenuAnchor0" href="{$__wcf->getAnchor('timsChatMessageContainer0')}" class="timsChatMessageTabMenuAnchor" data-user-id="0">
<span class="icon icon16 icon-warning-sign notifyIcon"></span>{*
*}<span class="userAvatar framed">
<span class="icon icon16 icon-group"></span>
</span>{*
*}<span>{$room}</span>
</a>
</li>
</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>
</ul>
</nav>
<nav class="jsMobileNavigation buttonGroupNavigation">
<ul class="buttonGroup">
<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}
{include file='header' sandbox=false}
<header class="boxHeadline">

View File

@ -1,12 +1,12 @@
{literal}
{if $message.type == $messageTypes.LEAVE || $message.type == $messageTypes.JOIN}
<div class="messageIcon">
<span class="icon icon16 icon-{if $message.type == $messageTypes.LEAVE}signout{elseif $message.type == $messageTypes.JOIN}signin{/if}"></span>
{if $message.type == $messageTypes.JOIN || $message.type == $messageTypes.LEAVE}
<div class="timsChatMessageIcon">
<span class="icon icon16 icon-{if $message.type == $messageTypes.JOIN}signin{else}signout{/if}"></span>
</div>
{/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="avatarContainer">
<div class="userAvatar{if $message.type != $messageTypes.INFORMATION} framed{/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="timsChatAvatarContainer">
<div class="userAvatar framed">
{if $message.type != $messageTypes.INFORMATION}
{if $message.type == $messageTypes.NORMAL || $message.type == $messageTypes.WHISPER || $message.type == $messageTypes.ATTACHMENT}
{@$message.avatar[32]}
@ -18,46 +18,38 @@
{/if}
</div>
{if $message.type == $messageTypes.ATTACHMENT}
<small class="framed avatarExtra">
<small class="framed timsChatAvatarExtraIcon">
<span class="icon icon16 icon-paperclip"></span>
</small>
{/if}
</div>
<div class="innerMessage">
<span class="username">
{if ($message.type == $messageTypes.WHISPER && $message.sender == WCF.User.userID) || $message.type != $messageTypes.WHISPER}
<div class="timsChatInnerMessage">
<span class="timsChatUsernameContainer">
{@$message.formattedUsername}
{else}
{$message.additionalData.receiverUsername}
{/if}
{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>
{if ($message.type == $messageTypes.WHISPER && $message.sender == WCF.User.userID) || $message.type != $messageTypes.WHISPER}
{$message.additionalData.receiverUsername}
{else}
{@$message.formattedUsername}
{if $message.type == $messageTypes.WHISPER}
<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>
<span class="reciever">{$message.additionalData.receiverUsername}</span>
{/if}
{/if}
</span>
<time>{@$message.formattedTime}</time>
{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}
<ul class="text">
<ul class="timsChatText">
<li>
{if $message.isFollowUp} <time>{@$message.formattedTime}</time>{/if}
{@$message.formattedMessage}
</li>
</ul>
{elseif $message.type == $messageTypes.INFORMATION}
<div class="text">{@$message.formattedMessage}</div>
<div class="timsChatText">{@$message.formattedMessage}</div>
{else}
<span class="text">{@$message.formattedMessage}</span>
<span class="timsChatText">{@$message.formattedMessage}</span>
{/if}
</div>
<span class="markContainer">
<span class="timsChatMarkContainer">
<input type="checkbox" value="{@$message.messageID}" />
</span>
</div>

View File

@ -1,29 +1,19 @@
<div class="tabMenuContainer chatTabMenuContainer containerPadding">
<nav class="menu chatSidebarMenu">
<ul>
<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>
<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>
<fieldset id="timsChatUserListContainer">
<legend>{lang}chat.global.users{/lang}</legend>
<div id="timsChatUserList">
<ul class="sidebarNestedCategoryList">
</ul>
</nav>
<section id="sidebarContent" class="tabMenuContent">
<fieldset>
<nav id="timsChatUserList">
<ul>
</ul>
</nav>
</fieldset>
<fieldset>
<nav id="timsChatRoomList" style="display: none;">
<div>
<ul>
</ul>
<div class="marginTop">
<button type="button">{lang}chat.general.forceRefresh{/lang}</button>
</div>
</div>
</nav>
</fieldset>
</section>
</div>
</div>
</fieldset>
<fieldset id="timsChatRoomListContainer">
<legend>{lang}chat.global.rooms{/lang}</legend>
<div id="timsChatRoomList">
<ul class="sidebarNestedCategoryList">
</ul>
</div>
<div class="marginTop">
<a id="timsChatRoomListReloadButton" class="button small jsOnly">{lang}chat.global.forceRefresh{/lang}</a>
</div>
</fieldset>

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}