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
Hide 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
...
@@ -17,16 +17,17 @@
...
@@ -17,16 +17,17 @@
"backbone.localStorage"
:
"1.1.7"
,
"backbone.localStorage"
:
"1.1.7"
,
"strophe"
:
"git@github.com:strophe/strophejs-bower.git#v1.1.3"
,
"strophe"
:
"git@github.com:strophe/strophejs-bower.git#v1.1.3"
,
"strophe.roster"
:
"https://raw.github.com/strophe/strophejs-plugins/b1f364eb6e854ffe844c57add38e885cfeb9b498/roster/strophe.roster.js"
,
"strophe.roster"
:
"https://raw.github.com/strophe/strophejs-plugins/b1f364eb6e854ffe844c57add38e885cfeb9b498/roster/strophe.roster.js"
,
"strophe.vcard"
:
"https://raw.github.com/strophe/strophejs-plugins/f5c9e16b463610d501591452cded0359f53aae48/vcard/strophe.vcard.js"
,
"strophe.vcard"
:
"https://raw.github.com/strophe/strophejs-plugins/f5c9e16b463610d501591452cded0359f53aae48/vcard/strophe.vcard.js"
,
"strophe.disco"
:
"https://raw.github.com/jcbrand/strophejs-plugins/75c8693992bc357c699b6d615eeb396e799f5c02/disco/strophe.disco.js"
,
"strophe.disco"
:
"https://raw.github.com/jcbrand/strophejs-plugins/75c8693992bc357c699b6d615eeb396e799f5c02/disco/strophe.disco.js"
,
"strophe.muc"
:
"https://raw.github.com/strophe/strophejs-plugins/02310ad1b8da2962cd05b0f4bceaecca134efed4/muc/strophe.muc.js"
,
"strophe.muc"
:
"https://raw.github.com/strophe/strophejs-plugins/02310ad1b8da2962cd05b0f4bceaecca134efed4/muc/strophe.muc.js"
,
"otr"
:
"0.2.12"
,
"otr"
:
"0.2.12"
,
"crypto-js-evanvosberg"
:
"~3.1.2"
,
"crypto-js-evanvosberg"
:
"~3.1.2"
,
"almond"
:
"~0.2.9"
,
"almond"
:
"~0.2.9"
,
"requirejs-text"
:
"~2.0.12"
,
"requirejs-text"
:
"~2.0.12"
,
"requirejs-tpl-jcbrand"
:
"*"
,
"requirejs-tpl-jcbrand"
:
"*"
,
"momentjs"
:
"~2.6.0"
,
"momentjs"
:
"~2.6.0"
,
"jquery.browser"
:
"~0.0.6"
"jquery.browser"
:
"~0.0.6"
,
"backbone.overview"
:
"*"
},
},
"exportsOverride"
:
{}
"exportsOverride"
:
{}
}
}
converse.js
View file @
24d58a5b
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
* http://conversejs.org
* http://conversejs.org
*
*
* Copyright (c) 2012, Jan-Carel Brand <jc@opkode.com>
* 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
// AMD/global registrations
...
@@ -158,6 +158,7 @@
...
@@ -158,6 +158,7 @@
this
.
forward_messages
=
false
;
this
.
forward_messages
=
false
;
this
.
hide_muc_server
=
false
;
this
.
hide_muc_server
=
false
;
this
.
i18n
=
locales
.
en
;
this
.
i18n
=
locales
.
en
;
this
.
no_trimming
=
false
;
// Set to true for phantomjs tests (where browser apparently has no width)
this
.
prebind
=
false
;
this
.
prebind
=
false
;
this
.
show_controlbox_by_default
=
false
;
this
.
show_controlbox_by_default
=
false
;
this
.
show_only_online_users
=
false
;
this
.
show_only_online_users
=
false
;
...
@@ -195,6 +196,7 @@
...
@@ -195,6 +196,7 @@
'
fullname
'
,
'
fullname
'
,
'
hide_muc_server
'
,
'
hide_muc_server
'
,
'
i18n
'
,
'
i18n
'
,
'
no_trimming
'
,
'
jid
'
,
'
jid
'
,
'
prebind
'
,
'
prebind
'
,
'
rid
'
,
'
rid
'
,
...
@@ -863,8 +865,8 @@
...
@@ -863,8 +865,8 @@
is_chatroom
:
false
,
// This is not a multi-user chatroom
is_chatroom
:
false
,
// This is not a multi-user chatroom
events
:
{
events
:
{
'
click .close-chatbox-button
'
:
'
close
Chat
'
,
'
click .close-chatbox-button
'
:
'
close
'
,
'
click .toggle-chatbox-button
'
:
'
toggleChatBox
'
,
'
click .toggle-chatbox-button
'
:
'
minimize
'
,
'
keypress textarea.chat-textarea
'
:
'
keyPressed
'
,
'
keypress textarea.chat-textarea
'
:
'
keyPressed
'
,
'
click .toggle-smiley
'
:
'
toggleEmoticonMenu
'
,
'
click .toggle-smiley
'
:
'
toggleEmoticonMenu
'
,
'
click .toggle-smiley ul li
'
:
'
insertEmoticon
'
,
'
click .toggle-smiley ul li
'
:
'
insertEmoticon
'
,
...
@@ -892,13 +894,16 @@
...
@@ -892,13 +894,16 @@
this
.
model
.
on
(
'
showReceivedOTRMessage
'
,
function
(
text
)
{
this
.
model
.
on
(
'
showReceivedOTRMessage
'
,
function
(
text
)
{
this
.
showMessage
({
'
message
'
:
text
,
'
sender
'
:
'
them
'
});
this
.
showMessage
({
'
message
'
:
text
,
'
sender
'
:
'
them
'
});
},
this
);
},
this
);
this
.
updateVCard
();
this
.
updateVCard
();
this
.
$el
.
insertAfter
(
converse
.
chatboxviews
.
get
(
"
controlbox
"
).
$el
);
this
.
$el
.
insertAfter
(
converse
.
chatboxviews
.
get
(
"
controlbox
"
).
$el
);
this
.
render
().
show
().
focus
().
model
.
messages
.
fetch
({
add
:
true
});
this
.
model
.
messages
.
fetch
({
add
:
true
});
if
(
this
.
model
.
get
(
'
status
'
))
{
this
.
render
();
this
.
showStatusMessage
(
this
.
model
.
get
(
'
status
'
));
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
)
{
if
((
_
.
contains
([
UNVERIFIED
,
VERIFIED
],
this
.
model
.
get
(
'
otr_status
'
)))
||
converse
.
use_otr_by_default
)
{
this
.
model
.
initiateOTR
();
this
.
model
.
initiateOTR
();
}
}
...
@@ -919,7 +924,7 @@
...
@@ -919,7 +924,7 @@
setTimeout
(
function
()
{
setTimeout
(
function
()
{
converse
.
refreshWebkit
();
converse
.
refreshWebkit
();
},
50
);
},
50
);
return
this
;
return
this
.
showStatusMessage
()
;
},
},
initDragResize
:
function
()
{
initDragResize
:
function
()
{
...
@@ -937,17 +942,6 @@
...
@@ -937,17 +942,6 @@
this
.
scrollDown
();
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
)
{
clearChatRoomMessages
:
function
(
ev
)
{
ev
.
stopPropagation
();
ev
.
stopPropagation
();
var
result
=
confirm
(
__
(
"
Are you sure you want to clear the messages from this room?
"
));
var
result
=
confirm
(
__
(
"
Are you sure you want to clear the messages from this room?
"
));
...
@@ -982,9 +976,6 @@
...
@@ -982,9 +976,6 @@
'
extra_classes
'
:
msg_dict
.
delayed
&&
'
delayed
'
||
''
'
extra_classes
'
:
msg_dict
.
delayed
&&
'
delayed
'
||
''
});
});
$content
.
append
(
$
(
message
).
children
(
'
.chat-message-content
'
).
first
().
text
(
text
).
addHyperlinks
().
addEmoticons
().
parent
());
$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
();
this
.
scrollDown
();
},
},
...
@@ -1276,7 +1267,7 @@
...
@@ -1276,7 +1267,7 @@
converse
.
emit
(
'
onBuddyStatusChanged
'
,
item
.
attributes
,
item
.
get
(
'
chat_status
'
));
converse
.
emit
(
'
onBuddyStatusChanged
'
,
item
.
attributes
,
item
.
get
(
'
chat_status
'
));
}
}
if
(
_
.
has
(
item
.
changed
,
'
status
'
))
{
if
(
_
.
has
(
item
.
changed
,
'
status
'
))
{
this
.
showStatusMessage
(
item
.
get
(
'
status
'
)
);
this
.
showStatusMessage
();
converse
.
emit
(
'
onBuddyStatusMessageChanged
'
,
item
.
attributes
,
item
.
get
(
'
status
'
));
converse
.
emit
(
'
onBuddyStatusMessageChanged
'
,
item
.
attributes
,
item
.
get
(
'
status
'
));
}
}
if
(
_
.
has
(
item
.
changed
,
'
image
'
))
{
if
(
_
.
has
(
item
.
changed
,
'
image
'
))
{
...
@@ -1285,61 +1276,53 @@
...
@@ -1285,61 +1276,53 @@
if
(
_
.
has
(
item
.
changed
,
'
otr_status
'
))
{
if
(
_
.
has
(
item
.
changed
,
'
otr_status
'
))
{
this
.
renderToolbar
().
informOTRChange
();
this
.
renderToolbar
().
informOTRChange
();
}
}
if
(
_
.
has
(
item
.
changed
,
'
minimized
'
))
{
if
(
item
.
get
(
'
minimized
'
))
{
this
.
hide
();
}
else
{
this
.
maximize
();
}
}
// TODO check for changed fullname as well
// TODO check for changed fullname as well
},
},
showStatusMessage
:
function
(
msg
)
{
showStatusMessage
:
function
(
msg
)
{
this
.
$el
.
find
(
'
p.user-custom-message
'
).
text
(
msg
).
attr
(
'
title
'
,
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
)
{
if
(
converse
.
connection
)
{
this
.
model
.
destroy
();
this
.
model
.
destroy
();
}
else
{
}
else
{
this
.
model
.
trigger
(
'
hide
'
);
this
.
model
.
trigger
(
'
hide
'
);
}
}
converse
.
emit
(
'
onChatBoxClosed
'
,
this
);
return
this
;
return
this
;
},
},
trimChat
:
function
()
{
maximize
:
function
()
{
// TODO: Instead of closing the chat, we should add it to
/* Restores a minimized chat box
// div#offscreen-chatboxes
*/
this
.
$el
.
hide
();
// Hide it immediately to avoid flashes on the screen
this
.
$el
.
insertAfter
(
converse
.
chatboxviews
.
get
(
"
controlbox
"
).
$el
).
show
();
this
.
closeChat
();
this
.
focus
();
},
converse
.
refreshWebkit
();
converse
.
emit
(
'
onChatBoxMaximized
'
,
this
);
saveToggleState
:
function
()
{
this
.
model
.
trigger
(
'
maximized
'
,
this
.
model
);
var
flyout
=
this
.
$el
.
find
(
'
.box-flyout
'
);
if
(
flyout
.
hasClass
(
'
minimized
'
))
{
flyout
.
removeClass
(
'
minimized
'
);
this
.
model
.
save
({
'
minimized
'
:
false
});
}
else
{
flyout
.
addClass
(
'
minimized
'
);
this
.
model
.
save
({
'
minimized
'
:
true
,
'
time_minimized
'
:
moment
().
format
()
});
}
return
this
;
},
},
toggleChatBox
:
function
(
ev
)
{
minimize
:
function
(
ev
)
{
var
$target
=
$
(
ev
.
target
),
$count
;
/* Minimizes a chat box
this
.
saveToggleState
();
*/
this
.
$el
.
children
(
'
.box-flyout
'
).
attr
(
'
style
'
,
''
);
this
.
model
.
save
({
this
.
$el
.
find
(
'
div.chat-body
'
).
slideToggle
(
'
fast
'
);
'
minimized
'
:
true
,
if
(
$target
.
hasClass
(
'
icon-minus
'
))
{
'
time_minimized
'
:
moment
().
format
()
$target
.
removeClass
(
'
icon-minus
'
).
addClass
(
'
icon-plus
'
);
});
}
else
{
this
.
$el
.
hide
(
'
fast
'
,
converse
.
refreshwebkit
);
$target
.
removeClass
(
'
icon-plus
'
).
addClass
(
'
icon-minus
'
);
converse
.
emit
(
'
onChatBoxMinimized
'
,
this
);
$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
);
},
},
updateVCard
:
function
()
{
updateVCard
:
function
()
{
...
@@ -1445,8 +1428,8 @@
...
@@ -1445,8 +1428,8 @@
hide
:
function
()
{
hide
:
function
()
{
if
(
this
.
$el
.
is
(
'
:visible
'
)
&&
this
.
$el
.
css
(
'
opacity
'
)
==
"
1
"
)
{
if
(
this
.
$el
.
is
(
'
:visible
'
)
&&
this
.
$el
.
css
(
'
opacity
'
)
==
"
1
"
)
{
this
.
$el
.
fadeOut
(
'
fast
'
,
converse
.
refreshWebkit
);
this
.
$el
.
hide
(
);
converse
.
emit
(
'
onChatBoxClosed
'
,
this
);
converse
.
refreshWebkit
(
);
}
}
return
this
;
return
this
;
},
},
...
@@ -1460,13 +1443,16 @@
...
@@ -1460,13 +1443,16 @@
// Without a connection, we haven't yet initialized
// Without a connection, we haven't yet initialized
// localstorage
// localstorage
this
.
model
.
save
();
this
.
model
.
save
();
this
.
initDragResize
();
}
}
return
this
;
return
this
;
},
},
scrollDown
:
function
()
{
scrollDown
:
function
()
{
var
$content
=
this
.
$el
.
find
(
'
.chat-content
'
);
var
$content
=
this
.
$
(
'
.chat-content
'
);
$content
.
scrollTop
(
$content
[
0
].
scrollHeight
);
if
(
$content
.
is
(
'
:visible
'
))
{
$content
.
scrollTop
(
$content
[
0
].
scrollHeight
);
}
return
this
;
return
this
;
}
}
});
});
...
@@ -1767,7 +1753,7 @@
...
@@ -1767,7 +1753,7 @@
}
}
}
}
if
(
!
nick
)
{
return
;
}
if
(
!
nick
)
{
return
;
}
chatroom
=
converse
.
chatboxviews
.
showChat
Box
({
chatroom
=
converse
.
chatboxviews
.
showChat
({
'
id
'
:
jid
,
'
id
'
:
jid
,
'
jid
'
:
jid
,
'
jid
'
:
jid
,
'
name
'
:
Strophe
.
unescapeNode
(
Strophe
.
getNodeFromJid
(
jid
)),
'
name
'
:
Strophe
.
unescapeNode
(
Strophe
.
getNodeFromJid
(
jid
)),
...
@@ -1786,7 +1772,7 @@
...
@@ -1786,7 +1772,7 @@
className
:
'
chatbox
'
,
className
:
'
chatbox
'
,
id
:
'
controlbox
'
,
id
:
'
controlbox
'
,
events
:
{
events
:
{
'
click a.close-chatbox-button
'
:
'
close
Chat
'
,
'
click a.close-chatbox-button
'
:
'
close
'
,
'
click ul#controlbox-tabs li a
'
:
'
switchTab
'
,
'
click ul#controlbox-tabs li a
'
:
'
switchTab
'
,
'
mousedown .dragresize-tm
'
:
'
onDragResizeStart
'
'
mousedown .dragresize-tm
'
:
'
onDragResizeStart
'
},
},
...
@@ -1890,8 +1876,8 @@
...
@@ -1890,8 +1876,8 @@
tagName
:
'
div
'
,
tagName
:
'
div
'
,
className
:
'
chatroom
'
,
className
:
'
chatroom
'
,
events
:
{
events
:
{
'
click .close-chatbox-button
'
:
'
close
Chat
'
,
'
click .close-chatbox-button
'
:
'
close
'
,
'
click .toggle-chatbox-button
'
:
'
toggleChatBox
'
,
'
click .toggle-chatbox-button
'
:
'
minimize
'
,
'
click .configure-chatroom-button
'
:
'
configureChatRoom
'
,
'
click .configure-chatroom-button
'
:
'
configureChatRoom
'
,
'
click .toggle-smiley
'
:
'
toggleEmoticonMenu
'
,
'
click .toggle-smiley
'
:
'
toggleEmoticonMenu
'
,
'
click .toggle-smiley ul li
'
:
'
insertEmoticon
'
,
'
click .toggle-smiley ul li
'
:
'
insertEmoticon
'
,
...
@@ -1904,6 +1890,13 @@
...
@@ -1904,6 +1890,13 @@
initialize
:
function
()
{
initialize
:
function
()
{
this
.
connect
(
null
);
this
.
connect
(
null
);
this
.
model
.
messages
.
on
(
'
add
'
,
this
.
onMessageAdded
,
this
);
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
.
model
.
on
(
'
destroy
'
,
function
(
model
,
response
,
options
)
{
this
.
hide
();
this
.
hide
();
converse
.
connection
.
muc
.
leave
(
converse
.
connection
.
muc
.
leave
(
...
@@ -1913,9 +1906,13 @@
...
@@ -1913,9 +1906,13 @@
undefined
);
undefined
);
},
},
this
);
this
);
this
.
$el
.
appendTo
(
converse
.
chatboxviews
.
$el
);
this
.
$el
.
insertAfter
(
converse
.
chatboxviews
.
get
(
"
controlbox
"
).
$el
);
this
.
render
().
show
().
model
.
messages
.
fetch
({
add
:
true
});
this
.
render
().
model
.
messages
.
fetch
({
add
:
true
});
this
.
initDragResize
();
if
(
this
.
model
.
get
(
'
minimized
'
))
{
this
.
hide
();
}
else
{
this
.
show
();
}
},
},
render
:
function
()
{
render
:
function
()
{
...
@@ -2387,7 +2384,7 @@
...
@@ -2387,7 +2384,7 @@
this
.
ChatBoxes
=
Backbone
.
Collection
.
extend
({
this
.
ChatBoxes
=
Backbone
.
Collection
.
extend
({
model
:
converse
.
ChatBox
,
model
:
converse
.
ChatBox
,
comparator
:
'
time_opened
'
,
comparator
:
'
time_opened
'
,
registerMessageHandler
:
function
()
{
registerMessageHandler
:
function
()
{
converse
.
connection
.
addHandler
(
converse
.
connection
.
addHandler
(
...
@@ -2478,43 +2475,67 @@
...
@@ -2478,43 +2475,67 @@
}
}
});
});
this
.
ChatBoxViews
=
Backbone
.
View
.
extend
({
this
.
ChatBoxViews
=
Backbone
.
Overview
.
extend
({
el
:
'
#conversejs
'
,
initialize
:
function
()
{
initialize
:
function
()
{
var
views
=
{};
this
.
trimmed_chatboxes_view
=
new
converse
.
MinimizedChatBoxesView
({
model
:
this
.
model
});
this
.
get
=
function
(
id
)
{
return
views
[
id
];
};
this
.
render
();
this
.
set
=
function
(
id
,
view
)
{
views
[
id
]
=
view
;
};
this
.
model
.
on
(
"
add
"
,
this
.
onChatAdded
,
this
);
this
.
getAll
=
function
()
{
return
views
;
};
this
.
model
.
on
(
"
maximized
"
,
function
(
item
)
{
this
.
trimChats
(
this
.
get
(
item
.
get
(
'
id
'
)));
},
this
);
},
this
.
model
.
on
(
"
add
"
,
function
(
item
)
{
render
:
function
()
{
var
view
=
this
.
get
(
item
.
get
(
'
id
'
));
this
.
$el
.
html
(
this
.
trimmed_chatboxes_view
.
render
());
if
(
!
view
)
{
},
if
(
item
.
get
(
'
chatroom
'
))
{
view
=
new
converse
.
ChatRoomView
({
'
model
'
:
item
});
_ensureElement
:
function
()
{
}
else
if
(
item
.
get
(
'
box_id
'
)
===
'
controlbox
'
)
{
/* Override method from backbone.js
view
=
new
converse
.
ControlBoxView
({
model
:
item
});
* If the #conversejs element doesn't exist, create it.
view
.
render
();
*/
}
else
{
if
(
!
this
.
el
)
{
view
=
new
converse
.
ChatBoxView
({
model
:
item
});
var
$el
=
$
(
'
#conversejs
'
);
}
if
(
!
$el
.
length
)
{
this
.
set
(
item
.
get
(
'
id
'
),
view
);
$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
}).
render
();
}
else
{
}
else
{
delete
view
.
model
;
// Remove ref to old model to help garbage collection
view
=
new
converse
.
ChatBoxView
({
model
:
item
});
view
.
model
=
item
;
view
.
initialize
();
}
}
this
.
trimOpenChats
(
view
);
this
.
add
(
item
.
get
(
'
id
'
),
view
);
},
this
);
}
else
{
delete
view
.
model
;
// Remove ref to old model to help garbage collection
view
.
model
=
item
;
view
.
initialize
();
}
this
.
trimChats
(
view
);
},
},
trim
Open
Chats
:
function
(
view
)
{
trimChats
:
function
(
view
)
{
/* This method is called before a new chat box will be opened.
/* This method is called before a new chat box will be opened.
*
*
* Check whether there is enough space in the page to show
* Check whether there is enough space in the page to show
* another chat box. Otherwise, close the oldest chat box.
* another chat box. Otherwise, close the oldest chat box.
*/
*/
var
toggle_width
=
0
,
if
(
converse
.
no_trimming
)
{
return
;
}
var
toggle_width
=
0
,
trimmed_chats_width
,
boxes_width
=
view
.
$el
.
outerWidth
(
true
),
boxes_width
=
view
.
$el
.
outerWidth
(
true
),
controlbox
=
this
.
get
(
'
controlbox
'
);
controlbox
=
this
.
get
(
'
controlbox
'
);
if
(
!
controlbox
||
!
controlbox
.
$el
.
is
(
'
:visible
'
))
{
if
(
!
controlbox
||
!
controlbox
.
$el
.
is
(
'
:visible
'
))
{
...
@@ -2529,16 +2550,31 @@
...
@@ -2529,16 +2550,31 @@
if
(
this
.
model
.
length
<=
1
)
{
if
(
this
.
model
.
length
<=
1
)
{
return
;
return
;
}
}
if
((
boxes_width
+
toggle_width
)
>
this
.
$el
.
width
())
{
trimmed_chats_width
=
this
.
trimmed_chatboxes_view
.
$
(
'
.box-flyout
'
).
outerWidth
(
true
)
||
0
;
// trim oldest view (which is not controlbox)
if
((
trimmed_chats_width
+
boxes_width
+
toggle_width
)
>
this
.
$el
.
width
())
{
this
.
get
(
this
.
model
.
at
(
1
).
get
(
'
id
'
)).
trimChat
(
);
this
.
get
OldestMaximizedChat
().
set
(
'
minimized
'
,
true
);
}
}
},
},
showChatBox
:
function
(
attrs
)
{
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
:
function
(
attrs
)
{
var
chatbox
=
this
.
model
.
get
(
attrs
.
jid
);
var
chatbox
=
this
.
model
.
get
(
attrs
.
jid
);
if
(
chatbox
)
{
if
(
chatbox
)
{
chatbox
.
trigger
(
'
show
'
);
if
(
chatbox
.
get
(
'
minimized
'
))
{
chatbox
.
set
({
'
minimized
'
:
false
});
}
else
{
chatbox
.
trigger
(
'
show
'
);
}
}
else
{
}
else
{
chatbox
=
this
.
model
.
create
(
attrs
,
{
chatbox
=
this
.
model
.
create
(
attrs
,
{
'
error
'
:
function
(
model
,
response
)
{
'
error
'
:
function
(
model
,
response
)
{
...
@@ -2550,6 +2586,126 @@
...
@@ -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
({
this
.
RosterItem
=
Backbone
.
Model
.
extend
({
initialize
:
function
(
attributes
,
options
)
{
initialize
:
function
(
attributes
,
options
)
{
var
jid
=
attributes
.
jid
;
var
jid
=
attributes
.
jid
;
...
@@ -2580,7 +2736,7 @@
...
@@ -2580,7 +2736,7 @@
openChat
:
function
(
ev
)
{
openChat
:
function
(
ev
)
{
ev
.
preventDefault
();
ev
.
preventDefault
();
return
converse
.
chatboxviews
.
showChat
Box
({
return
converse
.
chatboxviews
.
showChat
({
'
id
'
:
this
.
model
.
get
(
'
jid
'
),
'
id
'
:
this
.
model
.
get
(
'
jid
'
),
'
jid
'
:
this
.
model
.
get
(
'
jid
'
),
'
jid
'
:
this
.
model
.
get
(
'
jid
'
),
'
fullname
'
:
this
.
model
.
get
(
'
fullname
'
),
'
fullname
'
:
this
.
model
.
get
(
'
fullname
'
),
...
@@ -2963,17 +3119,11 @@
...
@@ -2963,17 +3119,11 @@
}
}
});
});
this
.
RosterView
=
Backbone
.
V
iew
.
extend
({
this
.
RosterView
=
Backbone
.
Overv
iew
.
extend
({
tagName
:
'
dl
'
,
tagName
:
'
dl
'
,
id
:
'
converse-roster
'
,
id
:
'
converse-roster
'
,
initialize
:
function
()
{
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
.
model
.
on
(
"
add
"
,
function
(
item
)
{
this
.
addRosterItemView
(
item
).
render
(
item
);
this
.
addRosterItemView
(
item
).
render
(
item
);
if
(
!
item
.
get
(
'
vcard_updated
'
))
{
if
(
!
item
.
get
(
'
vcard_updated
'
))
{
...
@@ -3007,7 +3157,6 @@
...
@@ -3007,7 +3157,6 @@
});
});
}
}
this
.
$el
.
hide
().
html
(
roster_markup
);
this
.
$el
.
hide
().
html
(
roster_markup
);
this
.
model
.
fetch
({
add
:
true
});
// Get the cached roster items from localstorage
this
.
model
.
fetch
({
add
:
true
});
// Get the cached roster items from localstorage
},
},
...
@@ -3029,7 +3178,7 @@
...
@@ -3029,7 +3178,7 @@
addRosterItemView
:
function
(
item
)
{
addRosterItemView
:
function
(
item
)
{
var
view
=
new
converse
.
RosterItemView
({
model
:
item
});
var
view
=
new
converse
.
RosterItemView
({
model
:
item
});
this
.
set
(
item
.
id
,
view
);
this
.
add
(
item
.
id
,
view
);
return
this
;
return
this
;
},
},
...
@@ -3460,7 +3609,7 @@
...
@@ -3460,7 +3609,7 @@
if
(
converse
.
show_controlbox_by_default
)
{
if
(
converse
.
show_controlbox_by_default
)
{
toggle
.
hide
();
// It's either or
toggle
.
hide
();
// It's either or
}
}
$
(
'
#conversejs
'
).
ap
pend
(
toggle
);
$
(
'
#conversejs
'
).
pre
pend
(
toggle
);
return
this
;
return
this
;
},
},
...
@@ -3503,14 +3652,17 @@
...
@@ -3503,14 +3652,17 @@
}
}
});
});
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
// Initialization
// --------------
// --------------
// This is the end of the initialize method.
// This is the end of the initialize method.
this
.
chatboxes
=
new
this
.
ChatBoxes
();
this
.
_initialize
();
this
.
chatboxviews
=
new
this
.
ChatBoxViews
({
model
:
this
.
chatboxes
});
this
.
controlboxtoggle
=
new
this
.
ControlBoxToggle
();
this
.
otr
=
new
this
.
OTR
();
if
((
this
.
prebind
)
&&
(
!
this
.
connection
))
{
if
((
this
.
prebind
)
&&
(
!
this
.
connection
))
{
if
((
!
this
.
jid
)
||
(
!
this
.
sid
)
||
(
!
this
.
rid
)
||
(
!
this
.
bosh_service_url
))
{
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
'
);
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,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aTI1RkMHdW5pMjVGQgd1bmlFMDE1B3VuaUUwMTYHdW5pRTAxNwd1bmlFMDFBB3VuaUUwMUIHdW5pRTAxRAd1bmkyMzFCB3VuaUUwMjEHdW5pRTAyMgd1bmlFMDI0B3VuaUUwMjUHdW5pRTAyNgd1bmlFMDI3B3VuaUUwMjgHdW5pRTAyOQd1bmlFMDJBB3VuaUUwMkIHdW5pRTAyRgd1bmlFMDJEB3VuaUUwMkUHdW5pRTAzMAd1bmlFMDMxB3VuaUUwMzIHdW5pRTAzMwd1bmkyNzY0DGludnNtaWxlZmFjZQd1bmkyNjFECXNtaWxlZmFjZQd1bmlFMDM4B3VuaTI2MzkHdW5pRTAzQQd1bmkyMzY5B3VuaTIzNjgHdW5pMjM2NAd1bmkyNjFGB3VuaUUwM0YHdW5pRTA0MAd1bmlFMDQxB3VuaTIzNjAHdW5pRTAxRgd1bmkyNkEwB3VuaUUwNDUHdW5pRTA0Ngd1bmlFMDQ3B3VuaUUwNDgHdW5pRTA0OQd1bmlFMDRBB3VuaUUwNEIHdW5pRTA0Qwd1bmlFMDREB3VuaUUwNEUHdW5pRTA0Rgd1bmlFMDUwB3VuaUUwNTMHdW5pRTA1NQd1bmkyNzE1B3VuaTI3MTgHdW5pRTA1OAd1bmlFMDVBB3VuaTI3MUEHdW5pMjYxMQd1bmkyQjI3B3VuaTJCMjgHdW5pMkIyNgd1bmkyQjI1B3VuaUUwNTkHdW5pRTAwMQd1bmkyQjE0B3VuaUUwMDIHdW5pRTAwNAAAAAH//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 {
...
@@ -568,13 +568,7 @@ span.spinner.hor_centered {
margin-right
:
5px
;
margin-right
:
5px
;
color
:
white
;
color
:
white
;
}
}
#conversejs
#offscreen-chatboxes
{
#conversejs
#trimmed-chatboxes
.box-flyout
{
float
:
left
;
height
:
25px
;
margin-left
:
5px
;
display
:
block
;
}
#conversejs
#offscreen-chatboxes
.box-flyout
{
position
:
absolute
;
position
:
absolute
;
display
:
block
;
display
:
block
;
bottom
:
1px
;
bottom
:
1px
;
...
@@ -582,15 +576,16 @@ span.spinner.hor_centered {
...
@@ -582,15 +576,16 @@ span.spinner.hor_centered {
border-radius
:
4px
;
border-radius
:
4px
;
height
:
auto
;
height
:
auto
;
}
}
#conversejs
#
offscreen
-chatboxes
.box-flyout
.chat-head
{
#conversejs
#
trimmed
-chatboxes
.box-flyout
.chat-head
{
font-size
:
100%
;
font-size
:
100%
;
border-radius
:
4px
;
border-radius
:
4px
;
padding
:
3px
0
0
5px
;
padding
:
3px
0
0
5px
;
margin
:
0
0
2px
2px
;
margin
:
0
0
2px
2px
;
box-shadow
:
1px
3px
5px
3px
rgba
(
0
,
0
,
0
,
0.4
);
box-shadow
:
1px
3px
5px
3px
rgba
(
0
,
0
,
0
,
0.4
);
height
:
24px
;
height
:
24px
;
width
:
130px
;
}
}
#conversejs
#
offscreen
-chatboxes
.chat-head-chatroom
{
#conversejs
#
trimmed
-chatboxes
.chat-head-chatroom
{
width
:
100px
;
width
:
100px
;
}
}
#conversejs
#toggle-controlbox
{
#conversejs
#toggle-controlbox
{
...
@@ -745,10 +740,11 @@ input.error {
...
@@ -745,10 +740,11 @@ input.error {
text-overflow
:
ellipsis
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
white-space
:
nowrap
;
text-shadow
:
rgba
(
0
,
0
,
0
,
0.51
)
0
-1px
0
;
text-shadow
:
rgba
(
0
,
0
,
0
,
0.51
)
0
-1px
0
;
height
:
1em
;
}
}
#conversejs
.chat-title
a
{
#conversejs
.chat-title
a
{
color
:
white
;
color
:
white
;
width
:
100%
;
display
:
block
;
}
}
#conversejs
.chat-head-chatbox
,
#conversejs
.chat-head-chatbox
,
#conversejs
.chat-head-chatroom
{
#conversejs
.chat-head-chatroom
{
...
@@ -836,23 +832,20 @@ dl.add-converse-contact {
...
@@ -836,23 +832,20 @@ dl.add-converse-contact {
#conversejs
.chat-head-message-count
{
#conversejs
.chat-head-message-count
{
font-weight
:
bold
;
font-weight
:
bold
;
position
:
absolute
;
position
:
absolute
;
left
:
-
6
px
;
left
:
-
5
px
;
top
:
-6
px
;
top
:
2
px
;
background
:
-webkit-gradient
(
linear
,
left
top
,
left
bottom
,
color-stop
(
0.35
,
#f6f6f6
),
color-stop
(
1
,
#808080
));
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%
);
background
:
-moz-linear-gradient
(
center
top
,
#ffff00
5%
,
#f6f6f6
100%
);
filter
:
progid
:
DXImageTransform
.
Microsoft
.
gradient
(
startColorstr
=
'yellow'
,
endColorstr
=
'#f6f6f6'
);
filter
:
progid
:
DXImageTransform
.
Microsoft
.
gradient
(
startColorstr
=
'yellow'
,
endColorstr
=
'#f6f6f6'
);
border
:
3px
solid
#4f6a72
;
border
:
1px
solid
;
text-shadow
:
1px
1px
0
#ccc
;
text-shadow
:
1px
1px
0
#ccc
;
color
:
darkred
;
color
:
darkred
;
border-radius
:
20%
;
border-radius
:
20%
;
padding
:
2px
10
px
;
padding
:
2px
4
px
;
font-size
:
1
8
px
;
font-size
:
1
5
px
;
text-align
:
center
;
text-align
:
center
;
display
:
none
;
display
:
none
;
}
}
#conversejs
.chat-head-chatroom
.chat-head-message-count
{
border
:
3px
solid
#2D617A
;
}
#conversejs
a
.configure-chatroom-button
,
#conversejs
a
.configure-chatroom-button
,
#conversejs
a
.toggle-chatbox-button
,
#conversejs
a
.toggle-chatbox-button
,
#conversejs
a
.close-chatbox-button
{
#conversejs
a
.close-chatbox-button
{
...
@@ -1040,6 +1033,7 @@ dl.add-converse-contact {
...
@@ -1040,6 +1033,7 @@ dl.add-converse-contact {
#conversejs
#converse-roster
dd
.pending-xmpp-contact
:hover
span
{
#conversejs
#converse-roster
dd
.pending-xmpp-contact
:hover
span
{
width
:
70%
;
width
:
70%
;
}
}
#conversejs
#trimmed-chatboxes
,
#conversejs
.chatbox
,
#conversejs
.chatbox
,
#conversejs
.chatroom
{
#conversejs
.chatroom
{
height
:
25px
;
height
:
25px
;
...
@@ -1047,6 +1041,9 @@ dl.add-converse-contact {
...
@@ -1047,6 +1041,9 @@ dl.add-converse-contact {
margin-right
:
15px
;
margin-right
:
15px
;
display
:
block
;
display
:
block
;
}
}
#conversejs
#trimmed-chatboxes
{
width
:
130px
;
}
#conversejs
.chatbox
{
#conversejs
.chatbox
{
width
:
200px
;
width
:
200px
;
}
}
...
...
docs/CHANGES.rst
View file @
24d58a5b
...
@@ -9,6 +9,7 @@ Changelog
...
@@ -9,6 +9,7 @@ Changelog
2. Configuration options for the chat toolbar have changed.
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`_.
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]
* All date handling is now done with moment.js. [jcbrand]
* Add a new toolbar button for clearing chat messages. [jcbrand]
* Add a new toolbar button for clearing chat messages. [jcbrand]
* Chat boxes and rooms can now be resized vertically. [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).
...
@@ -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
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.
Converse.js repository serves as a nice usable example of this.
...
...
index.html
View file @
24d58a5b
...
@@ -13,6 +13,11 @@
...
@@ -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/theme.css"
/>
<link
type=
"text/css"
rel=
"stylesheet"
media=
"screen"
href=
"css/converse.css"
/>
<link
type=
"text/css"
rel=
"stylesheet"
media=
"screen"
href=
"css/converse.css"
/>
<script
data-main=
"main"
src=
"components/requirejs/require.js"
></script>
<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>
</head>
<body
id=
"page-top"
data-spy=
"scroll"
data-target=
".navbar-custom"
>
<body
id=
"page-top"
data-spy=
"scroll"
data-target=
".navbar-custom"
>
...
@@ -209,15 +214,6 @@
...
@@ -209,15 +214,6 @@
</div>
</div>
</div>
</div>
</section>
</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>
</body>
<script
type=
"text/javascript"
>
<script
type=
"text/javascript"
>
...
...
less/converse.less
View file @
24d58a5b
...
@@ -598,14 +598,7 @@ span.spinner.hor_centered {
...
@@ -598,14 +598,7 @@ span.spinner.hor_centered {
color: white;
color: white;
}
}
#conversejs #offscreen-chatboxes {
#conversejs #trimmed-chatboxes .box-flyout {
float: left;
height: 25px;
margin-left: 5px;
display: block;
}
#conversejs #offscreen-chatboxes .box-flyout {
position: absolute;
position: absolute;
display: block;
display: block;
bottom: 1px;
bottom: 1px;
...
@@ -614,16 +607,17 @@ span.spinner.hor_centered {
...
@@ -614,16 +607,17 @@ span.spinner.hor_centered {
height: auto;
height: auto;
}
}
#conversejs #
offscreen
-chatboxes .box-flyout .chat-head {
#conversejs #
trimmed
-chatboxes .box-flyout .chat-head {
font-size: 100%;
font-size: 100%;
border-radius: 4px;
border-radius: 4px;
padding: 3px 0 0 5px;
padding: 3px 0 0 5px;
margin: 0 0 2px 2px;
margin: 0 0 2px 2px;
box-shadow: 1px 3px 5px 3px rgba(0,0,0,0.4);
box-shadow: 1px 3px 5px 3px rgba(0,0,0,0.4);
height: 24px;
height: 24px;
width: 130px;
}
}
#conversejs #
offscreen
-chatboxes .chat-head-chatroom {
#conversejs #
trimmed
-chatboxes .chat-head-chatroom {
width: 100px;
width: 100px;
}
}
...
@@ -808,11 +802,12 @@ input.error {
...
@@ -808,11 +802,12 @@ input.error {
text-overflow: ellipsis;
text-overflow: ellipsis;
white-space: nowrap;
white-space: nowrap;
text-shadow: rgba(0,0,0,0.51) 0 -1px 0;
text-shadow: rgba(0,0,0,0.51) 0 -1px 0;
height: 1em;
}
}
#conversejs .chat-title a {
#conversejs .chat-title a {
color: white;
color: white;
width: 100%;
display: block;
}
}
#conversejs .chat-head-chatbox,
#conversejs .chat-head-chatbox,
...
@@ -916,25 +911,21 @@ dl.add-converse-contact {
...
@@ -916,25 +911,21 @@ dl.add-converse-contact {
#conversejs .chat-head-message-count {
#conversejs .chat-head-message-count {
font-weight: bold;
font-weight: bold;
position: absolute;
position: absolute;
left: -
6
px;
left: -
5
px;
top:
-6
px;
top:
2
px;
background: -webkit-gradient(linear, left top, left bottom, color-stop(0.35, #f6f6f6), color-stop(1, grey) );
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%);
background: -moz-linear-gradient(center top, yellow 5%, #f6f6f6 100%);
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='yellow', endColorstr='#f6f6f6');
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;
text-shadow: 1px 1px 0 #ccc;
color: darkred;
color: darkred;
border-radius: 20%;
border-radius: 20%;
padding: 2px
10
px;
padding: 2px
4
px;
font-size: 1
8
px;
font-size: 1
5
px;
text-align: center;
text-align: center;
display: none;
display: none;
}
}
#conversejs .chat-head-chatroom .chat-head-message-count {
border: 3px solid #2D617A;
}
#conversejs a.configure-chatroom-button,
#conversejs a.configure-chatroom-button,
#conversejs a.toggle-chatbox-button,
#conversejs a.toggle-chatbox-button,
#conversejs a.close-chatbox-button {
#conversejs a.close-chatbox-button {
...
@@ -1152,6 +1143,7 @@ dl.add-converse-contact {
...
@@ -1152,6 +1143,7 @@ dl.add-converse-contact {
width: 70%;
width: 70%;
}
}
#conversejs #trimmed-chatboxes,
#conversejs .chatbox,
#conversejs .chatbox,
#conversejs .chatroom {
#conversejs .chatroom {
height: 25px;
height: 25px;
...
@@ -1160,6 +1152,10 @@ dl.add-converse-contact {
...
@@ -1160,6 +1152,10 @@ dl.add-converse-contact {
display: block;
display: block;
}
}
#conversejs #trimmed-chatboxes {
width: 130px;
}
#conversejs .chatbox {
#conversejs .chatbox {
width: 200px;
width: 200px;
}
}
...
...
main.js
View file @
24d58a5b
...
@@ -8,6 +8,7 @@ config = {
...
@@ -8,6 +8,7 @@ config = {
"
underscore
"
:
"
components/underscore/underscore
"
,
"
underscore
"
:
"
components/underscore/underscore
"
,
"
backbone
"
:
"
components/backbone/backbone
"
,
"
backbone
"
:
"
components/backbone/backbone
"
,
"
backbone.localStorage
"
:
"
components/backbone.localStorage/backbone.localStorage
"
,
"
backbone.localStorage
"
:
"
components/backbone.localStorage/backbone.localStorage
"
,
"
backbone.overview
"
:
"
components/backbone.overview/backbone.overview
"
,
"
text
"
:
'
components/requirejs-text/text
'
,
"
text
"
:
'
components/requirejs-text/text
'
,
"
tpl
"
:
'
components/requirejs-tpl-jcbrand/tpl
'
,
"
tpl
"
:
'
components/requirejs-tpl-jcbrand/tpl
'
,
"
converse-templates
"
:
"
src/templates
"
,
"
converse-templates
"
:
"
src/templates
"
,
...
...
mockup/index.html
View file @
24d58a5b
...
@@ -373,27 +373,72 @@
...
@@ -373,27 +373,72 @@
</div>
</div>
</div>
</div>
<div
id=
"
offscreen
-chatboxes"
>
<div
id=
"
trimmed
-chatboxes"
>
<div
class=
"box-flyout"
>
<div
class=
"box-flyout"
>
<div
class=
"chat-head chat-head-chatroom"
>
<div
class=
"chat-head chat-head-chatroom"
>
<a
class=
"close-chatbox-button icon-close"
></a>
<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>
<div
class=
"chat-head chat-head-chatbox"
>
<div
class=
"chat-head chat-head-chatbox"
>
<a
class=
"close-chatbox-button icon-close"
></a>
<a
class=
"close-chatbox-button icon-close"
></a>
<div
class=
"chat-title"
>
<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
JC Brand
</a>
</a>
</div>
</div>
</div>
</div>
<div
class=
"chat-head chat-head-chatroom"
>
<div
class=
"chat-head chat-head-chatroom"
>
<a
class=
"close-chatbox-button icon-close"
></a>
<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>
</div>
</div>
</div>
</div>
<script>
<script>
...
@@ -458,13 +503,7 @@ $(document).ready(function () {
...
@@ -458,13 +503,7 @@ $(document).ready(function () {
$
(
'
.toggle-chatbox-button
'
).
click
(
function
(
ev
)
{
$
(
'
.toggle-chatbox-button
'
).
click
(
function
(
ev
)
{
var
$grandparent
=
$
(
ev
.
target
).
parent
().
parent
().
parent
();
var
$grandparent
=
$
(
ev
.
target
).
parent
().
parent
().
parent
();
$grandparent
.
find
(
'
.chat-body
'
).
slideToggle
(
'
fast
'
);
$grandparent
.
fadeOut
(
'
fast
'
);
var
flyout
=
$grandparent
.
find
(
'
.box-flyout
'
);
if
(
flyout
.
hasClass
(
'
minimized
'
))
{
flyout
.
removeClass
(
'
minimized
'
);
}
else
{
flyout
.
addClass
(
'
minimized
'
);
}
});
});
// Clickable Dropdown
// 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 @@
...
@@ -30,11 +30,12 @@
});
});
it
(
"
is created when you click on a roster item
"
,
$
.
proxy
(
function
()
{
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
// openControlBox was called earlier, so the controlbox is
// visible, but no other chat boxes have been created.
// visible, but no other chat boxes have been created.
expect
(
this
.
chatboxes
.
length
).
toEqual
(
1
);
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
'
);
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
++
)
{
for
(
i
=
0
;
i
<
online_contacts
.
length
;
i
++
)
{
...
@@ -44,9 +45,59 @@
...
@@ -44,9 +45,59 @@
spyOn
(
view
,
'
openChat
'
).
andCallThrough
();
spyOn
(
view
,
'
openChat
'
).
andCallThrough
();
view
.
delegateEvents
();
// We need to rebind all events otherwise our spy won't be called
view
.
delegateEvents
();
// We need to rebind all events otherwise our spy won't be called
$el
.
click
();
$el
.
click
();
chatboxview
=
this
.
chatboxviews
.
get
(
jid
);
expect
(
view
.
openChat
).
toHaveBeenCalled
();
expect
(
view
.
openChat
).
toHaveBeenCalled
();
expect
(
this
.
chatboxes
.
length
).
toEqual
(
i
+
2
);
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
));
},
converse
));
...
@@ -72,14 +123,14 @@
...
@@ -72,14 +123,14 @@
it
(
"
can be saved to, and retrieved from, localStorage
"
,
$
.
proxy
(
function
()
{
it
(
"
can be saved to, and retrieved from, localStorage
"
,
$
.
proxy
(
function
()
{
spyOn
(
converse
,
'
emit
'
);
spyOn
(
converse
,
'
emit
'
);
spyOn
(
this
.
chatboxviews
,
'
trim
Open
Chats
'
);
spyOn
(
this
.
chatboxviews
,
'
trimChats
'
);
runs
(
function
()
{
runs
(
function
()
{
utils
.
openControlBox
();
utils
.
openControlBox
();
});
});
waits
(
250
);
waits
(
250
);
runs
(
function
()
{
runs
(
function
()
{
utils
.
openChatBoxes
(
6
);
utils
.
openChatBoxes
(
6
);
expect
(
this
.
chatboxviews
.
trim
Open
Chats
).
toHaveBeenCalled
();
expect
(
this
.
chatboxviews
.
trimChats
).
toHaveBeenCalled
();
// We instantiate a new ChatBoxes collection, which by default
// We instantiate a new ChatBoxes collection, which by default
// will be empty.
// will be empty.
var
newchatboxes
=
new
this
.
ChatBoxes
();
var
newchatboxes
=
new
this
.
ChatBoxes
();
...
@@ -104,8 +155,8 @@
...
@@ -104,8 +155,8 @@
var
chatbox
=
utils
.
openChatBoxes
(
1
)[
0
],
var
chatbox
=
utils
.
openChatBoxes
(
1
)[
0
],
controlview
=
this
.
chatboxviews
.
get
(
'
controlbox
'
),
// The controlbox is currently open
controlview
=
this
.
chatboxviews
.
get
(
'
controlbox
'
),
// The controlbox is currently open
chatview
=
this
.
chatboxviews
.
get
(
chatbox
.
get
(
'
jid
'
));
chatview
=
this
.
chatboxviews
.
get
(
chatbox
.
get
(
'
jid
'
));
spyOn
(
chatview
,
'
close
Chat
'
).
andCallThrough
();
spyOn
(
chatview
,
'
close
'
).
andCallThrough
();
spyOn
(
controlview
,
'
close
Chat
'
).
andCallThrough
();
spyOn
(
controlview
,
'
close
'
).
andCallThrough
();
spyOn
(
converse
,
'
emit
'
);
spyOn
(
converse
,
'
emit
'
);
// We need to rebind all events otherwise our spy won't be called
// We need to rebind all events otherwise our spy won't be called
...
@@ -117,56 +168,60 @@
...
@@ -117,56 +168,60 @@
});
});
waits
(
250
);
waits
(
250
);
runs
(
function
()
{
runs
(
function
()
{
expect
(
controlview
.
close
Chat
).
toHaveBeenCalled
();
expect
(
controlview
.
close
).
toHaveBeenCalled
();
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxClosed
'
,
jasmine
.
any
(
Object
));
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxClosed
'
,
jasmine
.
any
(
Object
));
expect
(
converse
.
emit
.
callCount
,
1
);
expect
(
converse
.
emit
.
callCount
,
1
);
chatview
.
$el
.
find
(
'
.close-chatbox-button
'
).
click
();
chatview
.
$el
.
find
(
'
.close-chatbox-button
'
).
click
();
});
});
waits
(
250
);
waits
(
250
);
runs
(
function
()
{
runs
(
function
()
{
expect
(
chatview
.
close
Chat
).
toHaveBeenCalled
();
expect
(
chatview
.
close
).
toHaveBeenCalled
();
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxClosed
'
,
jasmine
.
any
(
Object
));
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxClosed
'
,
jasmine
.
any
(
Object
));
expect
(
converse
.
emit
.
callCount
,
2
);
expect
(
converse
.
emit
.
callCount
,
2
);
});
});
},
converse
));
},
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
],
var
chatbox
=
utils
.
openChatBoxes
(
1
)[
0
],
chatview
=
this
.
chatboxviews
.
get
(
chatbox
.
get
(
'
jid
'
));
chatview
=
this
.
chatboxviews
.
get
(
chatbox
.
get
(
'
jid
'
)),
spyOn
(
chatview
,
'
toggleChatBox
'
).
andCallThrough
();
trimmed_chatboxes
=
this
.
chatboxviews
.
trimmed_chatboxes_view
;
spyOn
(
chatview
,
'
maximize
'
).
andCallThrough
();
spyOn
(
chatview
,
'
minimize
'
).
andCallThrough
();
spyOn
(
converse
,
'
emit
'
);
spyOn
(
converse
,
'
emit
'
);
spyOn
(
trimmed_chatboxes
,
'
onChanged
'
).
andCallThrough
();
// We need to rebind all events otherwise our spy won't be called
// We need to rebind all events otherwise our spy won't be called
chatview
.
delegateEvents
();
chatview
.
delegateEvents
();
runs
(
function
()
{
runs
(
function
()
{
chatview
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
click
();
chatview
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
click
();
});
});
waits
(
2
50
);
waits
(
50
);
runs
(
function
()
{
runs
(
function
()
{
expect
(
chatview
.
toggleChatBox
).
toHaveBeenCalled
();
expect
(
chatview
.
minimize
).
toHaveBeenCalled
();
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBox
Toggl
ed
'
,
jasmine
.
any
(
Object
));
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBox
Minimiz
ed
'
,
jasmine
.
any
(
Object
));
expect
(
converse
.
emit
.
callCount
,
2
);
expect
(
converse
.
emit
.
callCount
,
2
);
expect
(
chatview
.
$el
.
find
(
'
.chat-body
'
).
is
(
'
:visible
'
)).
toBeFalsy
();
expect
(
chatview
.
$el
.
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
.
model
.
get
(
'
minimized
'
)).
toBeTruthy
();
expect
(
chatview
.
model
.
get
(
'
minimized
'
)).
toBeTruthy
();
chatview
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
click
();
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
()
{
runs
(
function
()
{
expect
(
chatview
.
toggleChatBox
).
toHaveBeenCalled
();
expect
(
trimmed_chatboxes
.
onChanged
).
toHaveBeenCalled
();
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxToggled
'
,
jasmine
.
any
(
Object
));
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
(
'
.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-minus
'
)).
toBeTruthy
();
expect
(
chatview
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
hasClass
(
'
icon-plus
'
)).
toBeFalsy
();
expect
(
chatview
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
hasClass
(
'
icon-plus
'
)).
toBeFalsy
();
expect
(
chatview
.
model
.
get
(
'
minimized
'
)).
toBeFalsy
();
expect
(
chatview
.
model
.
get
(
'
minimized
'
)).
toBeFalsy
();
expect
(
converse
.
emit
.
callCount
,
3
);
});
});
}.
bind
(
converse
));
}.
bind
(
converse
));
it
(
"
will be removed from localStorage when closed
"
,
$
.
proxy
(
function
()
{
it
(
"
will be removed from localStorage when closed
"
,
$
.
proxy
(
function
()
{
spyOn
(
converse
,
'
emit
'
);
spyOn
(
converse
,
'
emit
'
);
spyOn
(
converse
.
chatboxviews
,
'
trim
Open
Chats
'
);
spyOn
(
converse
.
chatboxviews
,
'
trimChats
'
);
this
.
chatboxes
.
localStorage
.
_clear
();
this
.
chatboxes
.
localStorage
.
_clear
();
runs
(
function
()
{
runs
(
function
()
{
utils
.
closeControlBox
();
utils
.
closeControlBox
();
...
@@ -176,7 +231,7 @@
...
@@ -176,7 +231,7 @@
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxClosed
'
,
jasmine
.
any
(
Object
));
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxClosed
'
,
jasmine
.
any
(
Object
));
expect
(
converse
.
chatboxes
.
length
).
toEqual
(
0
);
expect
(
converse
.
chatboxes
.
length
).
toEqual
(
0
);
utils
.
openChatBoxes
(
6
);
utils
.
openChatBoxes
(
6
);
expect
(
converse
.
chatboxviews
.
trim
Open
Chats
).
toHaveBeenCalled
();
expect
(
converse
.
chatboxviews
.
trimChats
).
toHaveBeenCalled
();
expect
(
converse
.
chatboxes
.
length
).
toEqual
(
6
);
expect
(
converse
.
chatboxes
.
length
).
toEqual
(
6
);
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxOpened
'
,
jasmine
.
any
(
Object
));
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxOpened
'
,
jasmine
.
any
(
Object
));
utils
.
closeAllChatBoxes
();
utils
.
closeAllChatBoxes
();
...
@@ -303,7 +358,7 @@
...
@@ -303,7 +358,7 @@
$toolbar
=
view
.
$el
.
find
(
'
ul.chat-toolbar
'
);
$toolbar
=
view
.
$el
.
find
(
'
ul.chat-toolbar
'
);
callButton
=
$toolbar
.
find
(
'
.toggle-call
'
);
callButton
=
$toolbar
.
find
(
'
.toggle-call
'
);
expect
(
callButton
.
length
).
toBe
(
0
);
expect
(
callButton
.
length
).
toBe
(
0
);
view
.
close
Chat
();
view
.
close
();
// Now check that it's shown if enabled and that it emits
// Now check that it's shown if enabled and that it emits
// onCallButtonClicked
// onCallButtonClicked
converse
.
visible_toolbar_buttons
.
call
=
true
;
// enable the button
converse
.
visible_toolbar_buttons
.
call
=
true
;
// enable the button
...
@@ -328,7 +383,7 @@
...
@@ -328,7 +383,7 @@
$toolbar
=
view
.
$el
.
find
(
'
ul.chat-toolbar
'
);
$toolbar
=
view
.
$el
.
find
(
'
ul.chat-toolbar
'
);
clearButton
=
$toolbar
.
find
(
'
.toggle-clear
'
);
clearButton
=
$toolbar
.
find
(
'
.toggle-clear
'
);
expect
(
clearButton
.
length
).
toBe
(
0
);
expect
(
clearButton
.
length
).
toBe
(
0
);
view
.
close
Chat
();
view
.
close
();
// Now check that it's shown if enabled and that it calls
// Now check that it's shown if enabled and that it calls
// clearMessages
// clearMessages
converse
.
visible_toolbar_buttons
.
clear
=
true
;
// enable the button
converse
.
visible_toolbar_buttons
.
clear
=
true
;
// enable the button
...
@@ -409,13 +464,13 @@
...
@@ -409,13 +464,13 @@
runs
(
function
()
{
runs
(
function
()
{
utils
.
openChatBoxFor
(
contact_jid
);
utils
.
openChatBoxFor
(
contact_jid
);
});
});
waits
(
2
50
);
waits
(
50
);
runs
(
function
()
{
runs
(
function
()
{
var
chatview
=
converse
.
chatboxviews
.
get
(
contact_jid
);
var
chatview
=
converse
.
chatboxviews
.
get
(
contact_jid
);
expect
(
chatview
.
model
.
get
(
'
minimized
'
)).
toBeFalsy
();
expect
(
chatview
.
model
.
get
(
'
minimized
'
)).
toBeFalsy
();
chatview
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
click
();
chatview
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
click
();
});
});
waits
(
2
50
);
waits
(
50
);
runs
(
$
.
proxy
(
function
()
{
runs
(
$
.
proxy
(
function
()
{
var
chatview
=
this
.
chatboxviews
.
get
(
contact_jid
);
var
chatview
=
this
.
chatboxviews
.
get
(
contact_jid
);
expect
(
chatview
.
model
.
get
(
'
minimized
'
)).
toBeTruthy
();
expect
(
chatview
.
model
.
get
(
'
minimized
'
)).
toBeTruthy
();
...
@@ -431,11 +486,12 @@
...
@@ -431,11 +486,12 @@
this
.
chatboxes
.
onMessage
(
msg
);
this
.
chatboxes
.
onMessage
(
msg
);
expect
(
this
.
emit
).
toHaveBeenCalledWith
(
'
onMessage
'
,
msg
);
expect
(
this
.
emit
).
toHaveBeenCalledWith
(
'
onMessage
'
,
msg
);
},
converse
));
},
converse
));
waits
(
2
50
);
waits
(
50
);
runs
(
$
.
proxy
(
function
()
{
runs
(
$
.
proxy
(
function
()
{
var
chatview
=
this
.
chatboxviews
.
get
(
contact_jid
);
var
trimmed_chatboxes
=
this
.
chatboxviews
.
trimmed_chatboxes_view
;
var
$count
=
chatview
.
$el
.
find
(
'
.chat-head-message-count
'
);
var
trimmedview
=
trimmed_chatboxes
.
get
(
contact_jid
);
expect
(
chatview
.
model
.
get
(
'
minimized
'
)).
toBeTruthy
();
var
$count
=
trimmedview
.
$el
.
find
(
'
.chat-head-message-count
'
);
expect
(
trimmedview
.
model
.
get
(
'
minimized
'
)).
toBeTruthy
();
expect
(
$count
.
is
(
'
:visible
'
)).
toBeTruthy
();
expect
(
$count
.
is
(
'
:visible
'
)).
toBeTruthy
();
expect
(
$count
.
data
(
'
count
'
)).
toBe
(
1
);
expect
(
$count
.
data
(
'
count
'
)).
toBe
(
1
);
expect
(
$count
.
html
()).
toBe
(
'
1
'
);
expect
(
$count
.
html
()).
toBe
(
'
1
'
);
...
@@ -449,23 +505,25 @@
...
@@ -449,23 +505,25 @@
.
c
(
'
active
'
,
{
'
xmlns
'
:
'
http://jabber.org/protocol/chatstates
'
}).
tree
()
.
c
(
'
active
'
,
{
'
xmlns
'
:
'
http://jabber.org/protocol/chatstates
'
}).
tree
()
);
);
},
converse
));
},
converse
));
waits
(
10
0
);
waits
(
5
0
);
runs
(
$
.
proxy
(
function
()
{
runs
(
$
.
proxy
(
function
()
{
var
chatview
=
this
.
chatboxviews
.
get
(
contact_jid
);
var
trimmed_chatboxes
=
this
.
chatboxviews
.
trimmed_chatboxes_view
;
var
$count
=
chatview
.
$el
.
find
(
'
.chat-head-message-count
'
);
var
trimmedview
=
trimmed_chatboxes
.
get
(
contact_jid
);
expect
(
chatview
.
model
.
get
(
'
minimized
'
)).
toBeTruthy
();
var
$count
=
trimmedview
.
$el
.
find
(
'
.chat-head-message-count
'
);
expect
(
trimmedview
.
model
.
get
(
'
minimized
'
)).
toBeTruthy
();
expect
(
$count
.
is
(
'
:visible
'
)).
toBeTruthy
();
expect
(
$count
.
is
(
'
:visible
'
)).
toBeTruthy
();
expect
(
$count
.
data
(
'
count
'
)).
toBe
(
2
);
expect
(
$count
.
data
(
'
count
'
)).
toBe
(
2
);
expect
(
$count
.
html
()).
toBe
(
'
2
'
);
expect
(
$count
.
html
()).
toBe
(
'
2
'
);
chatview
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
click
();
trimmedview
.
$el
.
find
(
'
.restore-chat
'
).
click
();
},
converse
));
},
converse
));
waits
(
2
50
);
waits
(
50
);
runs
(
$
.
proxy
(
function
()
{
runs
(
$
.
proxy
(
function
()
{
var
chatview
=
this
.
chatboxviews
.
get
(
contact_jid
);
var
trimmed_chatboxes
=
this
.
chatboxviews
.
trimmed_chatboxes_view
;
var
$count
=
chatview
.
$el
.
find
(
'
.chat-head-message-count
'
);
var
trimmedview
=
trimmed_chatboxes
.
get
(
contact_jid
);
expect
(
chatview
.
model
.
get
(
'
minimized
'
)).
toBeFalsy
();
var
$count
=
trimmedview
.
$el
.
find
(
'
.chat-head-message-count
'
);
expect
(
trimmedview
.
model
.
get
(
'
minimized
'
)).
toBeFalsy
();
expect
(
$count
.
is
(
'
:visible
'
)).
toBeFalsy
();
expect
(
$count
.
is
(
'
:visible
'
)).
toBeFalsy
();
expect
(
$count
.
data
(
'
count
'
)).
toBe
(
0
);
expect
(
$count
.
data
(
'
count
'
)).
toBe
Falsy
(
);
expect
(
$count
.
html
()).
toBe
(
'
0
'
);
expect
(
$count
.
html
()).
toBe
(
'
0
'
);
},
converse
));
},
converse
));
},
converse
));
},
converse
));
...
...
spec/chatroom.js
View file @
24d58a5b
...
@@ -115,14 +115,14 @@
...
@@ -115,14 +115,14 @@
it
(
"
can be saved to, and retrieved from, localStorage
"
,
$
.
proxy
(
function
()
{
it
(
"
can be saved to, and retrieved from, localStorage
"
,
$
.
proxy
(
function
()
{
// We instantiate a new ChatBoxes collection, which by default
// We instantiate a new ChatBoxes collection, which by default
// will be empty.
// will be empty.
spyOn
(
this
.
chatboxviews
,
'
trim
Open
Chats
'
);
spyOn
(
this
.
chatboxviews
,
'
trimChats
'
);
utils
.
openControlBox
();
utils
.
openControlBox
();
var
newchatboxes
=
new
this
.
ChatBoxes
();
var
newchatboxes
=
new
this
.
ChatBoxes
();
expect
(
newchatboxes
.
length
).
toEqual
(
0
);
expect
(
newchatboxes
.
length
).
toEqual
(
0
);
// The chatboxes will then be fetched from localStorage inside the
// The chatboxes will then be fetched from localStorage inside the
// onConnected method
// onConnected method
newchatboxes
.
onConnected
();
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?
expect
(
newchatboxes
.
length
).
toEqual
(
2
);
// XXX: Includes controlbox, is this a bug?
// Check that the chatrooms retrieved from localStorage
// Check that the chatrooms retrieved from localStorage
// have the same attributes values as the original ones.
// have the same attributes values as the original ones.
...
@@ -139,33 +139,34 @@
...
@@ -139,33 +139,34 @@
this
.
rosterview
.
render
();
this
.
rosterview
.
render
();
},
converse
));
},
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
'
),
var
view
=
this
.
chatboxviews
.
get
(
'
lounge@muc.localhost
'
),
chatroom
=
view
.
model
,
$el
;
trimmed_chatboxes
=
this
.
chatboxviews
.
trimmed_chatboxes_view
;
spyOn
(
view
,
'
toggleChatBox
'
).
andCallThrough
();
spyOn
(
view
,
'
minimize
'
).
andCallThrough
();
spyOn
(
view
,
'
maximize
'
).
andCallThrough
();
spyOn
(
converse
,
'
emit
'
);
spyOn
(
converse
,
'
emit
'
);
view
.
delegateEvents
();
// We need to rebind all events otherwise our spy won't be called
view
.
delegateEvents
();
// We need to rebind all events otherwise our spy won't be called
runs
(
function
()
{
runs
(
function
()
{
view
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
click
();
view
.
$el
.
find
(
'
.toggle-chatbox-button
'
).
click
();
});
});
waits
(
2
50
);
waits
(
50
);
runs
(
function
()
{
runs
(
function
()
{
expect
(
view
.
toggleChatBox
).
toHaveBeenCalled
();
expect
(
view
.
minimize
).
toHaveBeenCalled
();
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBox
Toggl
ed
'
,
jasmine
.
any
(
Object
));
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBox
Minimiz
ed
'
,
jasmine
.
any
(
Object
));
expect
(
converse
.
emit
.
callCount
,
2
);
expect
(
converse
.
emit
.
callCount
,
2
);
expect
(
view
.
$el
.
find
(
'
.chat-body
'
).
is
(
'
:visible
'
)).
toBeFalsy
();
expect
(
view
.
$el
.
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
.
model
.
get
(
'
minimized
'
)).
toBeTruthy
();
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
()
{
runs
(
function
()
{
expect
(
view
.
toggleChatBox
).
toHaveBeenCalled
();
expect
(
view
.
maximize
).
toHaveBeenCalled
();
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxToggled
'
,
jasmine
.
any
(
Object
));
expect
(
converse
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxMaximized
'
,
jasmine
.
any
(
Object
));
expect
(
view
.
$el
.
find
(
'
.chat-body
'
).
is
(
'
:visible
'
)).
toBeTruthy
();
expect
(
view
.
$el
.
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
.
model
.
get
(
'
minimized
'
)).
toBeFalsy
();
expect
(
view
.
model
.
get
(
'
minimized
'
)).
toBeFalsy
();
expect
(
converse
.
emit
.
callCount
,
3
);
expect
(
converse
.
emit
.
callCount
,
3
);
});
});
...
@@ -174,16 +175,16 @@
...
@@ -174,16 +175,16 @@
it
(
"
can be closed again by clicking a DOM element with class 'close-chatbox-button'
"
,
$
.
proxy
(
function
()
{
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
;
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
,
'
emit
'
);
spyOn
(
converse
.
connection
.
muc
,
'
leave
'
);
spyOn
(
converse
.
connection
.
muc
,
'
leave
'
);
view
.
delegateEvents
();
// We need to rebind all events otherwise our spy won't be called
view
.
delegateEvents
();
// We need to rebind all events otherwise our spy won't be called
runs
(
function
()
{
runs
(
function
()
{
view
.
$el
.
find
(
'
.close-chatbox-button
'
).
click
();
view
.
$el
.
find
(
'
.close-chatbox-button
'
).
click
();
});
});
waits
(
2
50
);
waits
(
50
);
runs
(
function
()
{
runs
(
function
()
{
expect
(
view
.
close
Chat
).
toHaveBeenCalled
();
expect
(
view
.
close
).
toHaveBeenCalled
();
expect
(
this
.
connection
.
muc
.
leave
).
toHaveBeenCalled
();
expect
(
this
.
connection
.
muc
.
leave
).
toHaveBeenCalled
();
expect
(
this
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxClosed
'
,
jasmine
.
any
(
Object
));
expect
(
this
.
emit
).
toHaveBeenCalledWith
(
'
onChatBoxClosed
'
,
jasmine
.
any
(
Object
));
}.
bind
(
converse
));
}.
bind
(
converse
));
...
@@ -204,7 +205,7 @@
...
@@ -204,7 +205,7 @@
afterEach
(
$
.
proxy
(
function
()
{
afterEach
(
$
.
proxy
(
function
()
{
var
view
=
this
.
chatboxviews
.
get
(
'
problematic@muc.localhost
'
);
var
view
=
this
.
chatboxviews
.
get
(
'
problematic@muc.localhost
'
);
view
.
close
Chat
();
view
.
close
();
},
converse
));
},
converse
));
it
(
"
will show an error message if the room requires a password
"
,
$
.
proxy
(
function
()
{
it
(
"
will show an error message if the room requires a password
"
,
$
.
proxy
(
function
()
{
...
...
spec/controlbox.js
View file @
24d58a5b
...
@@ -8,13 +8,10 @@
...
@@ -8,13 +8,10 @@
);
);
}
(
this
,
function
(
mock
,
utils
)
{
}
(
this
,
function
(
mock
,
utils
)
{
describe
(
"
The Control Box
"
,
$
.
proxy
(
function
(
mock
,
utils
)
{
describe
(
"
The Control Box
"
,
$
.
proxy
(
function
(
mock
,
utils
)
{
beforeEach
(
function
()
{
beforeEach
(
function
()
{
runs
(
function
()
{
runs
(
function
()
{
utils
.
openControlBox
();
utils
.
openControlBox
();
});
});
waits
(
250
);
runs
(
function
()
{});
});
});
it
(
"
can be opened by clicking a DOM element with class 'toggle-online-users'
"
,
$
.
proxy
(
function
()
{
it
(
"
can be opened by clicking a DOM element with class 'toggle-online-users'
"
,
$
.
proxy
(
function
()
{
...
@@ -501,8 +498,6 @@
...
@@ -501,8 +498,6 @@
runs
(
function
()
{
runs
(
function
()
{
utils
.
openControlBox
();
utils
.
openControlBox
();
});
});
waits
(
250
);
runs
(
function
()
{});
},
converse
));
},
converse
));
it
(
"
contains two tabs, 'Contacts' and 'ChatRooms'
"
,
$
.
proxy
(
function
()
{
it
(
"
contains two tabs, 'Contacts' and 'ChatRooms'
"
,
$
.
proxy
(
function
()
{
...
@@ -524,8 +519,6 @@
...
@@ -524,8 +519,6 @@
runs
(
function
()
{
runs
(
function
()
{
utils
.
openControlBox
();
utils
.
openControlBox
();
});
});
waits
(
250
);
runs
(
function
()
{});
},
converse
));
},
converse
));
it
(
"
is opened by clicking the 'Chatrooms' tab
"
,
$
.
proxy
(
function
()
{
it
(
"
is opened by clicking the 'Chatrooms' tab
"
,
$
.
proxy
(
function
()
{
...
...
src/deps-full.js
View file @
24d58a5b
...
@@ -3,6 +3,7 @@ define("converse-dependencies", [
...
@@ -3,6 +3,7 @@ define("converse-dependencies", [
"
moment
"
,
"
moment
"
,
"
locales
"
,
"
locales
"
,
"
backbone.localStorage
"
,
"
backbone.localStorage
"
,
"
backbone.overview
"
,
"
jquery.tinysort
"
,
"
jquery.tinysort
"
,
"
jquery.browser
"
,
"
jquery.browser
"
,
"
strophe
"
,
"
strophe
"
,
...
...
src/deps-no-otr.js
View file @
24d58a5b
...
@@ -2,6 +2,7 @@ define("converse-dependencies", [
...
@@ -2,6 +2,7 @@ define("converse-dependencies", [
"
moment
"
,
"
moment
"
,
"
locales
"
,
"
locales
"
,
"
backbone.localStorage
"
,
"
backbone.localStorage
"
,
"
backbone.overview
"
,
"
jquery.tinysort
"
,
"
jquery.tinysort
"
,
"
jquery.browser
"
,
"
jquery.browser
"
,
"
strophe
"
,
"
strophe
"
,
...
...
src/templates.js
View file @
24d58a5b
define
(
"
converse-templates
"
,
[
define
(
"
converse-templates
"
,
[
"
tpl!src/templates/action
"
,
"
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_dropdown
"
,
"
tpl!src/templates/add_contact_form
"
,
"
tpl!src/templates/add_contact_form
"
,
"
tpl!src/templates/room_item
"
,
"
tpl!src/templates/change_status_message
"
,
"
tpl!src/templates/room_description
"
,
"
tpl!src/templates/chat_status
"
,
"
tpl!src/templates/room_panel
"
,
"
tpl!src/templates/chatroom
"
,
"
tpl!src/templates/chatarea
"
,
"
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/form_input
"
,
"
tpl!src/templates/select_option
"
,
"
tpl!src/templates/form_select
"
,
"
tpl!src/templates/form_select
"
,
"
tpl!src/templates/form_checkbox
"
,
"
tpl!src/templates/info
"
,
"
tpl!src/templates/field
"
,
"
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/occupant
"
,
"
tpl!src/templates/roster_item
"
,
"
tpl!src/templates/pending_contact
"
,
"
tpl!src/templates/pending_contact
"
,
"
tpl!src/templates/pending_contacts
"
,
"
tpl!src/templates/requesting_contact
"
,
"
tpl!src/templates/requesting_contact
"
,
"
tpl!src/templates/requesting_contacts
"
,
"
tpl!src/templates/requesting_contacts
"
,
"
tpl!src/templates/
pending_contacts
"
,
"
tpl!src/templates/
room_description
"
,
"
tpl!src/templates/
contacts
"
,
"
tpl!src/templates/
room_item
"
,
"
tpl!src/templates/
chat_status
"
,
"
tpl!src/templates/
room_panel
"
,
"
tpl!src/templates/
change_status_message
"
,
"
tpl!src/templates/
roster_item
"
,
"
tpl!src/templates/
choose_status
"
,
"
tpl!src/templates/
select_option
"
,
"
tpl!src/templates/status_option
"
,
"
tpl!src/templates/status_option
"
,
"
tpl!src/templates/login_panel
"
,
"
tpl!src/templates/toolbar
"
,
"
tpl!src/templates/controlbox_toggle
"
"
tpl!src/templates/trimmed_chat
"
,
"
tpl!src/templates/trimmed_chats
"
],
function
()
{
],
function
()
{
return
{
return
{
action
:
arguments
[
0
],
action
:
arguments
[
0
],
message
:
arguments
[
1
],
add_contact_dropdown
:
arguments
[
1
],
new_day
:
arguments
[
2
],
add_contact_form
:
arguments
[
2
],
info
:
arguments
[
3
],
change_status_message
:
arguments
[
3
],
controlbox
:
arguments
[
4
],
chat_status
:
arguments
[
4
],
chatbox
:
arguments
[
5
],
chatarea
:
arguments
[
5
],
toolbar
:
arguments
[
6
],
chatbox
:
arguments
[
6
],
contacts_tab
:
arguments
[
7
],
chatroom
:
arguments
[
7
],
contacts_panel
:
arguments
[
8
],
chatrooms_tab
:
arguments
[
8
],
chatrooms_tab
:
arguments
[
9
],
choose_status
:
arguments
[
9
],
login_tab
:
arguments
[
10
],
contacts
:
arguments
[
10
],
add_contact_dropdown
:
arguments
[
11
],
contacts_panel
:
arguments
[
11
],
add_contact_form
:
arguments
[
12
],
contacts_tab
:
arguments
[
12
],
room_item
:
arguments
[
13
],
controlbox
:
arguments
[
13
],
room_description
:
arguments
[
14
],
controlbox_toggle
:
arguments
[
14
],
room_panel
:
arguments
[
15
],
field
:
arguments
[
15
],
chatroom
:
arguments
[
16
],
form_checkbox
:
arguments
[
16
],
chatarea
:
arguments
[
17
],
form_input
:
arguments
[
17
],
form_input
:
arguments
[
18
],
form_select
:
arguments
[
18
],
select_option
:
arguments
[
19
],
info
:
arguments
[
19
],
form_select
:
arguments
[
20
],
login_panel
:
arguments
[
20
],
form_checkbox
:
arguments
[
21
],
login_tab
:
arguments
[
21
],
field
:
arguments
[
22
],
message
:
arguments
[
22
],
occupant
:
arguments
[
23
],
new_day
:
arguments
[
23
],
roster_item
:
arguments
[
24
],
occupant
:
arguments
[
24
],
pending_contact
:
arguments
[
25
],
pending_contact
:
arguments
[
25
],
requesting_contact
:
arguments
[
26
],
pending_contacts
:
arguments
[
26
],
requesting_contacts
:
arguments
[
27
],
requesting_contact
:
arguments
[
27
],
pending_contacts
:
arguments
[
28
],
requesting_contacts
:
arguments
[
28
],
contacts
:
arguments
[
29
],
room_description
:
arguments
[
29
],
chat_status
:
arguments
[
30
],
room_item
:
arguments
[
30
],
change_status_message
:
arguments
[
31
],
room_panel
:
arguments
[
31
],
choose_status
:
arguments
[
32
],
roster_item
:
arguments
[
32
],
status_option
:
arguments
[
33
],
select_option
:
arguments
[
33
],
login_panel
:
arguments
[
34
],
status_option
:
arguments
[
34
],
controlbox_toggle
:
arguments
[
35
]
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 {[}]}"
<div
class=
"box-flyout"
style=
"height: {{height}}px"
>
{[
if
(!
minimized
)
{]}
style=
"height: {{height}}px"
{[}]}
>
<div
class=
"dragresize dragresize-tm"
></div>
<div
class=
"dragresize dragresize-tm"
{[
if
(
minimized
)
{
]}
style=
"display:none"
{[
}
]}
></div>
<div
class=
"chat-head chat-head-chatbox"
>
<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=
"close-chatbox-button icon-close"
></a>
<a
class=
"toggle-chatbox-button
<a
class=
"toggle-chatbox-button icon-minus"
></a>
{[ if (minimized) { ]} icon-plus {[ } ]}
{[ if (!minimized) { ]} icon-minus {[ } ]}
"
></a>
<div
class=
"chat-title"
>
<div
class=
"chat-title"
>
{[ if (url) { ]}
{[ if (url) { ]}
<a
href=
"{{url}}"
target=
"_blank"
class=
"user"
>
<a
href=
"{{url}}"
target=
"_blank"
class=
"user"
>
...
@@ -19,7 +14,7 @@
...
@@ -19,7 +14,7 @@
</div>
</div>
<p
class=
"user-custom-message"
><p/>
<p
class=
"user-custom-message"
><p/>
</div>
</div>
<div
class=
"chat-body"
{[
if
(
minimized
)
{
]}
style=
"display:none"
{[
}
]}
>
<div
class=
"chat-body"
>
<div
class=
"chat-content"
></div>
<div
class=
"chat-content"
></div>
<form
class=
"sendXMPPMessage"
action=
""
method=
"post"
>
<form
class=
"sendXMPPMessage"
action=
""
method=
"post"
>
{[ if (show_toolbar) { ]}
{[ if (show_toolbar) { ]}
...
...
src/templates/chatroom.html
View file @
24d58a5b
<div
class=
"box-flyout
{[if (minimized) {]} minimized {[}]}
"
<div
class=
"box-flyout
"
style=
"height: {{height}}px
"
{[
if
(!
minimized
)
{]}
style=
"height: {{height}}px"
{[}
]}
>
{[
if
(
minimized
)
{
]}
style=
"display:none"
{[
}
]}
>
<div
class=
"dragresize dragresize-tm"
{[
if
(
minimized
)
{
]}
style=
"display:none"
{[
}
]}
></div>
<div
class=
"dragresize dragresize-tm"
></div>
<div
class=
"chat-head chat-head-chatroom"
>
<div
class=
"chat-head chat-head-chatroom"
>
<div
class=
"chat-head-message-count"
>
0
</div>
<div
class=
"chat-head-message-count"
>
0
</div>
<a
class=
"close-chatbox-button icon-close"
></a>
<a
class=
"close-chatbox-button icon-close"
></a>
<a
class=
"toggle-chatbox-button
<a
class=
"toggle-chatbox-button icon-minus"
></a>
{[ if (minimized) { ]} icon-plus {[ } ]}
{[ if (!minimized) { ]} icon-minus {[ } ]}
"
></a>
<a
class=
"configure-chatroom-button icon-wrench"
style=
"display:none"
></a>
<a
class=
"configure-chatroom-button icon-wrench"
style=
"display:none"
></a>
<div
class=
"chat-title"
>
{{ name }}
</div>
<div
class=
"chat-title"
>
{{ name }}
</div>
<p
class=
"chatroom-topic"
><p/>
<p
class=
"chatroom-topic"
><p/>
</div>
</div>
<div
class=
"chat-body"
{[
if
(
minimized
)
{
]}
style=
"display:none"
{[
}
]}
>
<div
class=
"chat-body"
><span
class=
"spinner centered"
/></div>
<span
class=
"spinner centered"
/>
</div>
</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 @@
...
@@ -6,8 +6,10 @@
<meta
name=
"description"
content=
"Converse.js: A chat client for your website"
/>
<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=
"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"
href=
"components/jasmine/src/html/jasmine.css"
>
<link
rel=
"stylesheet"
type=
"text/css"
media=
"screen"
href=
"stylesheets/stylesheet.css"
>
<link
type=
"text/css"
rel=
"stylesheet"
media=
"screen"
href=
"http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.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/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
src=
"main.js"
></script>
<script
data-main=
"tests/main"
src=
"components/requirejs/require.js"
></script>
<script
data-main=
"tests/main"
src=
"components/requirejs/require.js"
></script>
</head>
</head>
...
@@ -19,6 +21,5 @@
...
@@ -19,6 +21,5 @@
<h2
id=
"project_tagline"
>
Tests
</h2>
<h2
id=
"project_tagline"
>
Tests
</h2>
</header>
</header>
</div>
</div>
<div
id=
"conversejs"
></div>
</body>
</body>
</html>
</html>
tests/main.js
View file @
24d58a5b
...
@@ -45,7 +45,7 @@ require([
...
@@ -45,7 +45,7 @@ require([
auto_subscribe
:
false
,
auto_subscribe
:
false
,
animate
:
false
,
animate
:
false
,
connection
:
mock
.
mock_connection
,
connection
:
mock
.
mock_connection
,
test
ing
:
true
no_trimm
ing
:
true
},
function
(
converse
)
{
},
function
(
converse
)
{
window
.
converse
=
converse
;
window
.
converse
=
converse
;
window
.
crypto
=
{
window
.
crypto
=
{
...
...
tests/utils.js
View file @
24d58a5b
...
@@ -13,7 +13,7 @@
...
@@ -13,7 +13,7 @@
var
i
,
chatbox
;
var
i
,
chatbox
;
for
(
i
=
converse
.
chatboxes
.
models
.
length
-
1
;
i
>-
1
;
i
--
)
{
for
(
i
=
converse
.
chatboxes
.
models
.
length
-
1
;
i
>-
1
;
i
--
)
{
chatbox
=
converse
.
chatboxes
.
models
[
i
];
chatbox
=
converse
.
chatboxes
.
models
[
i
];
converse
.
chatboxviews
.
get
(
chatbox
.
get
(
'
id
'
)).
close
Chat
();
converse
.
chatboxviews
.
get
(
chatbox
.
get
(
'
id
'
)).
close
();
}
}
return
this
;
return
this
;
};
};
...
@@ -22,17 +22,16 @@
...
@@ -22,17 +22,16 @@
var
i
,
chatbox
,
num_chatboxes
=
converse
.
chatboxes
.
models
.
length
;
var
i
,
chatbox
,
num_chatboxes
=
converse
.
chatboxes
.
models
.
length
;
for
(
i
=
num_chatboxes
-
1
;
i
>-
1
;
i
--
)
{
for
(
i
=
num_chatboxes
-
1
;
i
>-
1
;
i
--
)
{
chatbox
=
converse
.
chatboxes
.
models
[
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
(
chatbox
.
get
(
'
id
'
)).
$el
.
remove
();
}
}
converse
.
chatboxviews
.
get
(
'
controlbox
'
).
close
Chat
();
converse
.
chatboxviews
.
get
(
'
controlbox
'
).
close
();
converse
.
chatboxviews
.
get
(
'
controlbox
'
).
$el
.
remove
();
converse
.
chatboxviews
.
get
(
'
controlbox
'
).
$el
.
remove
();
return
this
;
return
this
;
};
};
utils
.
initConverse
=
function
()
{
utils
.
initConverse
=
function
()
{
converse
.
chatboxes
=
new
converse
.
ChatBoxes
();
converse
.
_initialize
();
converse
.
chatboxviews
=
new
converse
.
ChatBoxViews
({
model
:
converse
.
chatboxes
});
converse
.
onConnected
();
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