Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
converse.js
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
converse.js
Commits
24d58a5b
Commit
24d58a5b
authored
Jun 04, 2014
by
JC Brand
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'consolidation'
parents
a29a0293
e2d494f0
Changes
25
Show whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
645 additions
and
636 deletions
+645
-636
activate
activate
+63
-0
bower.json
bower.json
+5
-4
converse.js
converse.js
+272
-120
converse.min.css
converse.min.css
+0
-12
css/converse.css
css/converse.css
+15
-18
docs/CHANGES.rst
docs/CHANGES.rst
+1
-0
docs/source/index.rst
docs/source/index.rst
+0
-7
index.html
index.html
+5
-9
less/converse.less
less/converse.less
+16
-20
main.js
main.js
+1
-0
mockup/index.html
mockup/index.html
+51
-12
mockup/minimized.html
mockup/minimized.html
+0
-274
spec/chatbox.js
spec/chatbox.js
+100
-42
spec/chatroom.js
spec/chatroom.js
+23
-22
spec/controlbox.js
spec/controlbox.js
+0
-7
src/deps-full.js
src/deps-full.js
+1
-0
src/deps-no-otr.js
src/deps-no-otr.js
+1
-0
src/templates.js
src/templates.js
+65
-61
src/templates/chatbox.html
src/templates/chatbox.html
+4
-9
src/templates/chatroom.html
src/templates/chatroom.html
+5
-10
src/templates/trimmed_chat.html
src/templates/trimmed_chat.html
+7
-0
src/templates/trimmed_chats.html
src/templates/trimmed_chats.html
+1
-0
tests.html
tests.html
+4
-3
tests/main.js
tests/main.js
+1
-1
tests/utils.js
tests/utils.js
+4
-5
No files found.
activate
0 → 100755
View file @
24d58a5b
# This file must be used with "source bin/activate" *from bash*
# you cannot run it directly
deactivate () {
# reset old environment variables
if [ -n "$_OLD_VIRTUAL_PATH" ] ; then
PATH="$_OLD_VIRTUAL_PATH"
export PATH
unset _OLD_VIRTUAL_PATH
fi
# This should detect bash and zsh, which have a hash command that must
# be called to get it to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then
hash -r
fi
if [ -n "$_OLD_VIRTUAL_PS1" ] ; then
PS1="$_OLD_VIRTUAL_PS1"
export PS1
unset _OLD_VIRTUAL_PS1
fi
unset VIRTUAL_ENV
if [ ! "$1" = "nondestructive" ] ; then
# Self destruct!
unset -f deactivate
fi
}
# unset irrelavent variables
deactivate nondestructive
VIRTUAL_ENV="/home/jc/dev/converse.js"
export VIRTUAL_ENV
_OLD_VIRTUAL_PATH="$PATH"
PATH="$VIRTUAL_ENV/node_modules/.bin:$PATH"
export PATH
if [ -z "$VIRTUAL_ENV_DISABLE_PROMPT" ] ; then
_OLD_VIRTUAL_PS1="$PS1"
if [ "x" != x ] ; then
PS1="$PS1"
else
if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then
# special case for Aspen magic directories
# see http://www.zetadev.com/software/aspen/
PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1"
else
PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1"
fi
fi
export PS1
fi
# This should detect bash and zsh, which have a hash command that must
# be called to get it to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then
hash -r
fi
bower.json
View file @
24d58a5b
...
...
@@ -26,7 +26,8 @@
"requirejs-text"
:
"~2.0.12"
,
"requirejs-tpl-jcbrand"
:
"*"
,
"momentjs"
:
"~2.6.0"
,
"jquery.browser"
:
"~0.0.6"
"jquery.browser"
:
"~0.0.6"
,
"backbone.overview"
:
"*"
},
"exportsOverride"
:
{}
}
converse.js
View file @
24d58a5b
...
...
@@ -3,7 +3,7 @@
* http://conversejs.org
*
* Copyright (c) 2012, Jan-Carel Brand <jc@opkode.com>
*
Dual licensed under the MIT and GPL Licenses
*
Licensed under the Mozilla Public License (MPL)
*/
// AMD/global registrations
...
...
@@ -158,6 +158,7 @@
this
.
forward_messages
=
false
;
this
.
hide_muc_server
=
false
;
this
.
i18n
=
locales
.
en
;
this
.
no_trimming
=
false
;
// Set to true for phantomjs tests (where browser apparently has no width)
this
.
prebind
=
false
;
this
.
show_controlbox_by_default
=
false
;
this
.
show_only_online_users
=
false
;
...
...
@@ -195,6 +196,7 @@
'
fullname
'
,
'
hide_muc_server
'
,
'
i18n
'
,
'
no_trimming
'
,
'
jid
'
,
'
prebind
'
,
'
rid
'
,
...
...
@@ -863,8 +865,8 @@
is_chatroom
:
false
,
// This is not a multi-user chatroom
events
:
{
'
click .close-chatbox-button
'
:
'
close
Chat
'
,
'
click .toggle-chatbox-button
'
:
'
toggleChatBox
'
,
'
click .close-chatbox-button
'
:
'
close
'
,
'
click .toggle-chatbox-button
'
:
'
minimize
'
,
'
keypress textarea.chat-textarea
'
:
'
keyPressed
'
,
'
click .toggle-smiley
'
:
'
toggleEmoticonMenu
'
,
'
click .toggle-smiley ul li
'
:
'
insertEmoticon
'
,
...
...
@@ -892,13 +894,16 @@
this
.
model
.
on
(
'
showReceivedOTRMessage
'
,
function
(
text
)
{
this
.
showMessage
({
'
message
'
:
text
,
'
sender
'
:
'
them
'
});
},
this
);
this
.
updateVCard
();
this
.
$el
.
insertAfter
(
converse
.
chatboxviews
.
get
(
"
controlbox
"
).
$el
);
this
.
render
().
show
().
focus
().
model
.
messages
.
fetch
({
add
:
true
});
if
(
this
.
model
.
get
(
'
status
'
))
{
this
.
showStatusMessage
(
this
.
model
.
get
(
'
status
'
));
this
.
model
.
messages
.
fetch
({
add
:
true
});
this
.
render
();
if
(
this
.
model
.
get
(
'
minimized
'
))
{
this
.
hide
();
}
else
{
this
.
show
();
}
this
.
initDragResize
();
if
((
_
.
contains
([
UNVERIFIED
,
VERIFIED
],
this
.
model
.
get
(
'
otr_status
'
)))
||
converse
.
use_otr_by_default
)
{
this
.
model
.
initiateOTR
();
}
...
...
@@ -919,7 +924,7 @@
setTimeout
(
function
()
{
converse
.
refreshWebkit
();
},
50
);
return
this
;
return
this
.
showStatusMessage
()
;
},
initDragResize
:
function
()
{
...
...
@@ -937,17 +942,6 @@
this
.
scrollDown
();
},
updateUnreadMessagesCounter
:
function
()
{
/* If the chatbox is minimized, we show a counter with the
* number of unread messages.
*/
var
$count
=
this
.
$el
.
find
(
'
.chat-head-message-count
'
);
var
count
=
parseInt
(
$count
.
data
(
'
count
'
)
||
0
,
10
)
+
1
;
$count
.
html
(
count
).
data
(
'
count
'
,
count
);
if
(
!
$count
.
is
(
'
:visible
'
))
{
$count
.
show
(
'
fast
'
);
}
return
this
;
},
clearChatRoomMessages
:
function
(
ev
)
{
ev
.
stopPropagation
();
var
result
=
confirm
(
__
(
"
Are you sure you want to clear the messages from this room?
"
));
...
...
@@ -982,9 +976,6 @@
'
extra_classes
'
:
msg_dict
.
delayed
&&
'
delayed
'
||
''
});
$content
.
append
(
$
(
message
).
children
(
'
.chat-message-content
'
).
first
().
text
(
text
).
addHyperlinks
().
addEmoticons
().
parent
());
if
(
this
.
model
.
get
(
'
minimized
'
)
&&
(
!
msg_time
.
isBefore
(
this
.
model
.
get
(
'
time_minimized
'
))))
{
this
.
updateUnreadMessagesCounter
();
}
this
.
scrollDown
();
},
...
...
@@ -1276,7 +1267,7 @@
converse
.
emit
(
'
onBuddyStatusChanged
'
,
item
.
attributes
,
item
.
get
(
'
chat_status
'
));
}
if
(
_
.
has
(
item
.
changed
,
'
status
'
))
{
this
.
showStatusMessage
(
item
.
get
(
'
status
'
)
);
this
.
showStatusMessage
();
converse
.
emit
(
'
onBuddyStatusMessageChanged
'
,
item
.
attributes
,
item
.
get
(
'
status
'
));
}
if
(
_
.
has
(
item
.
changed
,
'
image
'
))
{
...
...
@@ -1285,61 +1276,53 @@
if
(
_
.
has
(
item
.
changed
,
'
otr_status
'
))
{
this
.
renderToolbar
().
informOTRChange
();
}
if
(
_
.
has
(
item
.
changed
,
'
minimized
'
))
{
if
(
item
.
get
(
'
minimized
'
))
{
this
.
hide
();
}
else
{
this
.
maximize
();
}
}
// TODO check for changed fullname as well
},
showStatusMessage
:
function
(
msg
)
{
msg
=
msg
||
this
.
model
.
get
(
'
status
'
);
if
(
msg
)
{
this
.
$el
.
find
(
'
p.user-custom-message
'
).
text
(
msg
).
attr
(
'
title
'
,
msg
);
}
return
this
;
},
close
Chat
:
function
()
{
close
:
function
()
{
if
(
converse
.
connection
)
{
this
.
model
.
destroy
();
}
else
{
this
.
model
.
trigger
(
'
hide
'
);
}
converse
.
emit
(
'
onChatBoxClosed
'
,
this
);
return
this
;
},
trimChat
:
function
()
{
// TODO: Instead of closing the chat, we should add it to
// div#offscreen-chatboxes
this
.
$el
.
hide
();
// Hide it immediately to avoid flashes on the screen
this
.
closeChat
();
maximize
:
function
()
{
/* Restores a minimized chat box
*/
this
.
$el
.
insertAfter
(
converse
.
chatboxviews
.
get
(
"
controlbox
"
).
$el
).
show
();
this
.
focus
();
converse
.
refreshWebkit
();
converse
.
emit
(
'
onChatBoxMaximized
'
,
this
);
this
.
model
.
trigger
(
'
maximized
'
,
this
.
model
);
},
saveToggleState
:
function
()
{
var
flyout
=
this
.
$el
.
find
(
'
.box-flyout
'
);
if
(
flyout
.
hasClass
(
'
minimized
'
))
{
flyout
.
removeClass
(
'
minimized
'
);
this
.
model
.
save
({
'
minimized
'
:
false
});
}
else
{
flyout
.
addClass
(
'
minimized
'
);
minimize
:
function
(
ev
)
{
/* Minimizes a chat box
*/
this
.
model
.
save
({
'
minimized
'
:
true
,
'
time_minimized
'
:
moment
().
format
()
});
}
return
this
;
},
toggleChatBox
:
function
(
ev
)
{
var
$target
=
$
(
ev
.
target
),
$count
;
this
.
saveToggleState
();
this
.
$el
.
children
(
'
.box-flyout
'
).
attr
(
'
style
'
,
''
);
this
.
$el
.
find
(
'
div.chat-body
'
).
slideToggle
(
'
fast
'
);
if
(
$target
.
hasClass
(
'
icon-minus
'
))
{
$target
.
removeClass
(
'
icon-minus
'
).
addClass
(
'
icon-plus
'
);
}
else
{
$target
.
removeClass
(
'
icon-plus
'
).
addClass
(
'
icon-minus
'
);
$count
=
this
.
$el
.
find
(
'
.chat-head-message-count
'
);
$count
.
html
(
0
).
data
(
'
count
'
,
0
);
if
(
$count
.
is
(
'
:visible
'
))
{
$count
.
hide
(
'
fast
'
);
}
}
// Toggle drag resize ability
this
.
$el
.
find
(
'
.dragresize-tm
'
).
toggle
();
this
.
setChatBoxHeight
(
this
.
height
);
converse
.
emit
(
'
onChatBoxToggled
'
,
this
);
this
.
$el
.
hide
(
'
fast
'
,
converse
.
refreshwebkit
);
converse
.
emit
(
'
onChatBoxMinimized
'
,
this
);
},
updateVCard
:
function
()
{
...
...
@@ -1445,8 +1428,8 @@
hide
:
function
()
{
if
(
this
.
$el
.
is
(
'
:visible
'
)
&&
this
.
$el
.
css
(
'
opacity
'
)
==
"
1
"
)
{
this
.
$el
.
fadeOut
(
'
fast
'
,
converse
.
refreshWebkit
);
converse
.
emit
(
'
onChatBoxClosed
'
,
this
);
this
.
$el
.
hide
(
);
converse
.
refreshWebkit
(
);
}
return
this
;
},
...
...
@@ -1460,13 +1443,16 @@
// Without a connection, we haven't yet initialized
// localstorage
this
.
model
.
save
();
this
.
initDragResize
();
}
return
this
;
},
scrollDown
:
function
()
{
var
$content
=
this
.
$el
.
find
(
'
.chat-content
'
);
var
$content
=
this
.
$
(
'
.chat-content
'
);
if
(
$content
.
is
(
'
:visible
'
))
{
$content
.
scrollTop
(
$content
[
0
].
scrollHeight
);
}
return
this
;
}
});
...
...
@@ -1767,7 +1753,7 @@
}
}
if
(
!
nick
)
{
return
;
}
chatroom
=
converse
.
chatboxviews
.
showChat
Box
({
chatroom
=
converse
.
chatboxviews
.
showChat
({
'
id
'
:
jid
,
'
jid
'
:
jid
,
'
name
'
:
Strophe
.
unescapeNode
(
Strophe
.
getNodeFromJid
(
jid
)),
...
...
@@ -1786,7 +1772,7 @@
className
:
'
chatbox
'
,
id
:
'
controlbox
'
,
events
:
{
'
click a.close-chatbox-button
'
:
'
close
Chat
'
,
'
click a.close-chatbox-button
'
:
'
close
'
,
'
click ul#controlbox-tabs li a
'
:
'
switchTab
'
,
'
mousedown .dragresize-tm
'
:
'
onDragResizeStart
'
},
...
...
@@ -1890,8 +1876,8 @@
tagName
:
'
div
'
,
className
:
'
chatroom
'
,
events
:
{
'
click .close-chatbox-button
'
:
'
close
Chat
'
,
'
click .toggle-chatbox-button
'
:
'
toggleChatBox
'
,
'
click .close-chatbox-button
'
:
'
close
'
,
'
click .toggle-chatbox-button
'
:
'
minimize
'
,
'
click .configure-chatroom-button
'
:
'
configureChatRoom
'
,
'
click .toggle-smiley
'
:
'
toggleEmoticonMenu
'
,
'
click .toggle-smiley ul li
'
:
'
insertEmoticon
'
,
...
...
@@ -1904,6 +1890,13 @@
initialize
:
function
()
{
this
.
connect
(
null
);
this
.
model
.
messages
.
on
(
'
add
'
,
this
.
onMessageAdded
,
this
);
this
.
model
.
on
(
'
change:minimized
'
,
function
(
item
)
{
if
(
item
.
get
(
'
minimized
'
))
{
this
.
hide
();
}
else
{
this
.
maximize
();
}
},
this
);
this
.
model
.
on
(
'
destroy
'
,
function
(
model
,
response
,
options
)
{
this
.
hide
();
converse
.
connection
.
muc
.
leave
(
...
...
@@ -1913,9 +1906,13 @@
undefined
);
},
this
);
this
.
$el
.
appendTo
(
converse
.
chatboxviews
.
$el
);
this
.
render
().
show
().
model
.
messages
.
fetch
({
add
:
true
});
this
.
initDragResize
();
this
.
$el
.
insertAfter
(
converse
.
chatboxviews
.
get
(
"
controlbox
"
).
$el
);
this
.
render
().
model
.
messages
.
fetch
({
add
:
true
});
if
(
this
.
model
.
get
(
'
minimized
'
))
{
this
.
hide
();
}
else
{
this
.
show
();
}
},
render
:
function
()
{
...
...
@@ -2387,7 +2384,7 @@
this
.
ChatBoxes
=
Backbone
.
Collection
.
extend
({
model
:
converse
.
ChatBox
,
comparator
:
'
time_opened
'
,
comparator
:
'
time_opened
'
,
registerMessageHandler
:
function
()
{
converse
.
connection
.
addHandler
(
...
...
@@ -2478,43 +2475,67 @@
}
});
this
.
ChatBoxViews
=
Backbone
.
View
.
extend
({
el
:
'
#conversejs
'
,
this
.
ChatBoxViews
=
Backbone
.
Overview
.
extend
({
initialize
:
function
()
{
var
views
=
{};
this
.
get
=
function
(
id
)
{
return
views
[
id
];
};
this
.
set
=
function
(
id
,
view
)
{
views
[
id
]
=
view
;
};
this
.
getAll
=
function
()
{
return
views
;
};
this
.
trimmed_chatboxes_view
=
new
converse
.
MinimizedChatBoxesView
({
model
:
this
.
model
});
this
.
render
();
this
.
model
.
on
(
"
add
"
,
this
.
onChatAdded
,
this
);
this
.
model
.
on
(
"
maximized
"
,
function
(
item
)
{
this
.
trimChats
(
this
.
get
(
item
.
get
(
'
id
'
)));
},
this
);
},
this
.
model
.
on
(
"
add
"
,
function
(
item
)
{
render
:
function
()
{
this
.
$el
.
html
(
this
.
trimmed_chatboxes_view
.
render
());
},
_ensureElement
:
function
()
{
/* Override method from backbone.js
* If the #conversejs element doesn't exist, create it.
*/
if
(
!
this
.
el
)
{
var
$el
=
$
(
'
#conversejs
'
);
if
(
!
$el
.
length
)
{
$el
=
$
(
'
<div id="conversejs">
'
);
$
(
'
body
'
).
append
(
$el
);
}
this
.
setElement
(
$el
,
false
);
}
else
{
this
.
setElement
(
_
.
result
(
this
,
'
el
'
),
false
);
}
},
onChatAdded
:
function
(
item
)
{
var
view
=
this
.
get
(
item
.
get
(
'
id
'
));
if
(
!
view
)
{
if
(
item
.
get
(
'
chatroom
'
))
{
view
=
new
converse
.
ChatRoomView
({
'
model
'
:
item
});
}
else
if
(
item
.
get
(
'
box_id
'
)
===
'
controlbox
'
)
{
view
=
new
converse
.
ControlBoxView
({
model
:
item
});
view
.
render
();
view
=
new
converse
.
ControlBoxView
({
model
:
item
}).
render
();
}
else
{
view
=
new
converse
.
ChatBoxView
({
model
:
item
});
}
this
.
set
(
item
.
get
(
'
id
'
),
view
);
this
.
add
(
item
.
get
(
'
id
'
),
view
);
}
else
{
delete
view
.
model
;
// Remove ref to old model to help garbage collection
view
.
model
=
item
;
view
.
initialize
();
}
this
.
trimOpenChats
(
view
);
},
this
);
this
.
trimChats
(
view
);
},
trim
Open
Chats
:
function
(
view
)
{
trimChats
:
function
(
view
)
{
/* This method is called before a new chat box will be opened.
*
* Check whether there is enough space in the page to show
* another chat box. Otherwise, close the oldest chat box.
*/
if
(
converse
.
no_trimming
)
{
return
;
}
var
toggle_width
=
0
,
trimmed_chats_width
,
boxes_width
=
view
.
$el
.
outerWidth
(
true
),
controlbox
=
this
.
get
(
'
controlbox
'
);
if
(
!
controlbox
||
!
controlbox
.
$el
.
is
(
'
:visible
'
))
{
...
...
@@ -2529,16 +2550,31 @@
if
(
this
.
model
.
length
<=
1
)
{
return
;
}
if
((
boxes_width
+
toggle_width
)
>
this
.
$el
.
width
())
{
// trim oldest view (which is not controlbox)
this
.
get
(
this
.
model
.
at
(
1
).
get
(
'
id
'
)).
trimChat
();
trimmed_chats_width
=
this
.
trimmed_chatboxes_view
.
$
(
'
.box-flyout
'
).
outerWidth
(
true
)
||
0
;
if
((
trimmed_chats_width
+
boxes_width
+
toggle_width
)
>
this
.
$el
.
width
())
{
this
.
getOldestMaximizedChat
().
set
(
'
minimized
'
,
true
);
}
},
getOldestMaximizedChat
:
function
()
{
// Get oldest view (which is not controlbox)
var
i
=
0
;
var
model
=
this
.
model
.
sort
().
at
(
i
);
while
(
model
.
get
(
'
id
'
)
===
'
controlbox
'
||
model
.
get
(
'
minimized
'
)
===
true
)
{
i
++
;
model
=
this
.
model
.
at
(
i
);
}
return
model
;
},
showChat
Box
:
function
(
attrs
)
{
showChat
:
function
(
attrs
)
{
var
chatbox
=
this
.
model
.
get
(
attrs
.
jid
);
if
(
chatbox
)
{
if
(
chatbox
.
get
(
'
minimized
'
))
{
chatbox
.
set
({
'
minimized
'
:
false
});
}
else
{
chatbox
.
trigger
(
'
show
'
);
}
}
else
{
chatbox
=
this
.
model
.
create
(
attrs
,
{
'
error
'
:
function
(
model
,
response
)
{
...
...
@@ -2550,6 +2586,126 @@
}
});
this
.
MinimizedChatBoxView
=
Backbone
.
View
.
extend
({
tagName
:
'
div
'
,
className
:
'
chat-head
'
,
events
:
{
'
click .close-chatbox-button
'
:
'
close
'
,
'
click .restore-chat
'
:
'
restore
'
},
initialize
:
function
()
{
this
.
model
.
messages
.
on
(
'
add
'
,
function
(
msg
)
{
this
.
updateUnreadMessagesCounter
(
_
.
clone
(
msg
.
attributes
));
},
this
);
this
.
model
.
on
(
'
showSentOTRMessage
'
,
this
.
updateUnreadMessagesCounter
,
this
);
this
.
model
.
on
(
'
showReceivedOTRMessage
'
,
this
.
updateUnreadMessagesCounter
,
this
);
this
.
model
.
on
(
'
change:minimized
'
,
this
.
clearUnreadMessagesCounter
,
this
);
},
render
:
function
()
{
var
data
=
this
.
model
.
toJSON
();
if
(
this
.
model
.
get
(
'
chatroom
'
))
{
data
.
title
=
this
.
model
.
get
(
'
name
'
);
this
.
$el
.
addClass
(
'
chat-head-chatroom
'
);
}
else
{
data
.
title
=
this
.
model
.
get
(
'
fullname
'
);
this
.
$el
.
addClass
(
'
chat-head-chatbox
'
);
}
return
this
.
$el
.
html
(
converse
.
templates
.
trimmed_chat
(
data
));
},
clearUnreadMessagesCounter
:
function
()
{
if
(
!
this
.
model
.
get
(
'
minimized
'
))
{
this
.
$el
.
find
(
'
.chat-head-message-count
'
).
html
(
0
).
data
(
'
count
'
,
0
).
hide
();
}
},
updateUnreadMessagesCounter
:
function
(
msg_dict
)
{
var
count
,
$count
;
var
msg_time
=
(
typeof
msg_dict
===
'
object
'
&&
moment
(
msg_dict
.
time
))
||
moment
;
if
(
this
.
model
.
get
(
'
minimized
'
)
&&
(
!
msg_time
.
isBefore
(
this
.
model
.
get
(
'
time_minimized
'
))))
{
$count
=
this
.
$el
.
find
(
'
.chat-head-message-count
'
);
count
=
parseInt
(
$count
.
data
(
'
count
'
)
||
0
,
10
)
+
1
;
$count
.
html
(
count
).
data
(
'
count
'
,
count
);
if
(
!
$count
.
is
(
'
:visible
'
))
{
$count
.
show
(
'
fast
'
);
}
}
return
this
;
},
close
:
function
(
ev
)
{
if
(
ev
&&
ev
.
preventDefault
)
{
ev
.
preventDefault
();
}
ev
.
preventDefault
();
this
.
$el
.
remove
();
this
.
model
.
destroy
();
converse
.
emit
(
'
onChatBoxClosed
'
,
this
);
return
this
;
},
restore
:
function
(
ev
)
{
if
(
ev
&&
ev
.
preventDefault
)
{
ev
.
preventDefault
();
}
this
.
$el
.
remove
();
this
.
model
.
set
({
'
time_opened
'
:
moment
().
format
(),
'
minimized
'
:
false
});
return
this
;
}
});
this
.
MinimizedChatBoxesView
=
Backbone
.
Overview
.
extend
({
initialize
:
function
()
{
this
.
model
.
on
(
"
add
"
,
function
(
item
)
{
if
(
item
.
get
(
'
minimized
'
))
{
this
.
addChat
(
item
);
}
},
this
);
this
.
model
.
on
(
"
change:minimized
"
,
function
(
item
)
{
this
.
onChanged
(
item
);
},
this
);
},
render
:
function
()
{
return
this
.
$el
;
},
_ensureElement
:
function
()
{
/* Override method from backbone.js
* Make sure that the el and $el attributes point to a DOM snippet
* from src/templates/trimmed_chats.html
*/
if
(
!
this
.
el
)
{
var
$el
=
$
(
converse
.
templates
.
trimmed_chats
());
this
.
setElement
(
$el
,
false
);
}
else
{
this
.
setElement
(
_
.
result
(
this
,
'
el
'
),
false
);
}
},
onChanged
:
function
(
item
)
{
var
view
;
if
(
item
.
get
(
'
minimized
'
))
{
this
.
addChat
(
item
);
}
else
{
view
=
this
.
get
(
item
.
get
(
'
id
'
));
view
.
restore
();
}
},
addChat
:
function
(
item
)
{
var
view
=
new
converse
.
MinimizedChatBoxView
({
model
:
item
});
this
.
$
(
'
.box-flyout
'
).
append
(
view
.
render
());
this
.
add
(
item
.
get
(
'
id
'
),
view
);
}
});
this
.
RosterItem
=
Backbone
.
Model
.
extend
({
initialize
:
function
(
attributes
,
options
)
{
var
jid
=
attributes
.
jid
;
...
...
@@ -2580,7 +2736,7 @@
openChat
:
function
(
ev
)
{
ev
.
preventDefault
();
return
converse
.
chatboxviews
.
showChat
Box
({
return
converse
.
chatboxviews
.
showChat
({
'
id
'
:
this
.
model
.
get
(
'
jid
'
),
'
jid
'
:
this
.
model
.
get
(
'
jid
'
),
'
fullname
'
:
this
.
model
.
get
(
'
fullname
'
),
...
...
@@ -2963,17 +3119,11 @@
}
});
this
.
RosterView
=
Backbone
.
V
iew
.
extend
({
this
.
RosterView
=
Backbone
.
Overv
iew
.
extend
({
tagName
:
'
dl
'
,
id
:
'
converse-roster
'
,
initialize
:
function
()
{
var
views
=
{};
this
.
get
=
function
(
id
)
{
return
views
[
id
];
};
this
.
set
=
function
(
id
,
view
)
{
views
[
id
]
=
view
;
};
this
.
model
.
on
(
"
add
"
,
function
(
item
)
{
this
.
addRosterItemView
(
item
).
render
(
item
);
if
(
!
item
.
get
(
'
vcard_updated
'
))
{
...
...
@@ -3007,7 +3157,6 @@
});
}
this
.
$el
.
hide
().
html
(
roster_markup
);
this
.
model
.
fetch
({
add
:
true
});
// Get the cached roster items from localstorage
},
...
...
@@ -3029,7 +3178,7 @@
addRosterItemView
:
function
(
item
)
{
var
view
=
new
converse
.
RosterItemView
({
model
:
item
});
this
.
set
(
item
.
id
,
view
);
this
.
add
(
item
.
id
,
view
);
return
this
;
},
...
...
@@ -3460,7 +3609,7 @@
if
(
converse
.
show_controlbox_by_default
)
{
toggle
.
hide
();
// It's either or
}
$
(
'
#conversejs
'
).
ap
pend
(
toggle
);
$
(
'
#conversejs
'
).
pre
pend
(
toggle
);
return
this
;
},
...
...
@@ -3503,14 +3652,17 @@
}
});
// Initialization
// --------------
// This is the end of the initialize method.
this
.
_initialize
=
function
()
{
this
.
chatboxes
=
new
this
.
ChatBoxes
();
this
.
chatboxviews
=
new
this
.
ChatBoxViews
({
model
:
this
.
chatboxes
});
this
.
controlboxtoggle
=
new
this
.
ControlBoxToggle
();
this
.
otr
=
new
this
.
OTR
();
};
// Initialization
// --------------
// This is the end of the initialize method.
this
.
_initialize
();
if
((
this
.
prebind
)
&&
(
!
this
.
connection
))
{
if
((
!
this
.
jid
)
||
(
!
this
.
sid
)
||
(
!
this
.
rid
)
||
(
!
this
.
bosh_service_url
))
{
this
.
log
(
'
If you set prebind=true, you MUST supply JID, RID and SID values
'
);
...
...
converse.min.css
deleted
100644 → 0
View file @
a29a0293
/** Converse.js (Web-based XMPP instant messaging client)
* http://conversejs.org
* Copyright (c) 2012, Jan-Carel Brand <jc@opkode.com>
* Dual licensed under the MIT and GPL Licenses
*/
/*!
* Converse.js (Web-based XMPP instant messaging client)
* http://conversejs.org
*
* Copyright (c) 2012, Jan-Carel Brand <jc@opkode.com>
* Dual licensed under the MIT and GPL Licenses
*/
@font-face
{
font-family
:
Converse-js
;
src
:
url(fonticons/fonts/Converse-js.eot)
}
@font-face
{
font-family
:
Converse-js
;
src
:
url(data:application/font-woff;charset=utf-8;base64,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)
format
(
'woff'
),
url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAANAIAAAwBQRkZUTWXu0mgAADcoAAAAHEdERUYAhgAGAAA3CAAAACBPUy8yU3bcQQAAAVgAAABWY21hcDGBqkUAAALgAAACuGdhc3D//wADAAA3AAAAAAhnbHlmCMHqtwAABkwAACt4aGVhZP3EpBIAAADcAAAANmhoZWEEcQBfAAABFAAAACRobXR4eeoCIwAAAbAAAAEwbG9jYfBX+roAAAWYAAAAtG1heHAArACLAAABOAAAACBuYW1labUpXgAAMcQAAAGncG9zdAt4n0MAADNsAAADlAABAAAAAQAAA6jt8V8PPPUACwIAAAAAAM4ysZsAAAAAzjKxmwAA/98CQAIAAAAACAACAAAAAAAAAAEAAAIA/98ALgJAAAD+AAJAAAEAAAAAAAAAAAAAAAAAAAA/AAEAAABZAIgAEQAAAAAAAgAAAAEAAQAAAEAAAAAAAAAAAQICAZAABQAIAUwBZgAAAEcBTAFmAAAA9QAZAIQAAAIABQMAAAAAAAAAAAAAEADgoAAAAAAAAAAAUGZFZABAIxvwAAHg/+AALgIAACGAAAABAAAAAAAAAgAAAAAAAAAAqgAAAAAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAwIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAJAAAACQAAAAkAAAAIAAEACAAAAAgAAAAIAABwCAAAAAgAAAAIAAAACAAAAAgAAQAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAEACAAAgAgAAAAIAAAACAAAgAgAAAAIAAAACAAAAAgAAIAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAADAgAAIAIgAAACAAAAAAAAAAAAAAAAAABgAGAAQAAAACAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAADAAAAHAABAAAAAAGyAAMAAQAAABwABAGWAAAAUgBAAAUAEgAAIxsjYCNkI2kl2SX8Jg8mESYWJh0mHyY7JmwmoCcJJxAnFScYJxonZCsUKyjgBOAS4BfgG+Ad4B/gIuAr4DPgOOA64EHgUOBT4FXgWvAA//8AAAAAIxsjYCNkI2gl2SX7Jg4mESYWJh0mHyY5JmsmoCcJJw4nFScYJxonZCsUKyXgAOAS4BXgGuAd4B/gIeAk4C3gOOA64D/gReBT4FXgWPAA//8AANz+3Nnc0AAA2i8AAAAA2j7Z8doQ2hYAANme2ZvZBgAA2TXZM9k02MfVQgAAAAAf/h/+H/wf+yAbH/kf+AAAH/cf9x/3H/cf9R/0AAAQAwABAAAAAAAAAAAASgAAAEoATAAAAAAAAAAAAEYAAAAAAAAARAAAAAAAAAAAAAAAPgBEAAAAAAAAAAAAAAAAAAAAPgAAAAAAAAAAAAAAAAA+AAAAAAAzADIAEgARAAwACwAwAC4ALAAFAA0ADgBTAFIAUABRAAQAVQBXAAYAWAAlACYAJAAnACgAKQAqAEwAVABNAAABBgAAAQAAAAAAAAABAgAAAAIAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4ALABUAJgA1gD0AR4BZgGaAdoCJAKUAsoC7gMSA2IDyAQQBIQE4AVyBagGCAY6BwoHPgeAB7oH/gguCIIIugj6CUgJpAnECggKaAquC2ILoAvgDCAMZgyoDO4NNg1wDcoOCA6GDu4PRg++D+4QGBBOEKIQ/BFAEW4RnBG0EdQR/BIsElISahKoEtQTDBNWE4ITqhPGE/gUGBQuFEoUdBSSFLYU8hUeFYQVvAABAAD/4AIAAeAAAgAAEQEhAgD+AAHg/gAAAAAAAgAAAAACAAHRAAUADgAALQEFNSUFBxUjNSMVIzU3AgD/AP8AAQABAECAgIDAucbGUcfHSsCAgMCQAAAAAwAA/+ACAAHgAAkADgASAAABMhYVFA8BJzc2AQc3AScXByc3AbAhLxAgcCAV/osgkAEocB7gHOAB4C8hGxUgcCAQ/pCQIAEocG7gHOAAAAAEAAAAAAIAAaAABwAhACkALQAANhQWMjY0JiIlIy4CKwEiDgEHIyIGFREUFjMhMjY1ETQmAiImNDYyFhQ3IzUzmD1WPT1WAQtwBQgUD4APFAgFcA0TEw0BwA0TE7J2U1N2U1JAQNtWPT1WPUgVFhUVFhUTDf7gDRMTDQEgDRP+wlN2U1N2iyAABAAAACACAAGgAAcADwAlACkAABIUFjI2NCYiBhQWMjY0JiIFNTQmKwMiBh0BFBYzITI2PQEXNQchNSHAL0IvL0LvL0IvL0IBURMNUMAwDRMTDQFADROAwP8AAQABcUIvL0IvL0IvL0Iv8DANExMNoA0TEw0wUOCgYAAAAAIAAAAgAgABoAALAA4AAAEmIgcGFBcWMjc2NAU1FwHrcPZwFRVw9nAV/sCgAZAQEFS4VBAQVLi8wGAAAAEAAP/gAgAB4AAaAAATJR0BERQGIiY0NjMyFzUHFRQGIiY0NjMyFzWgAWBCXEJCLhkX4EJcQkIuGRcBgGAgQP7wIS8vQi8IpT3wIS8vQi8IqAAAAAMAAP/fAgAB4AAHAA8AMQAANxUWOwE1IyIhFTMyNzUmIzc0JiIGFRQXBhUUFhc1BgcmNTQ2MhYVFAcmJxU+ATU0JzZgCAgQEAgBGBAICAgIcJbUlg8PIx0PDAWDuoMFDA8dIw8Pv94B4OAB3gEgapaWai0qGx4hNw3KBwsWF12Dg10XFgsHyg03IR4bKgAAAAEAAP/gAeABwAAhAAAlDgIjIi4ENTQ+ATc2JiMiBg8BFB4CMz4CNTQmAWAMFREODyQYKhYVESMMFlsbDjAREVFeoTALIDVqoAwjERUWKhgkDw4RFQwWajAYGDChXlEHFzQOG1sAAAAAAQADAGAB/QFAACkAACUWBw4BJjU0PgEmJy4BIyIOAQcOAR4BFRQGJicmNzY3NjcwMjAyMRYXFgH9CQ8LSUMGBQMHDiwnGhwhCgcDBQZDSQsPCQYeRJMCApNEHsA/EQwHFRYHEwwSCBAIAgsLCBIMEwcWFQcMET8hHz8BAT8fAAAEAAD/4AIAAeAAHgAmACoANAAAATI2PQEjNSEiBhURFBYzITUzMjY9ASM1MzI2PQEjNSIyFhQGIiY0AyMRMwEjNTQ2OwEyFhUB4A0TQP5gDRMTDQGgIA0TQCANE0C6NCYmNCZgICABAMAlG0AbJQFgEw1AIBMN/kANE4ATDUAgEw1AICY0JiY0/sYBwP6gIBslJRsAAgAA/+AB4AHAADEAWgAAASEVIyIGHQEUFjsBFSMiBh0BFBY7ARUjIgYdARQWOwEVIyIGHQEUFjsBFSEyNjURNCYBIzUzMjY9ATQmKwE1MzI2PQE0KwE1MzI2PQE0KwE1MzI2PQE0KwE1MwHB/n8vBwoLBi8vBwoLBi8vBwoLBi8vBwoLBi8BgQ0SEv7SQBEHCAgHEREHCA8REQcIDxERBwgPEUABwEAJBiAHCiAJBiAHCiAJBiAHCiAJBiAHCkATDgGgDRL+QCAKByAHCCAKByAPIAoHIA8gCgcgDyAAAAAFAAAAAAIAAaAADwASABUAGgAdAAABISIGFREUFjMhMjY1ETQmBQc1NyEPARc3FyE/ARUB0P5gFBwcFAGgFBwc/uOHGAFQqDMzM2r+xtaHAaAcFP7AFBwcFAFAFBzTavsCfhs3N4eNkfsAAAACAAD/4AIAAeAADgASAAABBxcHIxcHFTM3FzU3FzcFJzcXARAwMHBwWIgUtFiAMDD+4CBwIAHgMDCAWLQUiFhwcDAwICBwIAABAAD/4AIAAcAAFAAAEjIWFAYjIicOAQc1PgE1NCcuATU0ltSWlmoUFCZZORwkASwzAcB6rHoDJhsCDg0sGQcHHlQwVgAAAAACAAD/4AIAAcAAHwA0AAAAIgcGBwYVFBcWFxYXFhU2NzYzMhcWMzI3Njc2NCcmJyYyFhQGIyInDgEHNT4BNTQnLgE1NAEpUiYjGzMRESAYBAIFBhMaBAQQECkmIxszMxsjudSWlmoUFCZZORwkASwzAYANDBYpOB4cHRUQHAkJBAYTAQINDBYpcCkWDE16rHoDJhsCDg0sGQcHHlQwVgAAAgAA/+ACQAHgABMARQAAJRQXFQYjIicGIyImNDYyFhUUBwYBBhUUFxYXFhcWFTY3NjMyFxYzFSInDgEHNT4BNTQnLgE1NDYzMhYXJicmJyYnJiIHBgIgIAgIMyQUFTxUVHhUGwX+UzMRESAYBAIFBhMaBAQQEBQUJlk5HCQBLDOWamiVAx8jCSgbIyZSJiMdIxEIASUFS2pLSzUpIQwBRyk4HhwdFRAcCQkEBhMBAkADJhsCDg0sGQcHHlQwVnp2VQ4DKyAWDA0NDAAAAgAA/+ACQAHgABQALgAAEjIWFAYjIicOAQc1PgE1NCcuATU0ARQWFxUuAScGIyInMjc2NzY1NCcWFRQGBwaNxo2NYxMSJFI1GSEBKi8B8hkVLUQfEBBHOHBRJxYXATspJAEB4HKhcQIjGgENDCkXBwcbTy1Q/r8VIwoLARYeAiNBICosMQcIMEMnRBcGAAAAAwAA/+ACQAHgAB8ANABOAAAAIgcGBwYVFBcWFxYXFhU2NzYzMhcWMzI3Njc2NCcmJyYyFhQGIyInDgEHNT4BNTQnLgE1NAEUFhcVLgEnBiMiJzI3Njc2NTQnFhUUBgcGARZMIyAYLw8QHRgEAQICExsEBA4PJiMgGC8vGCCsxo2NYxMSJFI1GSEBKi8B8hkVLUQfEBBHOHBRJxYXATspJAEBoAwLFCUyGxkaFA8dBAUCAhMBAQsLFCZkJRQLTHKhcQIjGgENDCkXBwcbTy1Q/r8VIwoLARYeAiNBICosMQcIMEMnRBcGAAIAQP/gAcABuAAdAD0AAAUhIiY1NDc2NyYnJjU0NzYyFxYVFAcGBxYXFhUUBiUhJicmJy4BPQE0Nz4BNTQmIgYVFBYXFh0BFAYHBgcGAaj+sAoOJx8pEgwUJSZwJiUUDBIpHycO/sEBGgcUISgJCgwWGzFEMRsWDAoJKCEUIA4KNzgtFBEWJSw+LC4uLD4sJRYRFC04NwoOMB8dLwkCDQgRDgcNMx8rPT0rHzMNBw4RCA0CCS8dAAADAAD/4AIAAdgAHQA9AGYAAAUhIiY1NDc2NyYnJjU0NzYyFxYVFAcGBxYXFhUUBiUhJicmJy4BPQE0Nz4BNTQmIgYVFBYXFh0BFAYHBgcGJyM2NzY3PgE9ATQnLgE1NDYzMhc2NyYjIgcGFRQXFhcGBwYVFBY7ATYB6P6wCg4nHykSDBQlJnAmJRQMEikfJw7+wQEaBxQhKAkKDBYbMUQxGxYMCgkoIRRXMAcUISgJCgwWGzEiBQQUGRocOCYlFAwSKR8nDgpCASAOCjc4LRQRFiUsPiwuLiw+LCUWERQtODcKDjAfHS8JAg0IEQ4HDTMfKz09Kx8zDQcOEQgNAgkvHQEfHS8JAg0IEQ4HDTMfKz0BFg4NLiw+LCUWERQtODcKDhcAAgAAACACAQGAABEAIwAAEzIWFAYiJj0BNDYzFSIHBgc2ITIWFAYiJj0BNDYzFSIHBgc2cC9BQV1Cg11CLwkHCQEoL0FBXUKDXUIvCQcJAQBCXEJCLhBdg0AvCQkBQlxCQi4QXYNALwkJAQAACAAc//8B4AHgAAcADwAXAB8AJwAvADcAPwAAEhQWMjY0JiIWFBYyNjQmIhYUFjI2NCYiBhQWMjY0JiIGFBYyNjQmIiYUFjI2NCYiAhQWMjY0JiIGFBYyNjQmIsAmNCYmNGIlNSYmNTMTGhMTGksTGhMTGpsTGhMTGpsTGhMTGiMcKBwcKEgVHhUVHgG6NCYmNCZeNSUlNSa7GhMTGhObGhMTGhNLGhMTGhMlGhMTGhMBBCgcHCgcqR4VFR4VAAAAAgAA/+ACAAHgABUAHQAAJScmBzY1NCYiBhQWMzI3Bh8BHgE2JiQiJjQ2MhYUAfB5ExIucKBwcFBHNgERZw0mGgL+9mpLS2pLLGcRATZHUHBwoHAuEhN5DwIaJoFLaktLagAAAAQAAP/gAgAB4AAnAC8AfwCHAAA/AScHJi8BIwcGBycHFwYPARUXFhcHFzcWHwEzNzY3FzcnNj8BNScmBiImNDYyFhQlNScmJzcnByYnNycHJic3JwcmLwEjBwYHJwcXBgcnBxcGBycHFwYPARUXFhcHFzcWFwcXNxYXBxc3Fh8BMzc2Nxc3JzY3FzcnNjcXNyc2NwYiJjQ2MhYUthUXHQgJBiAGCQgdFxUEAyMjAwQVFx0ICQYgBgkIHRcVBAMjIwM9GhMTGhMBcCIBAR0NIQMEFBccBQUHHRMGBgYgBgYGEx0HBQUcFxQEAyENHQEBIiIBAR0NIQMEFBccBQUHHRMGBgYgBgYGEx0HBQUcFxQEAyENHQEBcTopKTopdx0XFQQDIyMDBBUXHQgJBiAGCQgdFxUEAyMjAwQVFx0ICQYgBgk/ExoTExrdIAYGBhMdBwUFHBcUBAMhDR0BASIiAQEdDSEDBBQXHAUFBx0TBgYGIAYGBhMdBwUFHBcUBAMhDR0BASIiAQEdDSEDBBQXHAUFBx0TBgYwKTopKToAAAAAAQAA/+ACAAHgAB8AACUnNjU0JiMiBxcWFA8BBiIvAQYVFBYzMjcXHgE/ATYmAfXmEVQ8FRVTCgoyChoKUwZUPCQgxQkZCTMJAUfFICQ8VAZTChoKMgoKUxUVPFQR5goBCTMJGQAAAAACAAD/4AHgAcAAIwAvAAABIyIGHQEjIgYdARQWMyEyNj0BNCYrATU0NjsBMhYdATM1NCYDIzcmNTQ2MhYVFAcBgEAoOMgKDg4KARAKDg4KCBMNQA0TQDjoQA4OExoTDgHAOChgDgrwCg4OCvAKDmANExMNYGAoOP5gRgkRDRMTDREJAAADAED/4AHAAeAAFwAfACcAAAEjNTQmIgYdASMiBh0BFBYzITI2PQE0JgYiJjQ2MhYUNyM1NDYyFhUBoCBLaksgDRMTDQFADRMToBoTExoTIIAmNCYBAGA1S0s1YBMN4A0TEw3gDRPAExoTExqtYBomJhoAAAMAAP/gAUABwAAZACUALwAAASM1NCYrASIGHQEjIgYdARQWMyEyNj0BNCYHIzcmNTQ2MhYVFAc3IzU0NjsBMhYVASgIOChAKDgICg4OCgEQCg4OckAODhMaEw4ugBMNQA0TAQBgKDg4KGAOCvAKDg4K8AoO4EYJEQ0TEw0RCZpgDRMTDQAAAAACAAD/4AIAAeAAFwAfAAAAIgYVFBcHFRQWOwE1MzUzNTM3FjMyNjQGIiY0NjIWFAGihF4DwxMNIEBAQCoaHEJeXCgcHCgcAeBeQg8Ow2ANEyBAQCoKXoRCHCgcHCgAAAADAAD/4AIAAeAAIgAmADIAAAEnLgEvAS4BDwEOAR8BFhcPATM1MzUzNTM1Fh8BFjY/ATYmASc3FzcHBi8BJj8BNh8BFgH1MgYhBzIJHQuKCwgGJAECshBgQEBABQRHCxsIXAcD/k0WmxfkFwsMiAsLFwsMiAsBQzIFIgcyCQMHXAgbC0cDBLJwIEBAJAMCJAYIC4oLHf77FpwXPBcLC4gMCxcLC4gMAAADAAD/4AIAAeAAFQAdACEAACUnJgc2NTQmIgYUFjMyNwYfAR4BNiYkIiY0NjIWFCczFSMB8HkTEi5woHBwUEc2ARFnDSYaAv72aktLakvgwMAsZxEBNkdQcHCgcC4SE3kPAhomgUtqS0tqVUAAAAAAAwAA/+ACAAHgABUAHQApAAAlJyYHNjU0JiIGFBYzMjcGHwEeATYmJCImNDYyFhQnIxUjFTMVMzUzNSMB8HkTEi5woHBwUEc2ARFnDSYaAv72aktLaktgQEBAQEBALGcRATZHUHBwoHAuEhN5DwIaJoFLaktLapVAQEBAQAAAAAACAAD/4AIAAeAAJwAvAAAlNScmJzcnByYvASMHBgcnBxcGDwEVFxYXBxc3Fh8BMzc2Nxc3JzY3BiImNDYyFhQCAEkFBitEPA0ODGAMDg08RCsGBUlKBAYrRD0MDgxgDA4MPUQrBgSbNiUlNiWwYAwODTxEKwYFSUkFBitEPA0ODGAMDgw9RCsGBEpKBAYrRD0MDgQlNiUlNgAAAAAHAED/4AHAAeAACQANAB0ALQAxADUAOQAAASEiBh0BITU0JicXIz8BIyIGDwEGFjsBMjYvAS4BFyEiBhcTHgE7ATI2NxM2JgMjJzMXIzUzFyM1MwGQ/uAUHAGAHGgHhgd8gAoQAQoBDAqgCgwBCgEQTv7QDREBGgEVDfANFQEaARHlMBBAYEBAUDBAAaAcFBAQFBwgMjIgDgpDCg0NCkMKDqATDf7gDRMTDQEgDRP+4ODg4ODgAAAAAwAg/+AB4AHgAAMADQARAAAXIRMhJTUjFSMVNyEXNSsBNTNgAUAg/oABAICgIAGAIMBAQCABYGBAQGAgIGAgAAMAAABAAgABgAAJACEAKQAAACIGBx4BMjY3JicWFwYHBiInJic2NzY3BhUUFjI2NTQnFgYUBiImNDYyAVKkiiQkiqSKJCReLh0dLjqIOi4dHS4CBAhLaksIBHwcKBwcKAGAWEhIWFhISAMdLi4dJSUdLi4dAgIVFzVLSzUXFQIGKBwcKBwAAAAFAAAAAAIAAeAAEAAYACYAMAA7AAABFhcOASMiJzcWMzI3NjcmJwciJzcWFRQGEyMHJiMiBgcWFwcVMwEFMhYXBy4BNTQ2BzY3NjcGFRQXByYBpDshJIpSLiwnGRpEOi4dHCyBERCdBEurG24qLVKKJCA7WxsBxf7wEhsCNhIXHIUdLgIECBodKgFMKkJIWA8nBiUdLiwdpgSdEBE1SwFdbg5YSEEqWhsBxYIXEjYCGxIUHGMuHQICFRcrIx0cAAABACD/3wHhAeAAMgAAAScHBhQWMj8BNjQmIg8BMBQxBhQWMjcwMzE3JwcwFDEGIiY0NzIxNzYyFhQPAQYiJjQ3AV0hohQoORTDIkNfIs0vXoQvAYsgjCFfQyEBzBU5KBTDBxMNBwE8IaIVOSgUwyJfQyLMAS+EXi+MIIsBIUNeIs0UKDkVwgcNEwcAABEAAP/gAeABwAAHAA0AEwAYACAAKAAtADMAOABAAEgATQBTAFoAYQBoAG8AAAAiBhQWMjY0BzY3MwYHJQYHIzY3IRYXIz0CFhcWFxYXJzY3NjcVIzYXFSM2NwcmJzMWFzczFSMmFxUmJyYnJicXBgcGBzUzBic1MwYHNyYnMxYXJyMmJxYXFiU2NwYHIzYHMxYXJicmBQYHNjczBgFTxo2Nxo1oBgI/Ag3+uAYCPwINAScHAmALCxQQDAioEBQLC04IRmACB1kNAj8CBhhgVwdeCwsUEAwIqBAUCwtOCEZgAgcpAgY4DQIgMA4XIBkQ/soZIBcOMAwMMA4XIBkQATYZIBcOMAwBwI3GjY3Gsx8hIR+gHyEhHx8hQCBeBAcOHBIXKRwOBwReFzdAIR+gHyEhH0BAHz9eBAcOHBIXKRwOBwReFzdAIR9gIR8fIWAsIBAZEBAZECAsE/MsIBAZEBAZECAsEwAAAAIAAAAAAgABwAASACgAAAE0JiMiByYjIgYVFB8BFjI/ATYnBwYjJi8BJjU0NjMyHwE3NjMyFhUUAgBWPUEsLEE9VjCgICAgoDBbogIBAQKiGzEiJRkvLxklIjEBLT1WMDBWPUEsoCAgoCwDogIBAaIZJSIxGzQ0GzEiJQAFAAD/4AIAAeAABwAPABcAHwAnAAAWMjY0JiIGFBIyFhQGIiY0FjI3DgEiJic2FBYyNjQmIhYUFjI2NCYiltSWltSWqqx6eqx6eqxKBV18XQUgExoTExqtExoTExogltSWltQBOnqsenqsgSpDXFxDZSgcHCgcHCgcHCgcAAAAAAIAIP/gAewB4AAcACoAACUyFgYjFg4BIxQGIyImJxE+ATUyHgIGBzMyFgYlETMVIyImPQE0NjsBFQHQEQQWDwYBFg8mGkdaP16SChQSAxgbYBYMEv6AIEANExMNQMAwMAMkKRcZKQcBABx5OwkaKEgtMDBQ/wAQHBTAFBwQAAAABQAA/+ACAAHgAAcADwAXAB8AKwAAFjI2NCYiBhQSMhYUBiImNBY0NjIWFAYiNjQ2MhYUBiIfAQ4BIiYnNx4BMjaW1JaW1JaqrHp6rHpQExoTExqtExoTExoNKRVJVkkVKQ8zPDMgltSWltQBOnqsenqsAxoTExoTExoTExoTehgkKiokGBkdHQAAAAAFAAD/4AIAAeAABwAPABcAHwArAAAWMjY0JiIGFBIyFhQGIiY0FjQ2MhYUBiI2NDYyFhQGIhcVIxUUBiImPQEjNZbUlpbUlqqsenqselATGhMTGq0TGhMTGi0gHCgcgCCW1JaW1AE6eqx6eqwDGhMTGhMTGhMTGhNgIDAUHBwUMCAAAAAFAAD/4AIAAeAABwAPABcAHwArAAAWMjY0JiIGFBIyFhQGIiY0FjQ2MhYUBiI2NDYyFhQGIgcnPgEyFhcHLgEiBpbUlpbUlqqsenqselATGhMTGq0TGhMTGrMpFUlWSRUpDzM8MyCW1JaW1AE6eqx6eqwDGhMTGhMTGhMTGhPGGCQqKiQYGR0dAAAAAAUAAP/gAgAB4AAHAA8AGgAiAC4AABYyNjQmIgYUEjIWFAYiJjQXPgE3DgEjIiYnFjYUFjI2NCYiBiIHJjU0NjIWFRQHltSWltSWqqx6eqx63zZMDwlePyxLFjWeExoTExqBRAsDHCgcAyCW1JaW1AE6eqx6eqy6Cy4gQFUsJCndKBwcKBw6EgQPDBAQDA8EAAUAAP/gAgAB4AAHAA8AEwAbACMAABYyNjQmIgYUEjIWFAYiJjQFFwcnJjQ2MhYUBiI2NDYyFhQGIpbUlpbUlqqsenqsegFFC9oMGhMaExMarRMaExMaIJbUlpbUATp6rHp6rIMmQCbAGhMTGhMTGhMTGhMABQAA/+ACAAHgAAcADwAXAB8AOQAAFjI2NCYiBhQSMhYUBiImNDYUFjI2NCYiFhQWMjY0JiIXMxYGBwYmJy4BBw4BFyMmNjc2FhceATc+AZbUlpbUlqqsenqselATGhMTGq0TGhMTGhggBB0aIDwLByQTEREEIAQdGiA8CwckExERIJbUlpbUATp6rHp6rBcaExMaExMaExMaE8AbMQkMHCASEQcGIBEbMQkMHCASEQcGIAAABQAA/+ACAAHgAAcADwAXAB8AJwAAFjI2NCYiBhQSMhYUBiImNBY0NjIWFAYiEhQWMjY0JiIGFBYyNjQmIpbUlpbUlqqsenqsepAlNiUlNlsTGhMTGtMTGhMTGiCW1JaW1AE6eqx6eqzRNiUlNiUBBCgcHCgcHCgcHCgcAAUAAP/gAgACAAATACcAMwBLAFMAAAAiJjU0NTY3Njc2HgEGBwYHFhUUJy4BPgEXFhcWFxQVFAYiJjU0NyYWMjY3Fw4BIiYnNxYBNCcGByYiByYnBhUUFwYVFBYyNjU0JzYCIiY0NjIWFAFNGhMBKBESBwsDBwYPDgnUBgcDCwcSESgBExoTCQ5HPDMPKRVJVkkVKQ8BUQ0bPUSuRD0bDSEhltSWISGqrHp6rHoBABMNAQEdEwkFAQcNCwIDBwkNDS0CCw0HAQUJEx0BAQ0TEw0NCQfNHRkYJCoqJBgZATMiHjwZNTUZPB4iNys6RGqWlmpEOiv+h3qsenqsAAUAAP/gAgAB4AAHAA8AGwAvAEMAABYyNjQmIgYUEjIWFAYiJjQFLgEiBgcnPgEyFhcmFgYHBgcWFRQGIiY1NDU2NzY3NgY+ARcWFxYXFBUUBiImNTQ3JicmltSWltSWqqx6eqx6ATAPMzwzDykVSVZJFQsDBwYPDgkTGhMBKBESB/QDCwcSESgBExoTCQ4PBiCW1JaW1AE6eqx6eqzcGR0dGRgkKiok6A0LAgMHCQ0NExMNAQEdEwkFARQNBwEFCRMdAQENExMNDQkHAwIAAAAEAAD/4AIAAeAABwAPADEAPQAAFjI2NCYiBhQSMhYUBiImNCUyFh0BFAYrASImNSMUBisBIiY9ATQ2OwEyFh0BMzU0NjMDMjY3Fw4BIyInNxaW1JaW1JaqrHp6rHoBYAcJEw1ADRNAEw1ADRMJB2AHCUAJBzAiOxEbFUkrJCARGCCW1JaW1AE6eqx6eqwqCQcwDRMTDQ0TEw0wBwkJBxAQBwn/ACIcECQqDxwLAAAAAAgAAP/gAgAB4AAHAA8AGQAfACMAKQA9AFEAABYyNjQmIgYUEjIWFAYiJjQXFRQWOwEyNj0BByYnJjUzFyM1MxcGBzUzFCQyNz4BMhYXFjI3NjU0JiIGFRQXFjI3PgEyFhcWMjc2NTQmIgYVFBeW1JaW1JaqrHp6rHowSzVANUvgFBAcQGBAQEQQFED+6BECAhUcFQICEQEBIjAiAcERAgIVHBUCAhEBASIwIgEgltSWltQBOnqsenqsViA1S0s1IHoHDxwoYGBEDwdaKIgIDhISDggIBQUYIiIYBQUICA4SEg4ICAUFGCIiGAUFAAAAAAQAAP/gAgAB4AAHAA8AEwAdAAAAIgYUFjI2NAIiJjQ2MhYUJzMVIxcjNTM1IzUzFTMBatSWltSWqqx6eqx68EBAYIAgIGAgAeCW1JaW1P7Geqx6eqzWQMAgYCCAAAAAAAQAAP/gAgAB4AAHAA8AEwAXAAAAIgYUFjI2NCQyFhQGIiY0FzMVIxEzFSMBVqx6eqx6/sbUlpbUluBAQEBAAbB6rHp6rKqW1JaW1MpAAUDAAAAAAAQAA//gAf0B4AACAA4AFgAeAAABAyECMhcTFgYjISImNxMCFBYyNjQmIjQyFhUHIyc0AQCsAVi+JAzbDRMa/k4aEw3bAhMaExMaGhMKLAoBkf6PAcAW/kwWICAWAbT+oxoTExoToBMNYGANAAcAIP/gAeAB4AANABEAHwAuADIANgA8AAATMxUzNTQmKwEiBh0BMzUzFSMlNSMiBh0BFBY7ATUjNQc1NCYrARUzMjY9ATQjMgcjNTM1IzUzEwcnNxc3QEAgEw1ADRMgQEABoGANExMNYGBAEw1gYA0TFhYgQEBAQIDQcClHsAFgYMANExMNwMBAQCATDaANEyCgMDANE+ATDTAgUEAgQP8A4JAjSpcAAAQAAAAAAiEBwAAPAB8ALwA7AAAkIiY0NzY0JyY0NjIXFhQHJiImNDc2NCcmNDYyFxYUByYiJjQ3NjQnJjQ2MhcWFAcDNhYVERQGLwEjNTMBxxQOB0REBw4UB1JSXBQOBzExBw4UBz8/XRMOBx4eBw4TBy0tWgkODgl5UFATDhQHRMBEBxQOB1LoUiYOFAcxjDEHFA4HQLJAJg8TBx9WHwcTDwgsfiwBRAkFDv5iDgUJecAAAAMAAAAAAbgBwAAPAB8AKwAAJCImNDc2NCcmNDYyFxYUByYiJjQ3NjQnJjQ2MhcWFAcDNhYVERQGLwEjNTMBchQOBzExBw4UBz8/XRMOBx4eBw4TBy0tWgkODgl5UFBADhQHMYwxBxQOB0CyQCYPEwcfVh8HEw8ILH4sAUQJBQ7+Yg4FCXnAAAACAAAAAAFQAcAADwAbAAAkIiY0NzY0JyY0NjIXFhQHAzYWFREUBi8BIzUzARwTDgceHgcOEwctLVoJDg4JeVBQbQ8TBx9WHwcTDwgsfiwBRAkFDv5iDgUJecAAAAIAAAAAAeABwAALABsAABM2FhURFAYvASM1MwUVIycHIzU3JzUzFzczFQfJCQ4OCXlQUAGQKjY2KjY2KjY2KjYBuQkFDv5iDgUJecCWKjY2KjY2KjY2KjYAAAAAAQAAAAAA4AHAAAsAABM2FhURFAYvASM1M8kJDg4JeVBQAbkJBQ7+Yg4FCXnAAAAAAgAA//8CAAHBAA0AEQAAEzIVERQjIi8BIzUzNzYXIRUh1goKBgd5UFB5BzABAP8AAcAR/mIRB3nAeQfAQAAAAAIAAP//AgABwQANABkAABMyFREUIyIvASM1Mzc2ASMVIzUjNTM1MxUz1goKBgd5UFB5BwEwYEBgYEBgAcAR/mIRB3nAeQf/AGBgQGBgAAAAAwBgAAABoAHAABEAGQAhAAAlNjU0JisDETsCMjY1NCYnMzIWFAYrARcjNTMyFhQGAWIeSzVAQCAgQGA1SyK+MxUeHhUzUFBQFR8f7iMvNUv+QEs1IjujJjQmwIAmNCYAAgBgAAABoAHAABEAFQAAATMVFAYiJj0BMxUUFxYyNzY1BSEVIQFgQF6EXkAaHFQcGv8AAUD+wAHA0DxUVDzQ0B8XGhoXH7BAAAAAAAEAQAAAAcABwAALAAABFSMDMxUjNTMTIzUBwECgQOBAoEABwCD+gCAgAYAgAAAAAAEAAAAAAgABwAAqAAAlFSMWFRQHBiInJjUzFBYyNjQmIyE1MyYnJjQ3NjIXFhUjNCYiBhQWMzIXAgB1FTIugC4yQDlOOTkn/wCWAgIyMi6ALjJAOU45OSc9LeAgHiI4JSMjJTgaJiY0JiABAiVwJSMjJTgaJiY0JiAAAAAEACAAAAHgAcAAAwAHAA0AFAAAExEhEQMhESEBEScRIS8BNxc1IxcHYAGAIP7AAUD+gCABgCCpYEnASWABwP6AAYD+oAFA/oABQCD+gCBpYEnASWAAAAAAAwAAACACAAGgAA8AHwAiAAABISIGHQEUFjMhMjY9ATQmExQGIyEiJj0BNDYzITIWFQU3JwGg/sAoODgoAUAoODgYJhr+wBomJhoBQBom/uCgoAGgOCjAKDg4KMAoOP7gGiYmGsAaJiYa4ICAAAAAAAEAAf/hAf8B3wArAAAlJzc2NzYvASYHBg8BJyYnJg8BBhcWHwEHBgcGHwEWNzY/ARcWFxY/ATYnJgH7m5sDAQQISQcKAwObmwMDCgdJCAQBA5ubAwEECEkHCgMDm5sDAwoHSQgEAUWbmwMDCgdJCAQBA5ubAwEECEkHCgMDm5sDAwoHSQgEAQObmwMBBAhJBwoDAAADAAD/4AIAAeAABwAPABcAABAUFjI2NCYiARQHATYzMhYFNDcBBiMiJpbUlpbUASoc/vguNlBw/oAcAQguNlBwAUrUlpbUlv8ANi4BCBxwUDYu/vgccAAAAgAA/+ACAAHgAAcAFwAAACIGFBYyNjQPARcVIycHIzU3JzUzFzczAWrUlpbUloBTUy1TUy1TUy1TUy0B4JbUlpbUF1NTLVNTLVNTLVNTAAABAAAAoAIAASAADwAAERUUFjMhMjY9ATQmIyEiBgkHAeAHCQkH/iAHCQEQYAcJCQdgBwkJAAAAAAEAAP/gAgAB4AAjAAABIzU0JisBIgYdASMiBh0BFBY7ARUUFjsBMjY9ATMyNj0BNCYB8LAJB2AHCbAHCQkHsAkHYAcJsAcJCQEgsAcJCQewCQdgBwmwBwkJB7AJB2AHCQAAAAADAAD/4AIAAeAAAwAHAA0AABkBIREDIREhDwEnBxc3AgAg/kABwGCgYECg4AHg/gACAP4gAcBQoGBAoOAAAAAAAgAA/+ACAAHgAAMABwAAGQEhEQMhESECACD+QAHAAeD+AAIA/iABwAAAAAADAAD/4AIAAeAAAwAHAAsAABkBIREDIREhBSERIQIAIP5AAcD+oAEA/wAB4P4AAgD+IAHAYP8AAAMAAP/gAgAB4AAHAA8AFwAAACIGFBYyNjQCIiY0NjIWFCQUFjI2NCYiAWrUlpbUlrCgcHCgcP7gOFA4OFAB4JbUlpbU/tZwoHBwoHhQODhQOAAAAAIAAP/gAgAB4AAHAA8AAAAiBhQWMjY0AiImNDYyFhQBatSWltSWsKBwcKBwAeCW1JaW1P7WcKBwcKAAAAMAAP/gAgAB4AAHAAsAFQAAACIGFBYyNjQlMxUjEyM1MzUjNTMVMwFq1JaW1Jb+4EBAYIAgIGAgAeCW1JaW1DZA/wAggCCgAAcAAAAgAgABoAALAA8AEwAXABsAHwAjAAABNSERFBYzITI2NREDIREhBSEVIRczFSMVMxUjFTMVIyczFSMBwP5AEw0BsBQcYP6AAYD+oAFA/sDAgICAgGBgwKCgAWBA/qANExwUARD+4AFAQCAgICAgICCgoAAAAAQAAAAAAgABwAADAAcADgAWAAABIREhExEhEQEhNTcXNxUmFBYyNjQmIgHA/oABgED+AAGg/sBghFxgHCgcHCgBgP7AAYD+QAHA/qBAoKBAIIQoHBwoHAACAAD/4AIAAcAAFABCAAAAIgYVFBYXFhUUBgcVPgE3FjMyNjQlMhcWHwE3Njc2HwEWBwYjBxcWFxYPAQYnJjEnByIHBi8BJjc0PwEnJjUmPwE2AWrUljMsASQcOVkmERdqlv6jAgMBAlNTAQIFBCcEAgEBU1MBAQIEJwQFA1NTAQIGAycEAgJTUwICBCcCAcB6VjBUHQUKGSwNDgEcJQJ6rDkBAQFTUwEBAgQoAwUDU1MBAgYDKAMCAVNTAQIDKAQFAQJTUwECBAQoAgACAAD/4AIAAcAAFAAkAAAAIgYVFBYXFhUUBgcVPgE3FjMyNjQFITIWHQEUBiMhIiY9ATQ2AWrUljMsASQcOVkmERdqlv5OAVsFBwcF/qUFBwcBwHpWMFQdBQoZLA0OARwlAnqsJgcFRQUHBwVFBQcAAAAMAJYAAQAAAAAAAQALABgAAQAAAAAAAgACACoAAQAAAAAAAwAnAH0AAQAAAAAABAALAL0AAQAAAAAABQALAOEAAQAAAAAABgALAQUAAwABBAkAAQAWAAAAAwABBAkAAgAEACQAAwABBAkAAwBOAC0AAwABBAkABAAWAKUAAwABBAkABQAWAMkAAwABBAkABgAWAO0AQwBvAG4AdgBlAHIAcwBlAC0AagBzAABDb252ZXJzZS1qcwAAagBzAABqcwAARgBvAG4AdABGAG8AcgBnAGUAIAAyAC4AMAAgADoAIABDAG8AbgB2AGUAcgBzAGUALQBqAHMAIAA6ACAAMQA1AC0AOAAtADIAMAAxADMAAEZvbnRGb3JnZSAyLjAgOiBDb252ZXJzZS1qcyA6IDE1LTgtMjAxMwAAQwBvAG4AdgBlAHIAcwBlAC0AagBzAABDb252ZXJzZS1qcwAAVgBlAHIAcwBpAG8AbgAgADEALgAwAABWZXJzaW9uIDEuMAAAQwBvAG4AdgBlAHIAcwBlAC0AagBzAABDb252ZXJzZS1qcwAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAEAAgECAQMBBAEFAQYBBwEIAQkBCgELAQwBDQEOAQ8BEAERARIBEwEUARUBFgEXARgBGQEaARsBHAEdAR4BHwEgASEBIgEjASQBJQEmAScBKAEpASoBKwEsAS0BLgEvATABMQEyATMBNAE1ATYBNwE4ATkBOgE7ATwBPQE+AT8BQAFBAUIBQwFEAUUBRgFHAUgBSQFKAUsBTAFNAU4BTwFQAVEBUgFTAVQBVQFWAVcHdW5pRjAwMAd1bmlFMDAwB3VuaTI3MEUHdW5pRTAwMwd1bmkyNjE2CWludmNpcmNsZQ5tdXNpY2Fsbm90ZWRibAd1bmkyNjZDB3VuaTI2MEYHdW5pMjYwRQd1bmkyNzBGB3VuaTI3MTAHdW5pMjcwOQd1bmlFMDEyB3VuaTI1RkMHdW5pMjVGQgd1bmlFMDE1B3VuaUUwMTYHdW5pRTAxNwd1bmlFMDFBB3VuaUUwMUIHdW5pRTAxRAd1bmkyMzFCB3VuaUUwMjEHdW5pRTAyMgd1bmlFMDI0B3VuaUUwMjUHdW5pRTAyNgd1bmlFMDI3B3VuaUUwMjgHdW5pRTAyOQd1bmlFMDJBB3VuaUUwMkIHdW5pRTAyRgd1bmlFMDJEB3VuaUUwMkUHdW5pRTAzMAd1bmlFMDMxB3VuaUUwMzIHdW5pRTAzMwd1bmkyNzY0DGludnNtaWxlZmFjZQd1bmkyNjFECXNtaWxlZmFjZQd1bmlFMDM4B3VuaTI2MzkHdW5pRTAzQQd1bmkyMzY5B3VuaTIzNjgHdW5pMjM2NAd1bmkyNjFGB3VuaUUwM0YHdW5pRTA0MAd1bmlFMDQxB3VuaTIzNjAHdW5pRTAxRgd1bmkyNkEwB3VuaUUwNDUHdW5pRTA0Ngd1bmlFMDQ3B3VuaUUwNDgHdW5pRTA0OQd1bmlFMDRBB3VuaUUwNEIHdW5pRTA0Qwd1bmlFMDREB3VuaUUwNEUHdW5pRTA0Rgd1bmlFMDUwB3VuaUUwNTMHdW5pRTA1NQd1bmkyNzE1B3VuaTI3MTgHdW5pRTA1OAd1bmlFMDVBB3VuaTI3MUEHdW5pMjYxMQd1bmkyQjI3B3VuaTJCMjgHdW5pMkIyNgd1bmkyQjI1B3VuaUUwNTkHdW5pRTAwMQd1bmkyQjE0B3VuaUUwMDIHdW5pRTAwNAAAAAH//wACAAEAAAAOAAAAGAAAAAAAAgABAAMAWAABAAQAAAACAAAAAAABAAAAAMmJbzEAAAAAzjKxmwAAAADOMrGb)
format
(
'truetype'
);
font-weight
:
400
;
font-style
:
normal
}
[
data-icon
]
:before
{
font-family
:
Converse-js
;
content
:
attr
(
data-icon
);
speak
:
none
;
font-weight
:
400
;
font-variant
:
normal
;
text-transform
:
none
;
line-height
:
1
;
-webkit-font-smoothing
:
antialiased
}
#conversejs
.icon-address-book
,
#conversejs
.icon-angry
,
#conversejs
.icon-attachment
,
#conversejs
.icon-away
,
#conversejs
.icon-blocked
,
#conversejs
.icon-bold
,
#conversejs
.icon-bubbles
,
#conversejs
.icon-bubbles-2
,
#conversejs
.icon-bubbles-3
,
#conversejs
.icon-camera
,
#conversejs
.icon-camera-2
,
#conversejs
.icon-cancel-circle
,
#conversejs
.icon-checkbox-checked
,
#conversejs
.icon-checkbox-partial
,
#conversejs
.icon-checkbox-unchecked
,
#conversejs
.icon-close
,
#conversejs
.icon-cog
,
#conversejs
.icon-cogs
,
#conversejs
.icon-confused
,
#conversejs
.icon-cool
,
#conversejs
.icon-dnd
,
#conversejs
.icon-envelop
,
#conversejs
.icon-evil
,
#conversejs
.icon-eye
,
#conversejs
.icon-eye-blocked
,
#conversejs
.icon-globe
,
#conversejs
.icon-grin
,
#conversejs
.icon-happy
,
#conversejs
.icon-headphones
,
#conversejs
.icon-heart
,
#conversejs
.icon-home
,
#conversejs
.icon-image
,
#conversejs
.icon-info
,
#conversejs
.icon-italic
,
#conversejs
.icon-key
,
#conversejs
.icon-key-2
,
#conversejs
.icon-lock
,
#conversejs
.icon-lock-2
,
#conversejs
.icon-minus
,
#conversejs
.icon-music
,
#conversejs
.icon-new-tab
,
#conversejs
.icon-newspaper
,
#conversejs
.icon-notebook
,
#conversejs
.icon-notification
,
#conversejs
.icon-offline
,
#conversejs
.icon-online
,
#conversejs
.icon-pencil
,
#conversejs
.icon-phone
,
#conversejs
.icon-phone-hang-up
,
#conversejs
.icon-play
,
#conversejs
.icon-plus
,
#conversejs
.icon-pushpin
,
#conversejs
.icon-quotes-left
,
#conversejs
.icon-radio-checked
,
#conversejs
.icon-radio-unchecked
,
#conversejs
.icon-remove
,
#conversejs
.icon-remove-2
,
#conversejs
.icon-room-info
,
#conversejs
.icon-sad
,
#conversejs
.icon-search
,
#conversejs
.icon-shocked
,
#conversejs
.icon-smiley
,
#conversejs
.icon-spell-check
,
#conversejs
.icon-spinner
,
#conversejs
.icon-strikethrough
,
#conversejs
.icon-thumbs-up
,
#conversejs
.icon-tongue
,
#conversejs
.icon-unavailable
,
#conversejs
.icon-underline
,
#conversejs
.icon-unlocked
,
#conversejs
.icon-user
,
#conversejs
.icon-users
,
#conversejs
.icon-volume-decrease
,
#conversejs
.icon-volume-high
,
#conversejs
.icon-volume-increase
,
#conversejs
.icon-volume-low
,
#conversejs
.icon-volume-medium
,
#conversejs
.icon-volume-mute
,
#conversejs
.icon-volume-mute-2
,
#conversejs
.icon-warning
,
#conversejs
.icon-wink
,
#conversejs
.icon-wondering
,
#conversejs
.icon-wrench
,
#conversejs
.icon-xa
,
#conversejs
.icon-youtube
,
#conversejs
.icon-zoom-in
,
#conversejs
.icon-zoom-out
{
font-family
:
Converse-js
;
speak
:
none
;
font-style
:
normal
;
font-weight
:
400
;
font-variant
:
normal
;
text-transform
:
none
;
line-height
:
1
;
-webkit-font-smoothing
:
antialiased
}
#conversejs
.icon-home
:before
{
content
:
"\e000"
}
#conversejs
.icon-pencil
:before
{
content
:
"\270e"
}
#conversejs
.icon-camera
:before
{
content
:
"\e003"
}
#conversejs
.icon-camera-2
:before
{
content
:
"\2616"
}
#conversejs
.icon-play
:before
{
content
:
"\25d9"
}
#conversejs
.icon-music
:before
{
content
:
"\266b"
}
#conversejs
.icon-headphones
:before
{
content
:
"\266c"
}
#conversejs
.icon-phone
:before
{
content
:
"\260f"
}
#conversejs
.icon-phone-hang-up
:before
{
content
:
"\260e"
}
#conversejs
.icon-address-book
:before
{
content
:
"\270f"
}
#conversejs
.icon-notebook
:before
{
content
:
"\2710"
}
#conversejs
.icon-envelop
:before
{
content
:
"\2709"
}
#conversejs
.icon-pushpin
:before
{
content
:
"\e012"
}
#conversejs
.icon-online
:before
{
content
:
"\25fc"
}
#conversejs
.icon-away
:before
{
content
:
"\25fb"
}
#conversejs
.icon-bubbles
:before
{
content
:
"\e015"
}
#conversejs
.icon-bubbles-2
:before
{
content
:
"\e016"
}
#conversejs
.icon-bubbles-3
:before
{
content
:
"\e017"
}
#conversejs
.icon-user
:before
{
content
:
"\e01a"
}
#conversejs
.icon-users
:before
{
content
:
"\e01b"
}
#conversejs
.icon-quotes-left
:before
{
content
:
"\e01d"
}
#conversejs
.icon-spinner
:before
{
content
:
"\231b"
}
#conversejs
.icon-search
:before
{
content
:
"\e021"
}
#conversejs
.icon-cogs
:before
{
content
:
"\e022"
}
#conversejs
.icon-wrench
:before
{
content
:
"\e024"
}
#conversejs
.icon-unlocked
:before
{
content
:
"\e025"
}
#conversejs
.icon-lock
:before
{
content
:
"\e026"
}
#conversejs
.icon-lock-2
:before
{
content
:
"\e027"
}
#conversejs
.icon-key
:before
{
content
:
"\e028"
}
#conversejs
.icon-key-2
:before
{
content
:
"\e029"
}
#conversejs
.icon-zoom-out
:before
{
content
:
"\e02a"
}
#conversejs
.icon-zoom-in
:before
{
content
:
"\e02b"
}
#conversejs
.icon-cog
:before
{
content
:
"\e02f"
}
#conversejs
.icon-remove
:before
{
content
:
"\e02d"
}
#conversejs
.icon-remove-2
:before
{
content
:
"\e02e"
}
#conversejs
.icon-eye
:before
{
content
:
"\e030"
}
#conversejs
.icon-eye-blocked
:before
{
content
:
"\e031"
}
#conversejs
.icon-attachment
:before
{
content
:
"\e032"
}
#conversejs
.icon-globe
:before
{
content
:
"\e033"
}
#conversejs
.icon-heart
:before
{
content
:
"\2764"
}
#conversejs
.icon-happy
:before
{
content
:
"\263b"
}
#conversejs
.icon-thumbs-up
:before
{
content
:
"\261d"
}
#conversejs
.icon-smiley
:before
{
content
:
"\263a"
}
#conversejs
.icon-tongue
:before
{
content
:
"\e038"
}
#conversejs
.icon-sad
:before
{
content
:
"\2639"
}
#conversejs
.icon-wink
:before
{
content
:
"\e03a"
}
#conversejs
.icon-wondering
:before
{
content
:
"\2369"
}
#conversejs
.icon-confused
:before
{
content
:
"\2368"
}
#conversejs
.icon-shocked
:before
{
content
:
"\2364"
}
#conversejs
.icon-evil
:before
{
content
:
"\261f"
}
#conversejs
.icon-angry
:before
{
content
:
"\e03f"
}
#conversejs
.icon-cool
:before
{
content
:
"\e040"
}
#conversejs
.icon-grin
:before
{
content
:
"\e041"
}
#conversejs
.icon-info
:before
{
content
:
"\2360"
}
#conversejs
.icon-notification
:before
{
content
:
"\e01f"
}
#conversejs
.icon-warning
:before
{
content
:
"\26a0"
}
#conversejs
.icon-spell-check
:before
{
content
:
"\e045"
}
#conversejs
.icon-volume-high
:before
{
content
:
"\e046"
}
#conversejs
.icon-volume-medium
:before
{
content
:
"\e047"
}
#conversejs
.icon-volume-low
:before
{
content
:
"\e048"
}
#conversejs
.icon-volume-mute
:before
{
content
:
"\e049"
}
#conversejs
.icon-volume-mute-2
:before
{
content
:
"\e04a"
}
#conversejs
.icon-volume-decrease
:before
{
content
:
"\e04b"
}
#conversejs
.icon-volume-increase
:before
{
content
:
"\e04c"
}
#conversejs
.icon-bold
:before
{
content
:
"\e04d"
}
#conversejs
.icon-underline
:before
{
content
:
"\e04e"
}
#conversejs
.icon-italic
:before
{
content
:
"\e04f"
}
#conversejs
.icon-strikethrough
:before
{
content
:
"\e050"
}
#conversejs
.icon-new-tab
:before
{
content
:
"\e053"
}
#conversejs
.icon-youtube
:before
{
content
:
"\e055"
}
#conversejs
.icon-close
:before
{
content
:
"\2715"
}
#conversejs
.icon-blocked
:before
{
content
:
"\2718"
}
#conversejs
.icon-cancel-circle
:before
{
content
:
"\e058"
}
#conversejs
.icon-minus
:before
{
content
:
"\e05a"
}
#conversejs
.icon-plus
:before
{
content
:
"\271a"
}
#conversejs
.icon-checkbox-checked
:before
{
content
:
"\2611"
}
#conversejs
.icon-checkbox-unchecked
:before
{
content
:
"\2b27"
}
#conversejs
.icon-checkbox-partial
:before
{
content
:
"\2b28"
}
#conversejs
.icon-radio-checked
:before
{
content
:
"\2b26"
}
#conversejs
.icon-radio-unchecked
:before
{
content
:
"\2b25"
}
#conversejs
.icon-room-info
:before
{
content
:
"\e059"
}
#conversejs
.icon-newspaper
:before
{
content
:
"\e001"
}
#conversejs
.icon-image
:before
{
content
:
"\2b14"
}
#conversejs
.icon-offline
:before
,
#conversejs
.icon-unavailable
:before
,
#conversejs
.icon-xa
:before
{
content
:
"\e002"
}
#conversejs
.icon-dnd
:before
{
content
:
"\e004"
}
#conversejs
.no-text-select
{
-webkit-touch-callout
:
none
;
-webkit-user-select
:
none
;
-khtml-user-select
:
none
;
-moz-user-select
:
-moz-none
;
-ms-user-select
:
none
;
user-select
:
none
}
#conversejs
{
bottom
:
1px
;
direction
:
ltr
;
height
:
25px
;
left
:
0
;
position
:
fixed
;
right
:
0
;
z-index
:
30
;
display
:
block
}
#conversejs
,
#conversejs
input
{
color
:
#4f4f4f
}
#conversejs
a
{
text-decoration
:
none
}
#conversejs
ol
,
#conversejs
ul
{
list-style
:
none
}
#conversejs
dl
,
#conversejs
ol
,
#conversejs
ul
{
border
:
0
;
font
:
inherit
;
margin
:
0
0
15px
;
padding
:
0
;
vertical-align
:
baseline
}
#conversejs
.emoticon
{
font-size
:
14px
}
#conversejs
.hidden
{
display
:
none
}
#conversejs
.locked
{
padding-right
:
22px
}
span
.spinner
{
background
:
url(images/spinner.gif)
no-repeat
center
;
height
:
22px
;
padding
:
0
2px
;
display
:
block
}
span
.spinner.centered
{
text-align
:
center
;
padding-top
:
5em
}
span
.spinner.hor_centered
{
text-align
:
center
}
#conversejs
#toggle-controlbox
{
float
:
right
;
font-size
:
85%
;
border-top-right-radius
:
4px
;
border-top-left-radius
:
4px
;
background-color
:
rgba
(
83
,
144
,
200
,
100
);
padding
:
4px
8px
;
margin-right
:
15px
;
color
:
#fff
}
#conversejs
#connecting-to-chat
{
background
:
url(images/spinner.gif)
no-repeat
left
;
padding-left
:
1.4em
}
#conversejs
.chat-head
{
color
:
#fff
;
margin
:
0
;
font-size
:
100%
;
border-top-right-radius
:
4px
;
border-top-left-radius
:
4px
;
padding
:
3px
0
0
3px
}
#conversejs
.chat-body
{
background-color
:
#fff
;
border-bottom-right-radius
:
4px
;
border-bottom-left-radius
:
4px
;
border-top
:
0
}
#conversejs
.chatbox
.chat-body
,
#conversejs
.chatroom
.chat-body
{
height
:
-moz-calc
(
100%
-
38px
);
height
:
-o-calc
(
100%
-
38px
);
height
:
calc
(
100%
-
38px
)}
#conversejs
.chatroom
.chat-area
{
float
:
left
;
width
:
200px
;
height
:
100%
}
#conversejs
.chatroom
.participants
{
float
:
left
;
height
:
100%
;
background-color
:
#fff
;
overflow
:
auto
;
border-left
:
1px
solid
#AAA
;
max-width
:
98px
;
border-bottom-right-radius
:
4px
}
#conversejs
.participants
ul
.participant-list
li
{
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
display
:
block
;
font-size
:
12px
;
font-weight
:
700
;
padding
:
.5em
0
0
.5em
;
cursor
:
default
}
#conversejs
ul
.participant-list
li
.moderator
{
color
:
#8f2831
}
#conversejs
.chatroom
.participant-list
{
list-style
:
none
}
#conversejs
.chat-blink
{
background-color
:
#176679
;
border-right
:
1px
solid
#176679
;
border-left
:
1px
solid
#176679
}
#conversejs
.chat-content
{
position
:
relative
;
padding
:
4px
;
font-size
:
13px
;
color
:
#4f4f4f
;
overflow-y
:
auto
;
border
:
0
;
background-color
:
#fff
;
line-height
:
1.3em
;
box-sizing
:
border-box
;
-moz-box-sizing
:
border-box
;
height
:
-moz-calc
(
100%
-
76px
);
height
:
-o-calc
(
100%
-
76px
);
height
:
calc
(
100%
-
76px
)}
#conversejs
.chat-error
{
color
:
#8f2831
}
#conversejs
.chat-message-me
,
#conversejs
.chat-message-room
,
#conversejs
.chat-message-them
{
font-weight
:
700
;
white-space
:
nowrap
;
max-width
:
100px
;
text-overflow
:
ellipsis
;
overflow
:
hidden
;
display
:
inline-block
;
float
:
left
;
padding-right
:
3px
}
#conversejs
.chat-message-content
{
word-wrap
:
break-word
}
#conversejs
.chat-message-them
{
color
:
#8f2831
}
#conversejs
.chat-message-me
{
color
:
#436976
}
#conversejs
.chat-message-room
{
color
:
#4B7003
}
#conversejs
.chat-date
,
#conversejs
.chat-event
,
#conversejs
.chat-info
{
color
:
gray
}
#conversejs
li
.chat-info
{
padding-left
:
10px
}
#conversejs
.chat-date
{
display
:
inline-block
;
padding-top
:
10px
}
#conversejs
p
.not-implemented
{
margin-top
:
3em
;
margin-left
:
.3em
;
color
:
gray
}
#conversejs
div
.delayed
.chat-message-them
{
color
:
#FB5D50
}
#conversejs
div
.delayed
.chat-message-me
{
color
:
#7EABBB
}
input
.error
{
border
:
1px
solid
red
}
#conversejs
.conn-feedback.error
{
color
:
red
}
#conversejs
.chat-message-error
{
color
:
#76797C
;
font-size
:
90%
;
font-weight
:
400
}
#conversejs
.chat-head
.avatar
{
float
:
left
;
margin-right
:
6px
}
#conversejs
div
.chat-title
{
color
:
#fff
;
font-weight
:
700
;
line-height
:
15px
;
display
:
block
;
margin-top
:
2px
;
margin-right
:
20px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
text-shadow
:
rgba
(
0
,
0
,
0
,
.51
)
0
-1px
0
;
height
:
1em
}
#conversejs
div
.chat-title
a
{
color
:
#fff
}
#conversejs
.chat-head-chatbox
,
#conversejs
.chat-head-chatroom
{
background
:
linear-gradient
(
top
,
rgba
(
206
,
220
,
231
,
1
)
0
,
rgba
(
79
,
106
,
114
,
1
)
100%
);
height
:
35px
;
position
:
relative
}
#conversejs
p
.chatroom-topic
,
#conversejs
p
.user-custom-message
{
font-size
:
80%
;
font-style
:
italic
;
height
:
1.3em
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
margin
:
0
}
#conversejs
div
.chat-head-chatbox
a
.user-custom-message
{
color
:
#fff
}
#conversejs
.activated
{
display
:
block
!important
}
#conversejs
a
.subscribe-to-user
{
padding-left
:
2em
;
font-weight
:
700
}
dl
.add-converse-contact
{
margin
:
0
0
0
.5em
}
#conversejs
.fancy-dropdown
{
border
:
1px
solid
#ddd
;
height
:
22px
}
#conversejs
.fancy-dropdown
a
.choose-xmpp-status
{
width
:
155px
}
#conversejs
.fancy-dropdown
a
.choose-xmpp-status
,
#conversejs
.fancy-dropdown
a
.toggle-xmpp-contact-form
{
text-shadow
:
0
1px
0
rgba
(
255
,
255
,
255
,
1
);
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
display
:
inline
}
#conversejs
.fancy-dropdown
a
.toggle-xmpp-contact-form
span
{
float
:
left
}
#conversejs
.choose-xmpp-status
span
{
padding-right
:
5px
;
padding-left
:
5px
;
float
:
left
}
#conversejs
#fancy-xmpp-status-select
a
.change-xmpp-status-message
{
float
:
right
;
clear
:
right
;
height
:
22px
;
width
:
12px
;
padding
:
0
5px
0
0
;
color
:
#4f4f4f
}
#conversejs
ul
#found-users
{
padding
:
10px
0
5px
5px
;
border
:
0
}
#conversejs
form
.search-xmpp-contact
{
margin
:
0
;
padding
:
0
0
5px
5px
}
#conversejs
form
.search-xmpp-contact
input
{
width
:
8em
}
#conversejs
.controlbox-head
{
margin
:
0
;
color
:
#FFF
;
border-top-right-radius
:
4px
;
border-top-left-radius
:
4px
;
height
:
35px
;
clear
:
right
;
background-color
:
#5390C8
;
padding
:
3px
0
0
}
#conversejs
.chat-head-message-count
{
font-weight
:
700
;
position
:
absolute
;
left
:
-6px
;
top
:
-6px
;
background
:
-webkit-gradient
(
linear
,
left
top
,
left
bottom
,
color-stop
(
0.35
,
#f6f6f6
),
color-stop
(
1
,
grey
));
background
:
-moz-linear-gradient
(
center
top
,
#ff0
5%
,
#f6f6f6
100%
);
filter
:
progid
:
DXImageTransform
.
Microsoft
.
gradient
(
startColorstr
=
'yellow'
,
endColorstr
=
'#f6f6f6'
);
border
:
3px
solid
#4f6a72
;
text-shadow
:
1px
1px
0
#ccc
;
color
:
#8b0000
;
border-radius
:
20%
;
padding
:
2px
10px
;
font-size
:
18px
;
text-align
:
center
;
display
:
none
}
#conversejs
.chat-head-chatroom
.chat-head-message-count
{
border
:
3px
solid
#2D617A
}
#conversejs
a
.close-chatbox-button
,
#conversejs
a
.configure-chatroom-button
,
#conversejs
a
.toggle-chatbox-button
{
font-size
:
10px
;
padding
:
3px
3px
2px
;
margin-right
:
3px
;
cursor
:
pointer
;
float
:
right
;
-moz-box-shadow
:
inset
0
1px
0
0
#fff
;
-webkit-box-shadow
:
inset
0
1px
0
0
#fff
;
box-shadow
:
inset
0
1px
0
0
#fff
;
background
:
-webkit-gradient
(
linear
,
left
top
,
left
bottom
,
color-stop
(
0.05
,
#fff
),
color-stop
(
1
,
#f6f6f6
));
background
:
-moz-linear-gradient
(
center
top
,
#fff
5%
,
#f6f6f6
100%
);
filter
:
progid
:
DXImageTransform
.
Microsoft
.
gradient
(
startColorstr
=
'#ffffff'
,
endColorstr
=
'#f6f6f6'
);
-moz-border-radius
:
6px
;
-webkit-border-radius
:
6px
;
border-radius
:
6px
;
border
:
1px
solid
#888
;
display
:
inline-block
;
color
:
#666
!important
;
text-decoration
:
none
;
text-shadow
:
1px
1px
0
#fff
}
#conversejs
a
.close-chatbox-button
:active
,
#conversejs
a
.configure-chatroom-button
:active
,
#conversejs
a
.toggle-chatbox-button
:active
{
position
:
relative
;
top
:
1px
}
#conversejs
.controlbox-pane
dt
{
margin
:
0
;
padding-top
:
.5em
}
#conversejs
.chatroom-form-container
{
height
:
100%
;
color
:
#666
;
overflow-y
:
auto
;
border-bottom-right-radius
:
4px
;
border-bottom-left-radius
:
4px
}
#conversejs
.chatroom-form
{
background
:
#fff
;
font-size
:
12px
;
padding
:
10px
5px
}
#conversejs
.chat-body
p
{
font-size
:
14px
;
color
:
#666
;
padding
:
5px
;
margin
:
0
}
#conversejs
.chatroom-form
legend
{
font-size
:
14px
;
font-weight
:
700
;
margin-bottom
:
5px
}
#conversejs
.chatroom-form
label
{
font-weight
:
700
;
display
:
block
;
clear
:
both
}
#conversejs
.chatroom-form
label
input
,
#conversejs
.chatroom-form
label
select
{
float
:
right
}
#conversejs
#converse-roster
dd
.odd
{
background-color
:
#DCEAC5
}
#conversejs
#converse-roster
dd
.current-xmpp-contact
{
clear
:
both
}
#conversejs
#converse-roster
dd
.current-xmpp-contact
span
{
font-size
:
16px
;
float
:
left
;
color
:
#4f4f4f
}
#conversejs
#converse-roster
dd
.requesting-xmpp-contact
button
{
margin-left
:
.5em
}
#conversejs
#converse-roster
dd
a
,
#conversejs
#converse-roster
dd
span
{
text-shadow
:
0
1px
0
rgba
(
250
,
250
,
250
,
1
);
display
:
inline-block
;
overflow
:
hidden
;
white-space
:
nowrap
;
text-overflow
:
ellipsis
}
#conversejs
#converse-roster
dd
span
{
padding
:
2px
5px
0
0
}
#conversejs
#converse-roster
{
overflow-y
:
auto
;
overflow-x
:
hidden
;
width
:
100%
;
position
:
relative
;
margin
:
.5em
0
0
;
height
:
-moz-calc
(
100%
-
70px
);
height
:
-o-calc
(
100%
-
70px
);
height
:
calc
(
100%
-
70px
)}
#conversejs
dd
.available-chatroom
{
overflow-x
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
width
:
175px
}
#conversejs
dd
.available-chatroom
a
.open-room
{
width
:
148px
}
#conversejs
#available-chatrooms
dt
,
#conversejs
#converse-roster
dt
{
font-weight
:
400
;
font-size
:
13px
;
color
:
#666
;
border
:
none
;
padding
:
.3em
0
0
.5em
;
text-shadow
:
0
1px
0
rgba
(
250
,
250
,
250
,
1
)}
#conversejs
#converse-roster
dt
{
display
:
none
}
#conversejs
#converse-roster
dd
,
#conversejs
dd
.available-chatroom
{
font-weight
:
700
;
border
:
none
;
display
:
block
;
padding
:
0
0
0
.5em
;
color
:
#666
;
text-shadow
:
0
1px
0
rgba
(
250
,
250
,
250
,
1
)}
#conversejs
.room-info
{
font-size
:
11px
;
font-style
:
normal
;
font-weight
:
400
}
#conversejs
li
.room-info
{
display
:
block
;
margin-left
:
5px
}
#conversejs
div
.room-info
{
clear
:
left
}
#conversejs
p
.room-info
{
margin
:
0
;
padding
:
0
;
display
:
block
;
white-space
:
normal
}
#conversejs
a
.room-info
{
width
:
22px
;
height
:
22px
;
float
:
right
;
display
:
none
;
clear
:
right
}
#conversejs
a
.open-room
{
float
:
left
;
white-space
:
nowrap
;
text-overflow
:
ellipsis
;
overflow-x
:
hidden
}
#conversejs
dd
.available-chatroom
:hover
a
.room-info
{
display
:
inline-block
;
margin-top
:
3px
;
font-size
:
15px
}
#conversejs
#converse-roster
dd
a
.remove-xmpp-contact
{
line-height
:
21px
;
float
:
right
;
width
:
22px
;
margin
:
0
;
display
:
none
;
color
:
#4f4f4f
}
#conversejs
#converse-roster
dd
:hover
a
.remove-xmpp-contact
{
display
:
inline-block
}
#conversejs
#converse-roster
a
.open-chat
{
line-height
:
21px
;
width
:
85%
}
#conversejs
#converse-roster
dd
.pending-xmpp-contact
:hover
span
,
#conversejs
#converse-roster
dd
:hover
a
.open-chat
{
width
:
70%
}
#conversejs
.chatbox
,
#conversejs
.chatroom
{
height
:
25px
;
float
:
right
;
margin-right
:
15px
;
display
:
block
}
#conversejs
.chatbox
{
width
:
200px
}
#conversejs
.chatroom
{
width
:
300px
}
#conversejs
.controlbox-pane
{
padding
:
0
;
border-bottom-right-radius
:
4px
;
border-bottom-left-radius
:
4px
}
#conversejs
.controlbox-pane
dd
{
margin-left
:
0
;
margin-bottom
:
0
;
padding
:
1em
}
#conversejs
.controlbox-pane
dd
.odd
{
background-color
:
#DCEAC5
}
#conversejs
form
#converse-login
{
background
:
#fff
;
padding
:
2em
0
.3em
.5em
}
#conversejs
form
#converse-login
input
{
display
:
block
;
width
:
90%
}
#conversejs
form
#converse-login
.login-submit
{
margin-top
:
1em
;
width
:
auto
}
#conversejs
form
.set-xmpp-status
{
background
:
0
0
;
margin
:
none
;
padding
:
none
}
#conversejs
form
.add-chatroom
{
background
:
0
0
;
padding
:
3px
}
#conversejs
form
.add-chatroom
input
[
type
=
text
]
{
width
:
95%
;
margin
:
3px
}
#conversejs
form
.add-chatroom
input
[
type
=
button
],
#conversejs
form
.add-chatroom
input
[
type
=
submit
]
{
width
:
48%
}
select
#select-xmpp-status
{
float
:
right
;
margin-right
:
.5em
}
#conversejs
.chat-head
#controlbox-tabs
{
text-align
:
center
;
display
:
inline
;
overflow
:
hidden
;
font-size
:
12px
;
list-style-type
:
none
}
#conversejs
.chat-head
#controlbox-tabs
li
{
float
:
left
;
list-style
:
none
;
padding-left
:
0
;
text-shadow
:
#fff
0
1px
0
;
width
:
38%
}
#conversejs
ul
#controlbox-tabs
li
a
{
display
:
block
;
font-size
:
12px
;
height
:
34px
;
line-height
:
34px
;
margin
:
0
;
text-align
:
center
;
text-decoration
:
none
;
border-top-right-radius
:
5px
;
border-top-left-radius
:
5px
;
color
:
#666
;
text-shadow
:
0
1px
0
rgba
(
250
,
250
,
250
,
1
)}
#conversejs
.chat-head
#controlbox-tabs
li
a
:hover
{
color
:
#000
}
#conversejs
.chat-head
#controlbox-tabs
li
a
{
background-color
:
#fff
;
box-shadow
:
inset
0
4px
12px
rgba
(
0
,
0
,
0
,
.3
);
border-bottom
:
1px
solid
#CCC
}
#conversejs
ul
#controlbox-tabs
a
.current
,
#conversejs
ul
#controlbox-tabs
a
.current
:hover
{
box-shadow
:
none
;
border-bottom
:
0
;
height
:
35px
;
cursor
:
default
;
color
:
#666
}
#conversejs
div
#chatrooms
,
#conversejs
div
#login-dialog
,
#conversejs
div
#settings
,
#conversejs
div
#users
{
border
:
0
;
font-size
:
14px
;
background-color
:
#fff
;
border-bottom-right-radius
:
4px
;
border-bottom-left-radius
:
4px
;
width
:
100%
;
height
:
-moz-calc
(
100%
-
38px
);
height
:
-o-calc
(
100%
-
38px
);
height
:
calc
(
100%
-
38px
);
overflow-y
:
hidden
;
position
:
absolute
}
#conversejs
div
#chatrooms
{
overflow-y
:
auto
}
#conversejs
form
.sendXMPPMessage
{
background
:
#fff
;
border
:
0
;
border-top
:
1px
solid
#BBB
;
padding
:
0
;
margin
:
0
;
position
:
relative
;
-webkit-border-radius
:
4px
;
-moz-border-radius
:
4px
;
border-radius
:
4px
;
-moz-background-clip
:
padding
;
-webkit-background-clip
:
padding-box
;
background-clip
:
padding-box
;
border-top-left-radius
:
0
;
border-top-right-radius
:
0
;
width
:
200px
;
height
:
75px
}
#conversejs
.chatroom
form
.sendXMPPMessage
{
-webkit-border-bottom-right-radius
:
0
;
border-bottom-right-radius
:
0
}
#conversejs
.chat-textarea
{
box-sizing
:
border-box
;
-moz-box-sizing
:
border-box
;
border
:
0
;
width
:
100%
;
padding
:
3px
;
border-radius
:
4px
;
resize
:
none
;
height
:
55px
}
#conversejs
ul
.chat-toolbar
{
font-size
:
14px
;
margin
:
0
;
padding
:
0
5px
0
0
;
width
:
195px
;
float
:
right
;
display
:
inline-block
;
height
:
20px
}
#conversejs
.chat-toolbar
.toggle-otr
{
float
:
right
}
#conversejs
.chat-toolbar
.toggle-call
,
#conversejs
.chat-toolbar
ul
li
a
{
color
:
#4f4f4f
}
#conversejs
.chat-toolbar
ul
li
a
:hover
{
color
:
#8f2831
}
#conversejs
.chat-toolbar
ul
{
display
:
none
;
font-size
:
12px
;
position
:
absolute
;
bottom
:
100%
;
margin-bottom
:
1px
;
right
:
0
;
background
:
#fff
;
box-shadow
:
0
-1px
2px
0
rgba
(
0
,
0
,
0
,
.4
)}
#conversejs
.chat-toolbar
ul
li
{
position
:
relative
;
list-style
:
none
;
cursor
:
pointer
}
#conversejs
.chat-toolbar
.toggle-smiley
{
padding-left
:
5px
}
#conversejs
.chat-toolbar
.toggle-smiley
ul
li
{
font-size
:
14px
;
padding
:
5px
;
z-index
:
98
}
#conversejs
.chat-toolbar
.toggle-otr
ul
li
{
background-color
:
#fff
;
display
:
block
;
z-index
:
99
}
#conversejs
.chat-toolbar
ul
li
:hover
{
background-color
:
#eee
}
#conversejs
.chat-toolbar
.toggle-otr
ul
li
a
{
transition
:
background-color
.2s
ease-in-out
;
-webkit-transition
:
background-color
.2s
ease-in-out
;
-moz-transition
:
background-color
.2s
ease-in-out
;
display
:
block
;
padding
:
1px
;
text-decoration
:
none
}
#conversejs
.chat-toolbar-text
{
font-size
:
12px
;
padding-right
:
3px
}
#conversejs
.unencrypted
,
#conversejs
.unencrypted
a
{
color
:
#8f2831
}
#conversejs
.unverified
,
#conversejs
.unverified
a
{
color
:
#cf5300
}
#conversejs
.private
,
#conversejs
.private
a
{
color
:
#4B7003
}
#conversejs
ul
.chat-toolbar
li
{
display
:
inline-block
;
list-style
:
none
;
padding
:
0
3px
;
cursor
:
pointer
;
margin-top
:
1px
}
#conversejs
ul
.chat-toolbar
li
:hover
{
cursor
:
pointer
}
#conversejs
form
#set-custom-xmpp-status
{
float
:
left
;
padding
:
0
}
#conversejs
.chat-textarea-chatbox-selected
{
border
:
1px
solid
#578308
;
margin
:
0
}
#conversejs
.chat-textarea-chatroom-selected
{
border
:
2px
solid
#2D617A
;
margin
:
0
}
#conversejs
#set-custom-xmpp-status
button
{
padding
:
1px
2px
1px
1px
}
#conversejs
#controlbox
{
display
:
none
}
#conversejs
#controlbox
div
.xmpp-status
{
display
:
inline
}
#conversejs
.chatbox
dl
.dropdown
{
margin
:
.5em
;
background-color
:
#f0f0f0
}
#conversejs
.chatbox
.dropdown
dd
,
#conversejs
.dropdown
dt
,
#conversejs
.dropdown
ul
{
margin
:
0
;
padding
:
0
}
#conversejs
.chatbox
.dropdown
dd
{
position
:
relative
}
input
.custom-xmpp-status
{
width
:
124px
}
#conversejs
form
.add-xmpp-contact
{
background
:
0
0
;
padding
:
5px
}
#conversejs
form
.add-xmpp-contact
input
{
width
:
108px
}
#conversejs
.chatbox
.dropdown
dt
a
span
{
cursor
:
pointer
;
display
:
block
;
padding
:
4px
7px
0
5px
;
color
:
#4f4f4f
}
#conversejs
.chatbox
.dropdown
dd
ul
{
padding
:
5px
0
;
list-style
:
none
;
position
:
absolute
;
left
:
0
;
top
:
0
;
border
:
1px
solid
#ddd
;
border-top
:
0
;
width
:
99%
;
z-index
:
21
;
background-color
:
#f0f0f0
}
#conversejs
.chatbox
.dropdown
li
{
list-style
:
none
;
padding-left
:
0
}
#conversejs
.chatbox
.dropdown
a
{
height
:
22px
;
width
:
148px
;
display
:
inline-block
;
line-height
:
24px
}
#conversejs
.chatbox
.dropdown
dd
ul
li
:hover
{
background-color
:
#bed6e5
}
#conversejs
.xmpp-status-menu
li
a
{
width
:
100%
}
#conversejs
.xmpp-status-menu
li
a
span
{
padding
:
0
5px
;
color
:
#4f4f4f
}
#conversejs
.set-xmpp-status
.dropdown
dd
ul
{
z-index
:
22
}
#conversejs
.box-flyout
{
background
:
#fff
;
position
:
absolute
;
display
:
block
;
bottom
:
1px
;
box-shadow
:
1px
1px
5px
1px
rgba
(
0
,
0
,
0
,
.4
);
border-radius
:
4px
;
height
:
324px
}
#conversejs
.box-flyout.minimized
{
height
:
auto
}
#conversejs
.chatbox
.box-flyout
{
width
:
200px
}
#conversejs
.chatroom
.box-flyout
{
width
:
300px
}
#conversejs
.dragresize
{
position
:
absolute
;
width
:
200px
;
height
:
5px
;
background
:
0
0
;
border
:
0
;
top
:
0
;
margin-left
:
0
;
cursor
:
n-resize
;
z-index
:
20
}
\ No newline at end of file
css/converse.css
View file @
24d58a5b
...
...
@@ -568,13 +568,7 @@ span.spinner.hor_centered {
margin-right
:
5px
;
color
:
white
;
}
#conversejs
#offscreen-chatboxes
{
float
:
left
;
height
:
25px
;
margin-left
:
5px
;
display
:
block
;
}
#conversejs
#offscreen-chatboxes
.box-flyout
{
#conversejs
#trimmed-chatboxes
.box-flyout
{
position
:
absolute
;
display
:
block
;
bottom
:
1px
;
...
...
@@ -582,15 +576,16 @@ span.spinner.hor_centered {
border-radius
:
4px
;
height
:
auto
;
}
#conversejs
#
offscreen
-chatboxes
.box-flyout
.chat-head
{
#conversejs
#
trimmed
-chatboxes
.box-flyout
.chat-head
{
font-size
:
100%
;
border-radius
:
4px
;
padding
:
3px
0
0
5px
;
margin
:
0
0
2px
2px
;
box-shadow
:
1px
3px
5px
3px
rgba
(
0
,
0
,
0
,
0.4
);
height
:
24px
;
width
:
130px
;
}
#conversejs
#
offscreen
-chatboxes
.chat-head-chatroom
{
#conversejs
#
trimmed
-chatboxes
.chat-head-chatroom
{
width
:
100px
;
}
#conversejs
#toggle-controlbox
{
...
...
@@ -745,10 +740,11 @@ input.error {
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
text-shadow
:
rgba
(
0
,
0
,
0
,
0.51
)
0
-1px
0
;
height
:
1em
;
}
#conversejs
.chat-title
a
{
color
:
white
;
width
:
100%
;
display
:
block
;
}
#conversejs
.chat-head-chatbox
,
#conversejs
.chat-head-chatroom
{
...
...
@@ -836,23 +832,20 @@ dl.add-converse-contact {
#conversejs
.chat-head-message-count
{
font-weight
:
bold
;
position
:
absolute
;
left
:
-
6
px
;
top
:
-6
px
;
left
:
-
5
px
;
top
:
2
px
;
background
:
-webkit-gradient
(
linear
,
left
top
,
left
bottom
,
color-stop
(
0.35
,
#f6f6f6
),
color-stop
(
1
,
#808080
));
background
:
-moz-linear-gradient
(
center
top
,
#ffff00
5%
,
#f6f6f6
100%
);
filter
:
progid
:
DXImageTransform
.
Microsoft
.
gradient
(
startColorstr
=
'yellow'
,
endColorstr
=
'#f6f6f6'
);
border
:
3px
solid
#4f6a72
;
border
:
1px
solid
;
text-shadow
:
1px
1px
0
#ccc
;
color
:
darkred
;
border-radius
:
20%
;
padding
:
2px
10
px
;
font-size
:
1
8
px
;
padding
:
2px
4
px
;
font-size
:
1
5
px
;
text-align
:
center
;
display
:
none
;
}
#conversejs
.chat-head-chatroom
.chat-head-message-count
{
border
:
3px
solid
#2D617A
;
}
#conversejs
a
.configure-chatroom-button
,
#conversejs
a
.toggle-chatbox-button
,
#conversejs
a
.close-chatbox-button
{
...
...
@@ -1040,6 +1033,7 @@ dl.add-converse-contact {
#conversejs
#converse-roster
dd
.pending-xmpp-contact
:hover
span
{
width
:
70%
;
}
#conversejs
#trimmed-chatboxes
,
#conversejs
.chatbox
,
#conversejs
.chatroom
{
height
:
25px
;
...
...
@@ -1047,6 +1041,9 @@ dl.add-converse-contact {
margin-right
:
15px
;
display
:
block
;
}
#conversejs
#trimmed-chatboxes
{
width
:
130px
;
}
#conversejs
.chatbox
{
width
:
200px
;
}
...
...
docs/CHANGES.rst
View file @
24d58a5b
...
...
@@ -9,6 +9,7 @@ Changelog
2. Configuration options for the chat toolbar have changed.
Please refer to the `relevant documentation http://devbox:8890/docs/html/index.html#visible-toolbar-buttons`_.
* No initial HTML markup is now needed in the document body for converse.js to work. [jcbrand]
* All date handling is now done with moment.js. [jcbrand]
* Add a new toolbar button for clearing chat messages. [jcbrand]
* Chat boxes and rooms can now be resized vertically. [jcbrand]
...
...
docs/source/index.rst
View file @
24d58a5b
...
...
@@ -52,13 +52,6 @@ bottom of your page (after the closing *</body>* element).
});
});
Finally, Converse.js requires a special snippet of HTML markup to be included in your page:
::
<div id="conversejs"></div>
The `index.html <https://github.com/jcbrand/converse.js/blob/master/index.html>`_ file inside the
Converse.js repository serves as a nice usable example of this.
...
...
index.html
View file @
24d58a5b
...
...
@@ -13,6 +13,11 @@
<link
type=
"text/css"
rel=
"stylesheet"
media=
"screen"
href=
"css/theme.css"
/>
<link
type=
"text/css"
rel=
"stylesheet"
media=
"screen"
href=
"css/converse.css"
/>
<script
data-main=
"main"
src=
"components/requirejs/require.js"
></script>
<script
src=
"../components/jquery/dist/jquery.min.js"
></script>
<script
src=
"http://netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js"
></script>
<script
src=
"http://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js"
></script>
<script
src=
"js/init.js"
></script>
</head>
<body
id=
"page-top"
data-spy=
"scroll"
data-target=
".navbar-custom"
>
...
...
@@ -209,15 +214,6 @@
</div>
</div>
</section>
<!-- Core JavaScript Files -->
<script
src=
"../components/jquery/dist/jquery.min.js"
></script>
<script
src=
"http://netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js"
></script>
<script
src=
"http://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js"
></script>
<!-- Custom Theme JavaScript -->
<script
src=
"js/init.js"
></script>
<div
id=
"conversejs"
></div>
</body>
<script
type=
"text/javascript"
>
...
...
less/converse.less
View file @
24d58a5b
...
...
@@ -598,14 +598,7 @@ span.spinner.hor_centered {
color: white;
}
#conversejs #offscreen-chatboxes {
float: left;
height: 25px;
margin-left: 5px;
display: block;
}
#conversejs #offscreen-chatboxes .box-flyout {
#conversejs #trimmed-chatboxes .box-flyout {
position: absolute;
display: block;
bottom: 1px;
...
...
@@ -614,16 +607,17 @@ span.spinner.hor_centered {
height: auto;
}
#conversejs #
offscreen
-chatboxes .box-flyout .chat-head {
#conversejs #
trimmed
-chatboxes .box-flyout .chat-head {
font-size: 100%;
border-radius: 4px;
padding: 3px 0 0 5px;
margin: 0 0 2px 2px;
box-shadow: 1px 3px 5px 3px rgba(0,0,0,0.4);
height: 24px;
width: 130px;
}
#conversejs #
offscreen
-chatboxes .chat-head-chatroom {
#conversejs #
trimmed
-chatboxes .chat-head-chatroom {
width: 100px;
}
...
...
@@ -808,11 +802,12 @@ input.error {
text-overflow: ellipsis;
white-space: nowrap;
text-shadow: rgba(0,0,0,0.51) 0 -1px 0;
height: 1em;
}
#conversejs .chat-title a {
color: white;
width: 100%;
display: block;
}
#conversejs .chat-head-chatbox,
...
...
@@ -916,25 +911,21 @@ dl.add-converse-contact {
#conversejs .chat-head-message-count {
font-weight: bold;
position: absolute;
left: -
6
px;
top:
-6
px;
left: -
5
px;
top:
2
px;
background: -webkit-gradient(linear, left top, left bottom, color-stop(0.35, #f6f6f6), color-stop(1, grey) );
background: -moz-linear-gradient(center top, yellow 5%, #f6f6f6 100%);
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='yellow', endColorstr='#f6f6f6');
border:
3px solid rgb(79, 106, 114)
;
border:
1px solid
;
text-shadow: 1px 1px 0 #ccc;
color: darkred;
border-radius: 20%;
padding: 2px
10
px;
font-size: 1
8
px;
padding: 2px
4
px;
font-size: 1
5
px;
text-align: center;
display: none;
}
#conversejs .chat-head-chatroom .chat-head-message-count {
border: 3px solid #2D617A;
}
#conversejs a.configure-chatroom-button,
#conversejs a.toggle-chatbox-button,
#conversejs a.close-chatbox-button {
...
...
@@ -1152,6 +1143,7 @@ dl.add-converse-contact {
width: 70%;
}
#conversejs #trimmed-chatboxes,
#conversejs .chatbox,
#conversejs .chatroom {
height: 25px;
...
...
@@ -1160,6 +1152,10 @@ dl.add-converse-contact {
display: block;
}
#conversejs #trimmed-chatboxes {
width: 130px;
}
#conversejs .chatbox {
width: 200px;
}
...
...
main.js
View file @
24d58a5b
...
...
@@ -8,6 +8,7 @@ config = {
"
underscore
"
:
"
components/underscore/underscore
"
,
"
backbone
"
:
"
components/backbone/backbone
"
,
"
backbone.localStorage
"
:
"
components/backbone.localStorage/backbone.localStorage
"
,
"
backbone.overview
"
:
"
components/backbone.overview/backbone.overview
"
,
"
text
"
:
'
components/requirejs-text/text
'
,
"
tpl
"
:
'
components/requirejs-tpl-jcbrand/tpl
'
,
"
converse-templates
"
:
"
src/templates
"
,
...
...
mockup/index.html
View file @
24d58a5b
...
...
@@ -373,27 +373,72 @@
</div>
</div>
<div
id=
"
offscreen
-chatboxes"
>
<div
id=
"
trimmed
-chatboxes"
>
<div
class=
"box-flyout"
>
<div
class=
"chat-head chat-head-chatroom"
>
<a
class=
"close-chatbox-button icon-close"
></a>
<div
class=
"chat-title"
>
Restricted Chatroom
</div>
<div
class=
"chat-title"
>
<a
href=
"#"
class=
"restore-chat"
title=
"Click to maximize this chat"
>
<div
class=
"chat-head-message-count"
style=
"display:block"
>
3
</div>
Restricted Chatroom
</a>
</div>
</div>
<div
class=
"chat-head chat-head-chatbox"
>
<a
class=
"close-chatbox-button icon-close"
></a>
<div
class=
"chat-title"
>
<a
href=
"http://opkode.com"
target=
"_blank"
class=
"user"
>
<a
href=
"#"
class=
"restore-chat"
title=
"Click to maximize this chat"
>
<div
class=
"chat-head-message-count"
style=
"display:block"
>
42
</div>
JC Brand
</a>
</div>
</div>
<div
class=
"chat-head chat-head-chatroom"
>
<a
class=
"close-chatbox-button icon-close"
></a>
<div
class=
"chat-title"
>
My Chatroom
</div>
<div
class=
"chat-title"
>
<a
href=
"#"
class=
"restore-chat"
title=
"Click to maximize this chat"
>
My Chatroom
</a>
</div>
</div>
<div
class=
"chat-head chat-head-chatbox"
><a
class=
"close-chatbox-button icon-close"
></a>
<div
class=
"chat-title"
>
<a
href=
"#"
class=
"restore-chat"
title=
"Click to maximize this chat"
>
Annegreet Gomez
</a>
</div>
</div>
<div
class=
"chat-head chat-head-chatbox"
><a
class=
"close-chatbox-button icon-close"
></a>
<div
class=
"chat-title"
>
<a
href=
"#"
class=
"restore-chat"
title=
"Click to maximize this chat"
>
<div
class=
"chat-head-message-count"
style=
"display:block"
>
842
</div>
Asmaa Haakman
</a>
</div>
</div>
<div
class=
"chat-head chat-head-chatbox"
><a
class=
"close-chatbox-button icon-close"
></a>
<div
class=
"chat-title"
>
<a
href=
"#"
class=
"restore-chat"
title=
"Click to maximize this chat"
>
Candice van der Knijff
</a>
</div>
</div>
<div
class=
"chat-head chat-head-chatbox"
><a
class=
"close-chatbox-button icon-close"
></a>
<div
class=
"chat-title"
>
<a
href=
"#"
class=
"restore-chat"
title=
"Click to maximize this chat"
>
Laura Grunewald
</a>
</div>
</div>
<div
class=
"chat-head chat-head-chatbox"
><a
class=
"close-chatbox-button icon-close"
></a>
<div
class=
"chat-title"
>
<a
href=
"#"
class=
"restore-chat"
>
Lena Grunewald
</a>
</div>
</div>
</div>
</div>
</div>
<script>
...
...
@@ -458,13 +503,7 @@ $(document).ready(function () {
$
(
'
.toggle-chatbox-button
'
).
click
(
function
(
ev
)
{
var
$grandparent
=
$
(
ev
.
target
).
parent
().
parent
().
parent
();
$grandparent
.
find
(
'
.chat-body
'
).
slideToggle
(
'
fast
'
);
var
flyout
=
$grandparent
.
find
(
'
.box-flyout
'
);
if
(
flyout
.
hasClass
(
'
minimized
'
))
{
flyout
.
removeClass
(
'
minimized
'
);
}
else
{
flyout
.
addClass
(
'
minimized
'
);
}
$grandparent
.
fadeOut
(
'
fast
'
);
});
// Clickable Dropdown
...
...
mockup/minimized.html
deleted
100644 → 0
View file @
a29a0293
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<title
id=
"pageTitle"
>
Converse.js: Mockup of minimized chats
</title>
<meta
charset=
"utf-8"
>
<meta
http-equiv=
"Content-Type"
content=
"text/html; charset=UTF-8"
>
<meta
name=
"description"
content=
"Converse.js: Chat Client for Websites"
/>
<link
type=
"text/css"
href=
"../css/theme.css"
rel=
"stylesheet"
media=
"screen"
/>
<link
type=
"text/css"
href=
"../css/converse.css"
rel=
"stylesheet"
media=
"screen"
/>
<script
src=
"../components/jquery/dist/jquery.min.js"
></script>
</head>
<body>
<!-- HEADER -->
<div
id=
"header_wrap"
class=
"outer"
>
<header
class=
"inner"
>
<h1
id=
"project_title"
><a
href=
"http://conversejs.org"
>
Converse.js
</a></h1>
<h2
id=
"project_tagline"
>
Static Mockup
</h2>
</header>
</div>
<div
id=
"conversejs"
>
<div
class=
"chatbox"
id=
"37c0c87392010303765fe36b05c0967d62c6b70f"
>
<div
class=
"box-flyout minimized"
>
<div
class=
"dragresize dragresize-tm"
></div>
<div
class=
"chat-head chat-head-chatbox"
>
<div
class=
"chat-head-message-count"
style=
"display:block"
>
3
</div>
<a
class=
"close-chatbox-button icon-close"
></a>
<a
class=
"toggle-chatbox-button icon-minus"
></a>
<canvas
height=
"31px"
width=
"31px"
class=
"avatar"
style=
"background-color: black"
></canvas>
<div
class=
"chat-title"
>
<a
href=
"http://opkode.com"
target=
"_blank"
class=
"user"
>
JC Brand
</a>
</div>
<p
class=
"user-custom-message"
title=
"10000ft in the air"
>
10000ft in the air
</p>
</div>
<div
class=
"chat-body"
style=
"display: none"
>
<div
class=
"chat-content"
>
<div
class=
"chat-info"
><strong>
/help
</strong>
:This is an info message
</div>
<div
class=
"chat-error"
>
This is an error message
</div>
<div
class=
"chat-message"
>
<span
class=
"chat-message-me"
>
09:35 me:
</span>
<span
class=
"chat-message-content"
>
Hello world
<span
class=
"icon-smiley"
></span>
</span>
</div>
<div
class=
"chat-message "
>
<span
class=
"chat-message-them"
>
19:25 Benedict-John:
</span>
<span
class=
"chat-message-content"
>
Dagsê
</span>
</div>
<div
class=
"chat-message"
>
<span
class=
"chat-message-me"
>
19:39 me:
</span>
<span
class=
"chat-message-content"
>
This is a relatively long message to check that wrapping works as expected.
</span>
</div>
<div
class=
"chat-message"
>
<span
class=
"chat-message-me"
>
19:42 me:
</span>
<span
class=
"chat-message-content"
>
Supercalifragilisticexpialidociousstillnotlongenough
</span>
</div>
<div
class=
"chat-event"
>
JC Brand is busy
</div>
<div
class=
"chat-message "
>
<span
class=
"chat-message-me"
>
19:43 me:
</span>
<span
class=
"chat-message-content"
>
Another message to check that scrolling works.
</span>
</div>
</div>
<form
class=
"sendXMPPMessage"
action=
""
method=
"post"
>
<ul
class=
"chat-toolbar no-text-select"
>
<li
class=
"toggle-smiley icon-happy"
title=
"Insert a smilery"
>
<ul>
<li><a
class=
"icon-smiley"
href=
"#"
data-emoticon=
":)"
></a></li>
<li><a
class=
"icon-wink"
href=
"#"
data-emoticon=
";)"
></a></li>
<li><a
class=
"icon-grin"
href=
"#"
data-emoticon=
":D"
></a></li>
<li><a
class=
"icon-tongue"
href=
"#"
data-emoticon=
":P"
></a></li>
<li><a
class=
"icon-cool"
href=
"#"
data-emoticon=
"8)"
></a></li>
<li><a
class=
"icon-evil"
href=
"#"
data-emoticon=
">:)"
></a></li>
<li><a
class=
"icon-confused"
href=
"#"
data-emoticon=
":S"
></a></li>
<li><a
class=
"icon-wondering"
href=
"#"
data-emoticon=
":\"
></a></li>
<li><a
class=
"icon-angry"
href=
"#"
data-emoticon=
">:("
></a></li>
<li><a
class=
"icon-sad"
href=
"#"
data-emoticon=
":("
></a></li>
<li><a
class=
"icon-shocked"
href=
"#"
data-emoticon=
":O"
></a></li>
<li><a
class=
"icon-thumbs-up"
href=
"#"
data-emoticon=
"(^.^)b"
></a></li>
<li><a
class=
"icon-heart"
href=
"#"
data-emoticon=
"<3"
></a></li>
</ul>
</li>
<li
class=
"toggle-otr unencrypted"
title=
"Turn on 'off-the-record' chat encryption"
>
<span
class=
"chat-toolbar-text"
>
unencrypted
</span>
<span
class=
"icon-unlocked"
></span>
<ul>
<li><a
href=
"#"
>
Start private conversation
</a></li>
<li><a
href=
"#"
>
End private conversation
</a></li>
<li><a
href=
"#"
>
Authenticate buddy
</a></li>
<li><a
href=
"http://www.cypherpunks.ca/otr/help/3.2.0/levels.php"
target=
"_blank"
>
What's this?
</a></li>
</ul>
</li>
</ul>
<textarea
type=
"text"
class=
"chat-textarea"
placeholder=
"Personal message"
></textarea>
</form>
</div>
</div>
</div>
<div
class=
"chatroom"
id=
"4a77380f1cd9d392627b0e1469688f9ca44e9392"
>
<div
class=
"box-flyout minimized"
>
<div
class=
"dragresize dragresize-tm"
></div>
<div
class=
"chat-head chat-head-chatroom"
>
<div
class=
"chat-head-message-count"
style=
"display:block"
>
42
</div>
<a
class=
"close-chatbox-button icon-close"
></a>
<a
class=
"toggle-chatbox-button icon-minus"
></a>
<a
class=
"configure-chatroom-button icon-wrench"
style=
""
></a>
<div
class=
"chat-title"
>
Chatroom
</div>
<p
class=
"chatroom-topic"
>
May the force be with you
</p>
</div>
<div
class=
"chat-body"
style=
"display: none"
>
<div
class=
"chat-area"
>
<div
class=
"chat-content"
>
<time
class=
"chat-date"
datetime=
"2013-06-04T00:00:00.000Z"
>
Tue Jun 04 2013
</time>
<div
class=
"chat-message "
>
<span
class=
"chat-message-room"
>
18:50 luke:
</span>
<span
class=
"chat-message-content"
>
leia: hi :)
</span>
</div>
<div
class=
"chat-message "
>
<span
class=
"chat-message-room"
>
19:40 leia:
</span>
<span
class=
"chat-message-content"
>
I'll be gone for a while, will be back in about an hour
</span>
</div>
<div
class=
"chat-message "
>
<span
class=
"chat-message-room"
>
19:40 Obi-wan Kenobi, Jedi Master:
</span>
<span
class=
"chat-message-content"
>
I'll be gone for a while, will be back in about an hour
</span>
</div>
<div
class=
"chat-message"
>
<span
class=
"chat-message-me"
>
19:42 me:
</span>
<span
class=
"chat-message-content"
>
Supercalifragilisticexpialidociousstillnotlongenough
</span>
</div>
<div
class=
"chat-message "
>
<span
class=
"chat-message-room"
>
19:43 Obi-wan Kenobi, Jedi Master:
</span>
<span
class=
"chat-message-content"
>
Another message to check that scrolling works.
</span>
</div>
</div>
<form
class=
"sendXMPPMessage"
action=
""
method=
"post"
>
<ul
class=
"chat-toolbar no-text-select"
>
<li
class=
"toggle-smiley icon-happy"
title=
"Insert a smilery"
>
<ul>
<li><a
class=
"icon-smiley"
href=
"#"
data-emoticon=
":)"
></a></li>
<li><a
class=
"icon-wink"
href=
"#"
data-emoticon=
";)"
></a></li>
<li><a
class=
"icon-grin"
href=
"#"
data-emoticon=
":D"
></a></li>
<li><a
class=
"icon-tongue"
href=
"#"
data-emoticon=
":P"
></a></li>
<li><a
class=
"icon-cool"
href=
"#"
data-emoticon=
"8)"
></a></li>
<li><a
class=
"icon-evil"
href=
"#"
data-emoticon=
">:)"
></a></li>
<li><a
class=
"icon-confused"
href=
"#"
data-emoticon=
":S"
></a></li>
<li><a
class=
"icon-wondering"
href=
"#"
data-emoticon=
":\"
></a></li>
<li><a
class=
"icon-angry"
href=
"#"
data-emoticon=
">:("
></a></li>
<li><a
class=
"icon-sad"
href=
"#"
data-emoticon=
":("
></a></li>
<li><a
class=
"icon-shocked"
href=
"#"
data-emoticon=
":O"
></a></li>
<li><a
class=
"icon-thumbs-up"
href=
"#"
data-emoticon=
"(^.^)b"
></a></li>
<li><a
class=
"icon-heart"
href=
"#"
data-emoticon=
"<3"
></a></li>
</ul>
</li>
</ul>
<textarea
type=
"text"
class=
"chat-textarea"
placeholder=
"Message"
></textarea>
</form>
</div>
<div
class=
"participants"
>
<ul
class=
"participant-list"
>
<li
class=
"participant"
title=
"This user can send messages in this room"
>
Obi-wan Kenobi, Jedi Master
</li>
<li
class=
"participant"
title=
"This user can send messages in this room"
>
jabber the hut
</li>
<li
class=
"participant"
title=
"This user can send messages in this room"
>
leia
</li>
<li
class=
"moderator"
title=
"This user is a moderator"
>
luke
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<script>
$
(
document
).
ready
(
function
()
{
$
(
'
a[href=#chatrooms]
'
).
click
(
function
(
ev
)
{
switchTab
(
ev
);
});
$
(
'
a[href=#users]
'
).
click
(
function
(
ev
)
{
switchTab
(
ev
);
});
$
(
"
a.choose-xmpp-status
"
).
click
(
function
(
ev
)
{
ev
.
preventDefault
();
$
(
ev
.
target
).
parent
().
parent
().
siblings
(
'
dd
'
).
find
(
'
ul
'
).
toggle
(
'
fast
'
);
});
$
(
"
a.change-xmpp-status-message
"
).
click
(
function
(
ev
)
{
ev
.
preventDefault
();
var
form
=
''
+
'
<form id="set-custom-xmpp-status">
'
+
'
<input type="text" class="custom-xmpp-status"I am online"
'
+
'
placeholder="I am online"/>
'
+
'
<button type="submit">Save</button>
'
+
'
</form>
'
;
$
(
ev
.
target
).
closest
(
'
.xmpp-status
'
).
replaceWith
(
form
);
$
(
ev
.
target
).
closest
(
'
.custom-xmpp-status
'
).
focus
().
focus
();
});
$
(
'
.toggle-xmpp-contact-form
'
).
click
(
function
(
ev
)
{
ev
.
preventDefault
();
$
(
ev
.
target
).
parent
().
parent
().
find
(
'
.search-xmpp
'
).
toggle
(
'
fast
'
,
function
()
{
if
(
$
(
this
).
is
(
'
:visible
'
))
{
$
(
this
).
find
(
'
input.username
'
).
focus
();
}
});
});
var
switchTab
=
function
(
ev
)
{
ev
.
preventDefault
();
var
$tab
=
$
(
ev
.
target
),
$sibling
=
$tab
.
parent
().
siblings
(
'
li
'
).
children
(
'
a
'
),
$tab_panel
=
$
(
$tab
.
attr
(
'
href
'
)),
$sibling_panel
=
$
(
$sibling
.
attr
(
'
href
'
));
$sibling_panel
.
fadeOut
(
'
fast
'
,
function
()
{
$sibling
.
removeClass
(
'
current
'
);
$tab
.
addClass
(
'
current
'
);
$tab_panel
.
fadeIn
(
'
fast
'
,
function
()
{
});
});
}
$
(
function
()
{
$
(
'
.close-chatbox-button
'
).
click
(
function
(
ev
)
{
var
$grandparent
=
$
(
ev
.
target
).
parent
().
parent
().
parent
();
$grandparent
.
hide
(
300
,
function
()
{
// Webkit fix
document
.
getElementById
(
'
conversejs
'
).
style
.
display
=
'
none
'
;
document
.
getElementById
(
'
conversejs
'
).
offsetHeight
;
// no need to store this anywhere, the reference is enough
document
.
getElementById
(
'
conversejs
'
).
style
.
display
=
'
block
'
;
});
});
$
(
'
.toggle-chatbox-button
'
).
click
(
function
(
ev
)
{
var
$grandparent
=
$
(
ev
.
target
).
parent
().
parent
().
parent
();
$grandparent
.
find
(
'
.chat-body
'
).
slideToggle
(
300
);
var
flyout
=
$grandparent
.
find
(
'
.box-flyout
'
);
if
(
flyout
.
hasClass
(
'
minimized
'
))
{
flyout
.
removeClass
(
'
minimized
'
);
}
else
{
flyout
.
addClass
(
'
minimized
'
);
}
});
// Clickable Dropdown
$
(
'
.toggle-otr
'
).
click
(
function
(
e
)
{
$
(
'
.toggle-otr ul
'
).
slideToggle
(
200
);
e
.
stopPropagation
();
});
$
(
'
.toggle-smiley
'
).
click
(
function
(
e
)
{
$
(
e
.
target
).
find
(
'
ul
'
).
slideToggle
(
200
);
e
.
stopPropagation
();
});
$
(
document
).
click
(
function
()
{
if
(
$
(
'
.toggle-otr ul
'
).
is
(
'
:visible
'
))
{
$
(
'
.toggle-otr ul
'
,
this
).
slideUp
(
200
);
}
if
(
$
(
'
.toggle-smiley ul
'
).
is
(
'
:visible
'
))
{
$
(
'
.toggle-smiley ul
'
,
this
).
slideUp
(
200
);
}
});
});
});
</script>
</html>
spec/chatbox.js
View file @
24d58a5b
...
...
@@ -30,11 +30,12 @@
});
it
(
"
is created when you click on a roster item
"
,
$
.
proxy
(
function
()
{
var
i
,
$el
,
click
,
jid
,
view
;
var
i
,
$el
,
click
,
jid
,
view
,
chatboxview
;
// openControlBox was called earlier, so the controlbox is
// visible, but no other chat boxes have been created.
expect
(
this
.
chatboxes
.
length
).
toEqual
(
1
);
spyOn
(
this
.
chatboxviews
,
'
trimOpenChats
'
);
spyOn
(
this
.
chatboxviews
,
'
trimChats
'
);
expect
(
$
(
"
#conversejs .chatbox
"
).
length
).
toBe
(
1
);
// Controlbox is open
var
online_contacts
=
this
.
rosterview
.
$el
.
find
(
'
dt#xmpp-contacts
'
).
siblings
(
'
dd.current-xmpp-contact
'
).
find
(
'
a.open-chat
'
);
for
(
i
=
0
;
i
<
online_contacts
.
length
;
i
++
)
{
...
...
@@ -44,9 +45,59 @@
spyOn
(
view
,
'
openChat
'
).
andCallThrough
();
view
.
delegateEvents
();
// We need to rebind all events otherwise our spy won't be called
$el
.
click
();
chatboxview
=
this
.
chatboxviews
.
get
(
jid
);
expect
(
view
.
openChat
).
toHaveBeenCalled
();
expect
(
this
.
chatboxes
.
length
).
toEqual
(
i
+
2
);
expect
(
this
.
chatboxviews
.
trimOpenChats
).
toHaveBeenCalled
();
expect
(
this
.
chatboxviews
.
trimChats
).
toHaveBeenCalled
();
// Check that new chat boxes are created to the left of the
// controlbox (but to the right of all existing chat boxes)
expect
(
$
(
"
#conversejs .chatbox
"
).
length
).
toBe
(
i
+
2
);
expect
(
$
(
"
#conversejs .chatbox
"
)[
1
].
id
).
toBe
(
chatboxview
.
model
.
get
(
'
box_id
'
));
}
},
converse
));
it
(
"
can be trimmed to conserve space
"
,
$
.
proxy
(
function
()
{
var
i
,
$el
,
click
,
jid
,
key
,
view
,
chatboxview
;
// openControlBox was called earlier, so the controlbox is
// visible, but no other chat boxes have been created.
var
trimmed_chatboxes
=
converse
.
chatboxviews
.
trimmed_chatboxes_view
;
expect
(
this
.
chatboxes
.
length
).
toEqual
(
1
);
spyOn
(
this
.
chatboxviews
,
'
trimChats
'
);
spyOn
(
trimmed_chatboxes
,
'
onChanged
'
).
andCallThrough
();
expect
(
$
(
"
#conversejs .chatbox
"
).
length
).
toBe
(
1
);
// Controlbox is open
// Test that they can be trimmed
var
online_contacts
=
this
.
rosterview
.
$el
.
find
(
'
dt#xmpp-contacts
'
).
siblings
(
'
dd.current-xmpp-contact
'
).
find
(
'
a.open-chat
'
);
for
(
i
=
0
;
i
<
online_contacts
.
length
;
i
++
)
{
$el
=
$
(
online_contacts
[
i
]);
jid
=
$el
.
text
().
replace
(
'
'
,
'
.
'
).
toLowerCase
()
+
'
@localhost
'
;
view
=
this
.
rosterview
.
get
(
jid
);
view
.
delegateEvents
();
// We need to rebind all events otherwise our spy won't be called
$el
.
click
();
expect
(
this
.
chatboxviews
.
trimChats
).
toHaveBeenCalled
();
chatboxview
=
this
.
chatboxviews
.
get
(
jid
);
spyOn
(
chatboxview
,
'
hide
'
).
andCallThrough
();
chatboxview
.
model
.
set
({
'
minimized
'
:
true
});
expect
(
trimmed_chatboxes
.
onChanged
).
toHaveBeenCalled
();
expect
(
chatboxview
.
hide
).
toHaveBeenCalled
();
trimmedview
=
trimmed_chatboxes
.
get
(
jid
);
expect
(
trimmedview
.
$el
.
is
(
"
:visible
"
)).
toBeTruthy
();
}
// Test that they can be maximized again
var
chatboxviews
=
this
.
chatboxviews
.
getAll
();
var
keys
=
_
.
keys
(
chatboxviews
);
for
(
i
=
0
;
i
<
keys
.
length
;
i
++
)
{
key
=
keys
[
i
];
if
(
key
===
'
controlbox
'
)
{
continue
;
}
chatboxview
=
chatboxviews
[
key
];
trimmedview
=
trimmed_chatboxes
.
get
(
key
);
spyOn
(
chatboxview
,
'
maximize
'
).
andCallThrough
();
trimmedview
.
$
(
"
a.restore-chat
"
).
click
();
expect
(
trimmed_chatboxes
.
onChanged
).
toHaveBeenCalled
();
expect
(
chatboxview
.
maximize
).
toHaveBeenCalled
();
}
},
converse
));
...
...
@@ -72,14 +123,14 @@
it
(
"
can be saved to, and retrieved from, localStorage
"
,
$
.
proxy
(
function
()
{
spyOn
(
converse
,
'
emit
'
);
spyOn
(
this
.
chatboxviews
,
'
trim
Open
Chats
'
);
spyOn
(
this
.
chatboxviews
,
'
trimChats
'
);
runs
(
function
()
{
utils
.
openControlBox
();
});
waits
(
250
);
runs
(
function
()
{
utils
.
openChatBoxes
(
6
);
expect
(
this
.
chatboxviews
.
trim
Open
Chats
).
toHaveBeenCalled
();
expect
(
this
.
chatboxviews
.
trimChats
).
toHaveBeenCalled
();
// We instantiate a new ChatBoxes collection, which by default
// will be empty.
var
newchatboxes
=
new
this
.
ChatBoxes
();
...
...
@@ -104,8 +155,8 @@
var
chatbox
=
utils
.
openChatBoxes
(
1
)[
0
],
controlview
=
this
.
chatboxviews
.
get
(
'
controlbox
'
),
// The controlbox is currently open
chatview
=
this
.
chatboxviews
.
get
(
chatbox
.
get
(
'
jid
'
));
spyOn
(
chatview
,
'
close
Chat
'
).
andCallThrough
();
spyOn
(
controlview
,
'
close
Chat
'
).
andCallThrough
();
spyOn
(
chatview
,
'
close
'
).
andCallThrough
();
spyOn
(
controlview
,
'
close
'
).
andCallThrough
();
spyOn
(
converse
,
'
emit
'
);
// We need to rebind all events otherwise our spy won't be called
...
...
@@ -117,56 +168,60 @@
});
waits
(
250
);
runs
(
function
()
{
expect
(
controlview
.
close
Chat
).
toHaveBeenCalled
();
expect
(
controlview
.
close
).
toHaveBeenCalled
();
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxClosed
'
,
jasmine
.
any
(
Object
));
expect
(
converse
.
emit
.
callCount
,
1
);
chatview
.
$el
.
find
(
'
.close-chatbox-button
'
).
click
();
});
waits
(
250
);
runs
(
function
()
{
expect
(
chatview
.
close
Chat
).
toHaveBeenCalled
();
expect
(
chatview
.
close
).
toHaveBeenCalled
();
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxClosed
'
,
jasmine
.
any
(
Object
));
expect
(
converse
.
emit
.
callCount
,
2
);
});
},
converse
));
it
(
"
can be
toggl
ed by clicking a DOM element with class 'toggle-chatbox-button'
"
,
function
()
{
it
(
"
can be
minimiz
ed by clicking a DOM element with class 'toggle-chatbox-button'
"
,
function
()
{
var
chatbox
=
utils
.
openChatBoxes
(
1
)[
0
],
chatview
=
this
.
chatboxviews
.
get
(
chatbox
.
get
(
'
jid
'
));
spyOn
(
chatview
,
'
toggleChatBox
'
).
andCallThrough
();
chatview
=
this
.
chatboxviews
.
get
(
chatbox
.
get
(
'
jid
'
)),
trimmed_chatboxes
=
this
.
chatboxviews
.
trimmed_chatboxes_view
;
spyOn
(
chatview
,
'
maximize
'
).
andCallThrough
();
spyOn
(
chatview
,
'
minimize
'
).
andCallThrough
();
spyOn
(
converse
,
'
emit
'
);
spyOn
(
trimmed_chatboxes
,
'
onChanged
'
).
andCallThrough
();
// We need to rebind all events otherwise our spy won't be called
chatview
.
delegateEvents
();
runs
(
function
()
{
chatview
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
click
();
});
waits
(
2
50
);
waits
(
50
);
runs
(
function
()
{
expect
(
chatview
.
toggleChatBox
).
toHaveBeenCalled
();
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBox
Toggl
ed
'
,
jasmine
.
any
(
Object
));
expect
(
chatview
.
minimize
).
toHaveBeenCalled
();
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBox
Minimiz
ed
'
,
jasmine
.
any
(
Object
));
expect
(
converse
.
emit
.
callCount
,
2
);
expect
(
chatview
.
$el
.
find
(
'
.chat-body
'
).
is
(
'
:visible
'
)).
toBeFalsy
();
expect
(
chatview
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
hasClass
(
'
icon-minus
'
)).
toBeFalsy
();
expect
(
chatview
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
hasClass
(
'
icon-plus
'
)).
toBeTruthy
();
expect
(
chatview
.
$el
.
is
(
'
:visible
'
)).
toBeFalsy
();
expect
(
chatview
.
model
.
get
(
'
minimized
'
)).
toBeTruthy
();
chatview
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
click
();
trimmedview
=
trimmed_chatboxes
.
get
(
chatview
.
model
.
get
(
'
id
'
));
trimmedview
.
$
(
"
a.restore-chat
"
).
click
();
});
waits
(
2
50
);
waits
(
50
);
runs
(
function
()
{
expect
(
chatview
.
toggleChatBox
).
toHaveBeenCalled
();
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxToggled
'
,
jasmine
.
any
(
Object
));
expect
(
trimmed_chatboxes
.
onChanged
).
toHaveBeenCalled
();
expect
(
chatview
.
maximize
).
toHaveBeenCalled
();
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxMaximized
'
,
jasmine
.
any
(
Object
));
expect
(
chatview
.
$el
.
find
(
'
.chat-body
'
).
is
(
'
:visible
'
)).
toBeTruthy
();
expect
(
chatview
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
hasClass
(
'
icon-minus
'
)).
toBeTruthy
();
expect
(
chatview
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
hasClass
(
'
icon-plus
'
)).
toBeFalsy
();
expect
(
chatview
.
model
.
get
(
'
minimized
'
)).
toBeFalsy
();
expect
(
converse
.
emit
.
callCount
,
3
);
});
}.
bind
(
converse
));
it
(
"
will be removed from localStorage when closed
"
,
$
.
proxy
(
function
()
{
spyOn
(
converse
,
'
emit
'
);
spyOn
(
converse
.
chatboxviews
,
'
trim
Open
Chats
'
);
spyOn
(
converse
.
chatboxviews
,
'
trimChats
'
);
this
.
chatboxes
.
localStorage
.
_clear
();
runs
(
function
()
{
utils
.
closeControlBox
();
...
...
@@ -176,7 +231,7 @@
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxClosed
'
,
jasmine
.
any
(
Object
));
expect
(
converse
.
chatboxes
.
length
).
toEqual
(
0
);
utils
.
openChatBoxes
(
6
);
expect
(
converse
.
chatboxviews
.
trim
Open
Chats
).
toHaveBeenCalled
();
expect
(
converse
.
chatboxviews
.
trimChats
).
toHaveBeenCalled
();
expect
(
converse
.
chatboxes
.
length
).
toEqual
(
6
);
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxOpened
'
,
jasmine
.
any
(
Object
));
utils
.
closeAllChatBoxes
();
...
...
@@ -303,7 +358,7 @@
$toolbar
=
view
.
$el
.
find
(
'
ul.chat-toolbar
'
);
callButton
=
$toolbar
.
find
(
'
.toggle-call
'
);
expect
(
callButton
.
length
).
toBe
(
0
);
view
.
close
Chat
();
view
.
close
();
// Now check that it's shown if enabled and that it emits
// onCallButtonClicked
converse
.
visible_toolbar_buttons
.
call
=
true
;
// enable the button
...
...
@@ -328,7 +383,7 @@
$toolbar
=
view
.
$el
.
find
(
'
ul.chat-toolbar
'
);
clearButton
=
$toolbar
.
find
(
'
.toggle-clear
'
);
expect
(
clearButton
.
length
).
toBe
(
0
);
view
.
close
Chat
();
view
.
close
();
// Now check that it's shown if enabled and that it calls
// clearMessages
converse
.
visible_toolbar_buttons
.
clear
=
true
;
// enable the button
...
...
@@ -409,13 +464,13 @@
runs
(
function
()
{
utils
.
openChatBoxFor
(
contact_jid
);
});
waits
(
2
50
);
waits
(
50
);
runs
(
function
()
{
var
chatview
=
converse
.
chatboxviews
.
get
(
contact_jid
);
expect
(
chatview
.
model
.
get
(
'
minimized
'
)).
toBeFalsy
();
chatview
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
click
();
});
waits
(
2
50
);
waits
(
50
);
runs
(
$
.
proxy
(
function
()
{
var
chatview
=
this
.
chatboxviews
.
get
(
contact_jid
);
expect
(
chatview
.
model
.
get
(
'
minimized
'
)).
toBeTruthy
();
...
...
@@ -431,11 +486,12 @@
this
.
chatboxes
.
onMessage
(
msg
);
expect
(
this
.
emit
).
toHaveBeenCalledWith
(
'
onMessage
'
,
msg
);
},
converse
));
waits
(
2
50
);
waits
(
50
);
runs
(
$
.
proxy
(
function
()
{
var
chatview
=
this
.
chatboxviews
.
get
(
contact_jid
);
var
$count
=
chatview
.
$el
.
find
(
'
.chat-head-message-count
'
);
expect
(
chatview
.
model
.
get
(
'
minimized
'
)).
toBeTruthy
();
var
trimmed_chatboxes
=
this
.
chatboxviews
.
trimmed_chatboxes_view
;
var
trimmedview
=
trimmed_chatboxes
.
get
(
contact_jid
);
var
$count
=
trimmedview
.
$el
.
find
(
'
.chat-head-message-count
'
);
expect
(
trimmedview
.
model
.
get
(
'
minimized
'
)).
toBeTruthy
();
expect
(
$count
.
is
(
'
:visible
'
)).
toBeTruthy
();
expect
(
$count
.
data
(
'
count
'
)).
toBe
(
1
);
expect
(
$count
.
html
()).
toBe
(
'
1
'
);
...
...
@@ -449,23 +505,25 @@
.
c
(
'
active
'
,
{
'
xmlns
'
:
'
http://jabber.org/protocol/chatstates
'
}).
tree
()
);
},
converse
));
waits
(
10
0
);
waits
(
5
0
);
runs
(
$
.
proxy
(
function
()
{
var
chatview
=
this
.
chatboxviews
.
get
(
contact_jid
);
var
$count
=
chatview
.
$el
.
find
(
'
.chat-head-message-count
'
);
expect
(
chatview
.
model
.
get
(
'
minimized
'
)).
toBeTruthy
();
var
trimmed_chatboxes
=
this
.
chatboxviews
.
trimmed_chatboxes_view
;
var
trimmedview
=
trimmed_chatboxes
.
get
(
contact_jid
);
var
$count
=
trimmedview
.
$el
.
find
(
'
.chat-head-message-count
'
);
expect
(
trimmedview
.
model
.
get
(
'
minimized
'
)).
toBeTruthy
();
expect
(
$count
.
is
(
'
:visible
'
)).
toBeTruthy
();
expect
(
$count
.
data
(
'
count
'
)).
toBe
(
2
);
expect
(
$count
.
html
()).
toBe
(
'
2
'
);
chatview
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
click
();
trimmedview
.
$el
.
find
(
'
.restore-chat
'
).
click
();
},
converse
));
waits
(
2
50
);
waits
(
50
);
runs
(
$
.
proxy
(
function
()
{
var
chatview
=
this
.
chatboxviews
.
get
(
contact_jid
);
var
$count
=
chatview
.
$el
.
find
(
'
.chat-head-message-count
'
);
expect
(
chatview
.
model
.
get
(
'
minimized
'
)).
toBeFalsy
();
var
trimmed_chatboxes
=
this
.
chatboxviews
.
trimmed_chatboxes_view
;
var
trimmedview
=
trimmed_chatboxes
.
get
(
contact_jid
);
var
$count
=
trimmedview
.
$el
.
find
(
'
.chat-head-message-count
'
);
expect
(
trimmedview
.
model
.
get
(
'
minimized
'
)).
toBeFalsy
();
expect
(
$count
.
is
(
'
:visible
'
)).
toBeFalsy
();
expect
(
$count
.
data
(
'
count
'
)).
toBe
(
0
);
expect
(
$count
.
data
(
'
count
'
)).
toBe
Falsy
(
);
expect
(
$count
.
html
()).
toBe
(
'
0
'
);
},
converse
));
},
converse
));
...
...
spec/chatroom.js
View file @
24d58a5b
...
...
@@ -115,14 +115,14 @@
it
(
"
can be saved to, and retrieved from, localStorage
"
,
$
.
proxy
(
function
()
{
// We instantiate a new ChatBoxes collection, which by default
// will be empty.
spyOn
(
this
.
chatboxviews
,
'
trim
Open
Chats
'
);
spyOn
(
this
.
chatboxviews
,
'
trimChats
'
);
utils
.
openControlBox
();
var
newchatboxes
=
new
this
.
ChatBoxes
();
expect
(
newchatboxes
.
length
).
toEqual
(
0
);
// The chatboxes will then be fetched from localStorage inside the
// onConnected method
newchatboxes
.
onConnected
();
expect
(
this
.
chatboxviews
.
trim
Open
Chats
).
toHaveBeenCalled
();
expect
(
this
.
chatboxviews
.
trimChats
).
toHaveBeenCalled
();
expect
(
newchatboxes
.
length
).
toEqual
(
2
);
// XXX: Includes controlbox, is this a bug?
// Check that the chatrooms retrieved from localStorage
// have the same attributes values as the original ones.
...
...
@@ -139,33 +139,34 @@
this
.
rosterview
.
render
();
},
converse
));
it
(
"
can be
toggl
ed by clicking a DOM element with class 'toggle-chatbox-button'
"
,
function
()
{
it
(
"
can be
minimiz
ed by clicking a DOM element with class 'toggle-chatbox-button'
"
,
function
()
{
var
view
=
this
.
chatboxviews
.
get
(
'
lounge@muc.localhost
'
),
chatroom
=
view
.
model
,
$el
;
spyOn
(
view
,
'
toggleChatBox
'
).
andCallThrough
();
trimmed_chatboxes
=
this
.
chatboxviews
.
trimmed_chatboxes_view
;
spyOn
(
view
,
'
minimize
'
).
andCallThrough
();
spyOn
(
view
,
'
maximize
'
).
andCallThrough
();
spyOn
(
converse
,
'
emit
'
);
view
.
delegateEvents
();
// We need to rebind all events otherwise our spy won't be called
runs
(
function
()
{
view
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
click
();
});
waits
(
2
50
);
waits
(
50
);
runs
(
function
()
{
expect
(
view
.
toggleChatBox
).
toHaveBeenCalled
();
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBox
Toggl
ed
'
,
jasmine
.
any
(
Object
));
expect
(
view
.
minimize
).
toHaveBeenCalled
();
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBox
Minimiz
ed
'
,
jasmine
.
any
(
Object
));
expect
(
converse
.
emit
.
callCount
,
2
);
expect
(
view
.
$el
.
find
(
'
.chat-body
'
).
is
(
'
:visible
'
)).
toBeFalsy
();
expect
(
view
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
hasClass
(
'
icon-minus
'
)).
toBeFalsy
();
expect
(
view
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
hasClass
(
'
icon-plus
'
)).
toBeTruthy
();
expect
(
view
.
$el
.
is
(
'
:visible
'
)).
toBeFalsy
();
expect
(
view
.
model
.
get
(
'
minimized
'
)).
toBeTruthy
();
view
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
click
();
expect
(
view
.
minimize
).
toHaveBeenCalled
();
trimmedview
=
trimmed_chatboxes
.
get
(
view
.
model
.
get
(
'
id
'
));
trimmedview
.
$
(
"
a.restore-chat
"
).
click
();
});
waits
(
2
50
);
waits
(
50
);
runs
(
function
()
{
expect
(
view
.
toggleChatBox
).
toHaveBeenCalled
();
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxToggled
'
,
jasmine
.
any
(
Object
));
expect
(
view
.
$el
.
find
(
'
.chat-body
'
).
is
(
'
:visible
'
)).
toBeTruthy
();
expect
(
view
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
hasClass
(
'
icon-minus
'
)).
toBeTruthy
();
expect
(
view
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
hasClass
(
'
icon-plus
'
)).
toBeFalsy
();
expect
(
view
.
maximize
).
toHaveBeenCalled
();
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxMaximized
'
,
jasmine
.
any
(
Object
));
expect
(
view
.
$el
.
is
(
'
:visible
'
)).
toBeTruthy
();
expect
(
view
.
model
.
get
(
'
minimized
'
)).
toBeFalsy
();
expect
(
converse
.
emit
.
callCount
,
3
);
});
...
...
@@ -174,16 +175,16 @@
it
(
"
can be closed again by clicking a DOM element with class 'close-chatbox-button'
"
,
$
.
proxy
(
function
()
{
var
view
=
this
.
chatboxviews
.
get
(
'
lounge@muc.localhost
'
),
chatroom
=
view
.
model
,
$el
;
spyOn
(
view
,
'
close
Chat
'
).
andCallThrough
();
spyOn
(
view
,
'
close
'
).
andCallThrough
();
spyOn
(
converse
,
'
emit
'
);
spyOn
(
converse
.
connection
.
muc
,
'
leave
'
);
view
.
delegateEvents
();
// We need to rebind all events otherwise our spy won't be called
runs
(
function
()
{
view
.
$el
.
find
(
'
.close-chatbox-button
'
).
click
();
});
waits
(
2
50
);
waits
(
50
);
runs
(
function
()
{
expect
(
view
.
close
Chat
).
toHaveBeenCalled
();
expect
(
view
.
close
).
toHaveBeenCalled
();
expect
(
this
.
connection
.
muc
.
leave
).
toHaveBeenCalled
();
expect
(
this
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxClosed
'
,
jasmine
.
any
(
Object
));
}.
bind
(
converse
));
...
...
@@ -204,7 +205,7 @@
afterEach
(
$
.
proxy
(
function
()
{
var
view
=
this
.
chatboxviews
.
get
(
'
problematic@muc.localhost
'
);
view
.
close
Chat
();
view
.
close
();
},
converse
));
it
(
"
will show an error message if the room requires a password
"
,
$
.
proxy
(
function
()
{
...
...
spec/controlbox.js
View file @
24d58a5b
...
...
@@ -8,13 +8,10 @@
);
}
(
this
,
function
(
mock
,
utils
)
{
describe
(
"
The Control Box
"
,
$
.
proxy
(
function
(
mock
,
utils
)
{
beforeEach
(
function
()
{
runs
(
function
()
{
utils
.
openControlBox
();
});
waits
(
250
);
runs
(
function
()
{});
});
it
(
"
can be opened by clicking a DOM element with class 'toggle-online-users'
"
,
$
.
proxy
(
function
()
{
...
...
@@ -501,8 +498,6 @@
runs
(
function
()
{
utils
.
openControlBox
();
});
waits
(
250
);
runs
(
function
()
{});
},
converse
));
it
(
"
contains two tabs, 'Contacts' and 'ChatRooms'
"
,
$
.
proxy
(
function
()
{
...
...
@@ -524,8 +519,6 @@
runs
(
function
()
{
utils
.
openControlBox
();
});
waits
(
250
);
runs
(
function
()
{});
},
converse
));
it
(
"
is opened by clicking the 'Chatrooms' tab
"
,
$
.
proxy
(
function
()
{
...
...
src/deps-full.js
View file @
24d58a5b
...
...
@@ -3,6 +3,7 @@ define("converse-dependencies", [
"
moment
"
,
"
locales
"
,
"
backbone.localStorage
"
,
"
backbone.overview
"
,
"
jquery.tinysort
"
,
"
jquery.browser
"
,
"
strophe
"
,
...
...
src/deps-no-otr.js
View file @
24d58a5b
...
...
@@ -2,6 +2,7 @@ define("converse-dependencies", [
"
moment
"
,
"
locales
"
,
"
backbone.localStorage
"
,
"
backbone.overview
"
,
"
jquery.tinysort
"
,
"
jquery.browser
"
,
"
strophe
"
,
...
...
src/templates.js
View file @
24d58a5b
define
(
"
converse-templates
"
,
[
"
tpl!src/templates/action
"
,
"
tpl!src/templates/message
"
,
"
tpl!src/templates/new_day
"
,
"
tpl!src/templates/info
"
,
"
tpl!src/templates/controlbox
"
,
"
tpl!src/templates/chatbox
"
,
"
tpl!src/templates/toolbar
"
,
"
tpl!src/templates/contacts_tab
"
,
"
tpl!src/templates/contacts_panel
"
,
"
tpl!src/templates/chatrooms_tab
"
,
"
tpl!src/templates/login_tab
"
,
"
tpl!src/templates/add_contact_dropdown
"
,
"
tpl!src/templates/add_contact_form
"
,
"
tpl!src/templates/room_item
"
,
"
tpl!src/templates/room_description
"
,
"
tpl!src/templates/room_panel
"
,
"
tpl!src/templates/chatroom
"
,
"
tpl!src/templates/change_status_message
"
,
"
tpl!src/templates/chat_status
"
,
"
tpl!src/templates/chatarea
"
,
"
tpl!src/templates/chatbox
"
,
"
tpl!src/templates/chatroom
"
,
"
tpl!src/templates/chatrooms_tab
"
,
"
tpl!src/templates/choose_status
"
,
"
tpl!src/templates/contacts
"
,
"
tpl!src/templates/contacts_panel
"
,
"
tpl!src/templates/contacts_tab
"
,
"
tpl!src/templates/controlbox
"
,
"
tpl!src/templates/controlbox_toggle
"
,
"
tpl!src/templates/field
"
,
"
tpl!src/templates/form_checkbox
"
,
"
tpl!src/templates/form_input
"
,
"
tpl!src/templates/select_option
"
,
"
tpl!src/templates/form_select
"
,
"
tpl!src/templates/form_checkbox
"
,
"
tpl!src/templates/field
"
,
"
tpl!src/templates/info
"
,
"
tpl!src/templates/login_panel
"
,
"
tpl!src/templates/login_tab
"
,
"
tpl!src/templates/message
"
,
"
tpl!src/templates/new_day
"
,
"
tpl!src/templates/occupant
"
,
"
tpl!src/templates/roster_item
"
,
"
tpl!src/templates/pending_contact
"
,
"
tpl!src/templates/pending_contacts
"
,
"
tpl!src/templates/requesting_contact
"
,
"
tpl!src/templates/requesting_contacts
"
,
"
tpl!src/templates/
pending_contacts
"
,
"
tpl!src/templates/
contacts
"
,
"
tpl!src/templates/
chat_status
"
,
"
tpl!src/templates/
change_status_message
"
,
"
tpl!src/templates/
choose_status
"
,
"
tpl!src/templates/
room_description
"
,
"
tpl!src/templates/
room_item
"
,
"
tpl!src/templates/
room_panel
"
,
"
tpl!src/templates/
roster_item
"
,
"
tpl!src/templates/
select_option
"
,
"
tpl!src/templates/status_option
"
,
"
tpl!src/templates/login_panel
"
,
"
tpl!src/templates/controlbox_toggle
"
"
tpl!src/templates/toolbar
"
,
"
tpl!src/templates/trimmed_chat
"
,
"
tpl!src/templates/trimmed_chats
"
],
function
()
{
return
{
action
:
arguments
[
0
],
message
:
arguments
[
1
],
new_day
:
arguments
[
2
],
info
:
arguments
[
3
],
c
ontrolbox
:
arguments
[
4
],
chat
box
:
arguments
[
5
],
toolbar
:
arguments
[
6
],
c
ontacts_tab
:
arguments
[
7
],
c
ontacts_panel
:
arguments
[
8
],
ch
atrooms_tab
:
arguments
[
9
],
login_tab
:
arguments
[
10
],
add_contact_dropdown
:
arguments
[
11
],
add_contact_form
:
arguments
[
12
],
room_item
:
arguments
[
13
],
room_description
:
arguments
[
14
],
room_panel
:
arguments
[
15
],
chatroom
:
arguments
[
16
],
chatarea
:
arguments
[
17
],
form_
input
:
arguments
[
18
],
select_option
:
arguments
[
19
],
form_select
:
arguments
[
20
],
form_checkbox
:
arguments
[
21
],
field
:
arguments
[
22
],
occupant
:
arguments
[
23
],
roster_item
:
arguments
[
24
],
add_contact_dropdown
:
arguments
[
1
],
add_contact_form
:
arguments
[
2
],
change_status_message
:
arguments
[
3
],
c
hat_status
:
arguments
[
4
],
chat
area
:
arguments
[
5
],
chatbox
:
arguments
[
6
],
c
hatroom
:
arguments
[
7
],
c
hatrooms_tab
:
arguments
[
8
],
ch
oose_status
:
arguments
[
9
],
contacts
:
arguments
[
10
],
contacts_panel
:
arguments
[
11
],
contacts_tab
:
arguments
[
12
],
controlbox
:
arguments
[
13
],
controlbox_toggle
:
arguments
[
14
],
field
:
arguments
[
15
],
form_checkbox
:
arguments
[
16
],
form_input
:
arguments
[
17
],
form_
select
:
arguments
[
18
],
info
:
arguments
[
19
],
login_panel
:
arguments
[
20
],
login_tab
:
arguments
[
21
],
message
:
arguments
[
22
],
new_day
:
arguments
[
23
],
occupant
:
arguments
[
24
],
pending_contact
:
arguments
[
25
],
requesting_contact
:
arguments
[
26
],
requesting_contacts
:
arguments
[
27
],
pending_contacts
:
arguments
[
28
],
contacts
:
arguments
[
29
],
chat_status
:
arguments
[
30
],
change_status_message
:
arguments
[
31
],
choose_status
:
arguments
[
32
],
status_option
:
arguments
[
33
],
login_panel
:
arguments
[
34
],
controlbox_toggle
:
arguments
[
35
]
pending_contacts
:
arguments
[
26
],
requesting_contact
:
arguments
[
27
],
requesting_contacts
:
arguments
[
28
],
room_description
:
arguments
[
29
],
room_item
:
arguments
[
30
],
room_panel
:
arguments
[
31
],
roster_item
:
arguments
[
32
],
select_option
:
arguments
[
33
],
status_option
:
arguments
[
34
],
toolbar
:
arguments
[
35
],
trimmed_chat
:
arguments
[
36
],
trimmed_chats
:
arguments
[
37
]
};
});
src/templates/chatbox.html
View file @
24d58a5b
<div
class=
"box-flyout {[if (minimized) {]} minimized {[}]}"
{[
if
(!
minimized
)
{]}
style=
"height: {{height}}px"
{[}]}
>
<div
class=
"dragresize dragresize-tm"
{[
if
(
minimized
)
{
]}
style=
"display:none"
{[
}
]}
></div>
<div
class=
"box-flyout"
style=
"height: {{height}}px"
>
<div
class=
"dragresize dragresize-tm"
></div>
<div
class=
"chat-head chat-head-chatbox"
>
<div
class=
"chat-head-message-count"
>
0
</div>
<a
class=
"close-chatbox-button icon-close"
></a>
<a
class=
"toggle-chatbox-button
{[ if (minimized) { ]} icon-plus {[ } ]}
{[ if (!minimized) { ]} icon-minus {[ } ]}
"
></a>
<a
class=
"toggle-chatbox-button icon-minus"
></a>
<div
class=
"chat-title"
>
{[ if (url) { ]}
<a
href=
"{{url}}"
target=
"_blank"
class=
"user"
>
...
...
@@ -19,7 +14,7 @@
</div>
<p
class=
"user-custom-message"
><p/>
</div>
<div
class=
"chat-body"
{[
if
(
minimized
)
{
]}
style=
"display:none"
{[
}
]}
>
<div
class=
"chat-body"
>
<div
class=
"chat-content"
></div>
<form
class=
"sendXMPPMessage"
action=
""
method=
"post"
>
{[ if (show_toolbar) { ]}
...
...
src/templates/chatroom.html
View file @
24d58a5b
<div
class=
"box-flyout
{[if (minimized) {]} minimized {[}]}
"
{[
if
(!
minimized
)
{]}
style=
"height: {{height}}px"
{[}
]}
>
<div
class=
"dragresize dragresize-tm"
{[
if
(
minimized
)
{
]}
style=
"display:none"
{[
}
]}
></div>
<div
class=
"box-flyout
"
style=
"height: {{height}}px
"
{[
if
(
minimized
)
{
]}
style=
"display:none"
{[
}
]}
>
<div
class=
"dragresize dragresize-tm"
></div>
<div
class=
"chat-head chat-head-chatroom"
>
<div
class=
"chat-head-message-count"
>
0
</div>
<a
class=
"close-chatbox-button icon-close"
></a>
<a
class=
"toggle-chatbox-button
{[ if (minimized) { ]} icon-plus {[ } ]}
{[ if (!minimized) { ]} icon-minus {[ } ]}
"
></a>
<a
class=
"toggle-chatbox-button icon-minus"
></a>
<a
class=
"configure-chatroom-button icon-wrench"
style=
"display:none"
></a>
<div
class=
"chat-title"
>
{{ name }}
</div>
<p
class=
"chatroom-topic"
><p/>
</div>
<div
class=
"chat-body"
{[
if
(
minimized
)
{
]}
style=
"display:none"
{[
}
]}
>
<span
class=
"spinner centered"
/>
</div>
<div
class=
"chat-body"
><span
class=
"spinner centered"
/></div>
</div>
src/templates/trimmed_chat.html
0 → 100644
View file @
24d58a5b
<a
class=
"close-chatbox-button icon-close"
></a>
<div
class=
"chat-title"
>
<a
href=
"#"
class=
"restore-chat"
>
<div
class=
"chat-head-message-count"
>
0
</div>
{{ title }}
</a>
</div>
src/templates/trimmed_chats.html
0 → 100644
View file @
24d58a5b
<div
id=
"trimmed-chatboxes"
><div
class=
"box-flyout"
></div></div>
tests.html
View file @
24d58a5b
...
...
@@ -6,8 +6,10 @@
<meta
name=
"description"
content=
"Converse.js: A chat client for your website"
/>
<link
rel=
"shortcut icon"
type=
"image/png"
href=
"components/jasmine/images/jasmine_favicon.png"
>
<link
rel=
"stylesheet"
type=
"text/css"
href=
"components/jasmine/src/html/jasmine.css"
>
<link
rel=
"stylesheet"
type=
"text/css"
media=
"screen"
href=
"stylesheets/stylesheet.css"
>
<link
rel=
"stylesheet"
type=
"text/css"
media=
"screen"
href=
"converse.css"
>
<link
type=
"text/css"
rel=
"stylesheet"
media=
"screen"
href=
"http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css"
/>
<link
type=
"text/css"
rel=
"stylesheet"
media=
"screen"
href=
"http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css"
/>
<link
type=
"text/css"
rel=
"stylesheet"
media=
"screen"
href=
"css/theme.css"
/>
<link
type=
"text/css"
rel=
"stylesheet"
media=
"screen"
href=
"css/converse.css"
/>
<script
src=
"main.js"
></script>
<script
data-main=
"tests/main"
src=
"components/requirejs/require.js"
></script>
</head>
...
...
@@ -19,6 +21,5 @@
<h2
id=
"project_tagline"
>
Tests
</h2>
</header>
</div>
<div
id=
"conversejs"
></div>
</body>
</html>
tests/main.js
View file @
24d58a5b
...
...
@@ -45,7 +45,7 @@ require([
auto_subscribe
:
false
,
animate
:
false
,
connection
:
mock
.
mock_connection
,
test
ing
:
true
no_trimm
ing
:
true
},
function
(
converse
)
{
window
.
converse
=
converse
;
window
.
crypto
=
{
...
...
tests/utils.js
View file @
24d58a5b
...
...
@@ -13,7 +13,7 @@
var
i
,
chatbox
;
for
(
i
=
converse
.
chatboxes
.
models
.
length
-
1
;
i
>-
1
;
i
--
)
{
chatbox
=
converse
.
chatboxes
.
models
[
i
];
converse
.
chatboxviews
.
get
(
chatbox
.
get
(
'
id
'
)).
close
Chat
();
converse
.
chatboxviews
.
get
(
chatbox
.
get
(
'
id
'
)).
close
();
}
return
this
;
};
...
...
@@ -22,17 +22,16 @@
var
i
,
chatbox
,
num_chatboxes
=
converse
.
chatboxes
.
models
.
length
;
for
(
i
=
num_chatboxes
-
1
;
i
>-
1
;
i
--
)
{
chatbox
=
converse
.
chatboxes
.
models
[
i
];
converse
.
chatboxviews
.
get
(
chatbox
.
get
(
'
id
'
)).
close
Chat
();
converse
.
chatboxviews
.
get
(
chatbox
.
get
(
'
id
'
)).
close
();
converse
.
chatboxviews
.
get
(
chatbox
.
get
(
'
id
'
)).
$el
.
remove
();
}
converse
.
chatboxviews
.
get
(
'
controlbox
'
).
close
Chat
();
converse
.
chatboxviews
.
get
(
'
controlbox
'
).
close
();
converse
.
chatboxviews
.
get
(
'
controlbox
'
).
$el
.
remove
();
return
this
;
};
utils
.
initConverse
=
function
()
{
converse
.
chatboxes
=
new
converse
.
ChatBoxes
();
converse
.
chatboxviews
=
new
converse
.
ChatBoxViews
({
model
:
converse
.
chatboxes
});
converse
.
_initialize
();
converse
.
onConnected
();
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment