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
273da9e8
Commit
273da9e8
authored
Aug 16, 2017
by
JC Brand
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move chatboxes collection and overview into separate plugin
parent
ad695c25
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
391 additions
and
330 deletions
+391
-330
src/config.js
src/config.js
+1
-0
src/converse-chatboxes.js
src/converse-chatboxes.js
+377
-0
src/converse-chatview.js
src/converse-chatview.js
+2
-0
src/converse-core.js
src/converse-core.js
+8
-328
src/converse-minimize.js
src/converse-minimize.js
+1
-1
src/converse-rosterview.js
src/converse-rosterview.js
+2
-1
No files found.
src/config.js
View file @
273da9e8
...
...
@@ -53,6 +53,7 @@ require.config({
"
inverse
"
:
"
src/inverse
"
,
"
converse-bookmarks
"
:
"
src/converse-bookmarks
"
,
"
converse-chatboxes
"
:
"
src/converse-chatboxes
"
,
"
converse-chatview
"
:
"
src/converse-chatview
"
,
"
converse-controlbox
"
:
"
src/converse-controlbox
"
,
"
converse-core
"
:
"
src/converse-core
"
,
...
...
src/converse-chatboxes.js
0 → 100644
View file @
273da9e8
// Converse.js (A browser based XMPP chat client)
// http://conversejs.org
//
// Copyright (c) 2012-2017, Jan-Carel Brand <jc@opkode.com>
// Licensed under the Mozilla Public License (MPLv2)
//
/*global define */
(
function
(
root
,
factory
)
{
define
([
"
converse-core
"
],
factory
);
}(
this
,
function
(
converse
)
{
"
use strict
"
;
const
{
Backbone
,
Strophe
,
b64_sha1
,
utils
,
_
}
=
converse
.
env
;
converse
.
plugins
.
add
(
'
converse-chatboxes
'
,
{
overrides
:
{
// Overrides mentioned here will be picked up by converse.js's
// plugin architecture they will replace existing methods on the
// relevant objects or classes.
disconnect
:
function
()
{
const
{
_converse
}
=
this
.
__super__
;
_converse
.
chatboxviews
.
closeAllChatBoxes
();
return
this
.
__super__
.
disconnect
.
apply
(
this
,
arguments
);
},
logOut
:
function
()
{
const
{
_converse
}
=
this
.
__super__
;
_converse
.
chatboxviews
.
closeAllChatBoxes
();
return
this
.
__super__
.
logOut
.
apply
(
this
,
arguments
);
},
initStatus
:
function
()
{
const
{
_converse
}
=
this
.
__super__
;
_converse
.
chatboxviews
.
closeAllChatBoxes
();
return
this
.
__super__
.
initStatus
.
apply
(
this
,
arguments
);
},
onStatusInitialized
:
function
()
{
const
{
_converse
}
=
this
.
__super__
;
_converse
.
chatboxes
.
onConnected
();
return
this
.
__super__
.
onStatusInitialized
.
apply
(
this
,
arguments
);
}
},
initialize
()
{
/* The initialize function gets called as soon as the plugin is
* loaded by converse.js's plugin machinery.
*/
const
{
_converse
}
=
this
;
_converse
.
api
.
promises
.
add
(
'
chatBoxesFetched
'
);
_converse
.
ChatBoxes
=
Backbone
.
Collection
.
extend
({
comparator
:
'
time_opened
'
,
model
(
attrs
,
options
)
{
return
new
_converse
.
ChatBox
(
attrs
,
options
);
},
registerMessageHandler
()
{
_converse
.
connection
.
addHandler
(
this
.
onMessage
.
bind
(
this
),
null
,
'
message
'
,
'
chat
'
);
_converse
.
connection
.
addHandler
(
this
.
onErrorMessage
.
bind
(
this
),
null
,
'
message
'
,
'
error
'
);
},
chatBoxMayBeShown
(
chatbox
)
{
return
true
;
},
onChatBoxesFetched
(
collection
)
{
/* Show chat boxes upon receiving them from sessionStorage
*
* This method gets overridden entirely in src/converse-controlbox.js
* if the controlbox plugin is active.
*/
collection
.
each
((
chatbox
)
=>
{
if
(
this
.
chatBoxMayBeShown
(
chatbox
))
{
chatbox
.
trigger
(
'
show
'
);
}
});
_converse
.
emit
(
'
chatBoxesFetched
'
);
},
onConnected
()
{
this
.
browserStorage
=
new
Backbone
.
BrowserStorage
[
_converse
.
storage
](
b64_sha1
(
`converse.chatboxes-
${
_converse
.
bare_jid
}
`
));
this
.
registerMessageHandler
();
this
.
fetch
({
add
:
true
,
success
:
this
.
onChatBoxesFetched
.
bind
(
this
)
});
},
onErrorMessage
(
message
)
{
/* Handler method for all incoming error message stanzas
*/
// TODO: we can likely just reuse "onMessage" below
const
from_jid
=
Strophe
.
getBareJidFromJid
(
message
.
getAttribute
(
'
from
'
));
if
(
utils
.
isSameBareJID
(
from_jid
,
_converse
.
bare_jid
))
{
return
true
;
}
// Get chat box, but only create a new one when the message has a body.
const
chatbox
=
this
.
getChatBox
(
from_jid
);
if
(
!
chatbox
)
{
return
true
;
}
chatbox
.
createMessage
(
message
,
null
,
message
);
return
true
;
},
onMessage
(
message
)
{
/* Handler method for all incoming single-user chat "message"
* stanzas.
*/
let
contact_jid
,
delay
,
resource
,
from_jid
=
message
.
getAttribute
(
'
from
'
),
to_jid
=
message
.
getAttribute
(
'
to
'
);
const
original_stanza
=
message
,
to_resource
=
Strophe
.
getResourceFromJid
(
to_jid
),
is_carbon
=
!
_
.
isNull
(
message
.
querySelector
(
`received[xmlns="
${
Strophe
.
NS
.
CARBONS
}
"]`
));
if
(
_converse
.
filter_by_resource
&&
(
to_resource
&&
to_resource
!==
_converse
.
resource
))
{
_converse
.
log
(
`onMessage: Ignoring incoming message intended for a different resource:
${
to_jid
}
`
,
Strophe
.
LogLevel
.
INFO
);
return
true
;
}
else
if
(
utils
.
isHeadlineMessage
(
message
))
{
// XXX: Ideally we wouldn't have to check for headline
// messages, but Prosody sends headline messages with the
// wrong type ('chat'), so we need to filter them out here.
_converse
.
log
(
`onMessage: Ignoring incoming headline message sent with type 'chat' from JID:
${
from_jid
}
`
,
Strophe
.
LogLevel
.
INFO
);
return
true
;
}
const
forwarded
=
message
.
querySelector
(
'
forwarded
'
);
if
(
!
_
.
isNull
(
forwarded
))
{
const
forwarded_message
=
forwarded
.
querySelector
(
'
message
'
);
const
forwarded_from
=
forwarded_message
.
getAttribute
(
'
from
'
);
if
(
is_carbon
&&
Strophe
.
getBareJidFromJid
(
forwarded_from
)
!==
from_jid
)
{
// Prevent message forging via carbons
//
// https://xmpp.org/extensions/xep-0280.html#security
return
true
;
}
message
=
forwarded_message
;
delay
=
forwarded
.
querySelector
(
'
delay
'
);
from_jid
=
message
.
getAttribute
(
'
from
'
);
to_jid
=
message
.
getAttribute
(
'
to
'
);
}
const
from_bare_jid
=
Strophe
.
getBareJidFromJid
(
from_jid
),
from_resource
=
Strophe
.
getResourceFromJid
(
from_jid
),
is_me
=
from_bare_jid
===
_converse
.
bare_jid
;
if
(
is_me
)
{
// I am the sender, so this must be a forwarded message...
contact_jid
=
Strophe
.
getBareJidFromJid
(
to_jid
);
resource
=
Strophe
.
getResourceFromJid
(
to_jid
);
}
else
{
contact_jid
=
from_bare_jid
;
resource
=
from_resource
;
}
// Get chat box, but only create a new one when the message has a body.
const
chatbox
=
this
.
getChatBox
(
contact_jid
,
!
_
.
isNull
(
message
.
querySelector
(
'
body
'
))),
msgid
=
message
.
getAttribute
(
'
id
'
);
if
(
chatbox
)
{
const
messages
=
msgid
&&
chatbox
.
messages
.
findWhere
({
msgid
})
||
[];
if
(
_
.
isEmpty
(
messages
))
{
// Only create the message when we're sure it's not a
// duplicate
chatbox
.
incrementUnreadMsgCounter
(
original_stanza
);
chatbox
.
createMessage
(
message
,
delay
,
original_stanza
);
}
}
_converse
.
emit
(
'
message
'
,
{
'
stanza
'
:
original_stanza
,
'
chatbox
'
:
chatbox
});
return
true
;
},
createChatBox
(
jid
,
attrs
)
{
/* Creates a chat box
*
* Parameters:
* (String) jid - The JID of the user for whom a chat box
* gets created.
* (Object) attrs - Optional chat box atributes.
*/
const
bare_jid
=
Strophe
.
getBareJidFromJid
(
jid
),
roster_item
=
_converse
.
roster
.
get
(
bare_jid
);
let
roster_info
=
{};
if
(
!
_
.
isUndefined
(
roster_item
))
{
roster_info
=
{
'
fullname
'
:
_
.
isEmpty
(
roster_item
.
get
(
'
fullname
'
))?
jid
:
roster_item
.
get
(
'
fullname
'
),
'
image_type
'
:
roster_item
.
get
(
'
image_type
'
),
'
image
'
:
roster_item
.
get
(
'
image
'
),
'
url
'
:
roster_item
.
get
(
'
url
'
),
};
}
else
if
(
!
_converse
.
allow_non_roster_messaging
)
{
_converse
.
log
(
`Could not get roster item for JID
${
bare_jid
}
`
+
'
and allow_non_roster_messaging is set to false
'
,
Strophe
.
LogLevel
.
ERROR
);
return
;
}
return
this
.
create
(
_
.
assignIn
({
'
id
'
:
bare_jid
,
'
jid
'
:
bare_jid
,
'
fullname
'
:
jid
,
'
image_type
'
:
_converse
.
DEFAULT_IMAGE_TYPE
,
'
image
'
:
_converse
.
DEFAULT_IMAGE
,
'
url
'
:
''
,
},
roster_info
,
attrs
||
{}));
},
getChatBox
(
jid
,
create
,
attrs
)
{
/* Returns a chat box or optionally return a newly
* created one if one doesn't exist.
*
* Parameters:
* (String) jid - The JID of the user whose chat box we want
* (Boolean) create - Should a new chat box be created if none exists?
* (Object) attrs - Optional chat box atributes.
*/
jid
=
jid
.
toLowerCase
();
let
chatbox
=
this
.
get
(
Strophe
.
getBareJidFromJid
(
jid
));
if
(
!
chatbox
&&
create
)
{
chatbox
=
this
.
createChatBox
(
jid
,
attrs
);
}
return
chatbox
;
}
});
_converse
.
ChatBoxViews
=
Backbone
.
Overview
.
extend
({
initialize
()
{
this
.
model
.
on
(
"
add
"
,
this
.
onChatBoxAdded
,
this
);
this
.
model
.
on
(
"
destroy
"
,
this
.
removeChat
,
this
);
},
_ensureElement
()
{
/* Override method from backbone.js
* If the #conversejs element doesn't exist, create it.
*/
if
(
!
this
.
el
)
{
let
el
=
document
.
querySelector
(
'
#conversejs
'
);
if
(
_
.
isNull
(
el
))
{
el
=
document
.
createElement
(
'
div
'
);
el
.
setAttribute
(
'
id
'
,
'
conversejs
'
);
// Converse.js expects a <body> tag to be present.
document
.
querySelector
(
'
body
'
).
appendChild
(
el
);
}
el
.
innerHTML
=
''
;
this
.
setElement
(
el
,
false
);
}
else
{
this
.
setElement
(
_
.
result
(
this
,
'
el
'
),
false
);
}
},
onChatBoxAdded
(
item
)
{
// Views aren't created here, since the core code doesn't
// contain any views. Instead, they're created in overrides in
// plugins, such as in converse-chatview.js and converse-muc.js
return
this
.
get
(
item
.
get
(
'
id
'
));
},
removeChat
(
item
)
{
this
.
remove
(
item
.
get
(
'
id
'
));
},
closeAllChatBoxes
()
{
/* This method gets overridden in src/converse-controlbox.js if
* the controlbox plugin is active.
*/
this
.
each
(
function
(
view
)
{
view
.
close
();
});
return
this
;
},
chatBoxMayBeShown
(
chatbox
)
{
return
this
.
model
.
chatBoxMayBeShown
(
chatbox
);
},
getChatBox
(
attrs
,
create
)
{
let
chatbox
=
this
.
model
.
get
(
attrs
.
jid
);
if
(
!
chatbox
&&
create
)
{
chatbox
=
this
.
model
.
create
(
attrs
,
{
'
error
'
(
model
,
response
)
{
_converse
.
log
(
response
.
responseText
);
}
});
}
return
chatbox
;
},
showChat
(
attrs
)
{
/* Find the chat box and show it (if it may be shown).
* If it doesn't exist, create it.
*/
const
chatbox
=
this
.
getChatBox
(
attrs
,
true
);
if
(
this
.
chatBoxMayBeShown
(
chatbox
))
{
chatbox
.
trigger
(
'
show
'
,
true
);
}
return
chatbox
;
}
});
_converse
.
chatboxes
=
new
_converse
.
ChatBoxes
();
_converse
.
chatboxviews
=
new
_converse
.
ChatBoxViews
({
'
model
'
:
this
.
chatboxes
});
_converse
.
api
.
listen
.
on
(
'
beforeTearDown
'
,
()
=>
{
this
.
chatboxes
.
remove
();
// Don't call off(), events won't get re-registered upon reconnect.
delete
this
.
chatboxes
.
browserStorage
;
});
_converse
.
getViewForChatBox
=
function
(
chatbox
)
{
if
(
!
chatbox
)
{
return
;
}
return
_converse
.
chatboxviews
.
get
(
chatbox
.
get
(
'
id
'
));
};
/* We extend the default converse.js API */
_
.
extend
(
_converse
.
api
,
{
'
chats
'
:
{
'
open
'
(
jids
,
attrs
)
{
debugger
;
if
(
_
.
isUndefined
(
jids
))
{
_converse
.
log
(
"
chats.open: You need to provide at least one JID
"
,
Strophe
.
LogLevel
.
ERROR
);
return
null
;
}
else
if
(
_
.
isString
(
jids
))
{
return
_converse
.
getViewForChatBox
(
_converse
.
chatboxes
.
getChatBox
(
jids
,
true
,
attrs
).
trigger
(
'
show
'
)
);
}
return
_
.
map
(
jids
,
(
jid
)
=>
_converse
.
getViewForChatBox
(
_converse
.
chatboxes
.
getChatBox
(
jid
,
true
,
attrs
).
trigger
(
'
show
'
)
)
);
},
'
get
'
(
jids
)
{
if
(
_
.
isUndefined
(
jids
))
{
const
result
=
[];
_converse
.
chatboxes
.
each
(
function
(
chatbox
)
{
// FIXME: Leaky abstraction from MUC. We need to add a
// base type for chat boxes, and check for that.
if
(
chatbox
.
get
(
'
type
'
)
!==
'
chatroom
'
)
{
result
.
push
(
_converse
.
getViewForChatBox
(
chatbox
));
}
});
return
result
;
}
else
if
(
_
.
isString
(
jids
))
{
return
_converse
.
getViewForChatBox
(
_converse
.
chatboxes
.
getChatBox
(
jids
));
}
return
_
.
map
(
jids
,
_
.
partial
(
_
.
flow
(
_converse
.
chatboxes
.
getChatBox
.
bind
(
_converse
.
chatboxes
),
_converse
.
getViewForChatBox
.
bind
(
_converse
)
),
_
,
true
)
);
}
}
});
}
});
return
converse
;
}));
src/converse-chatview.js
View file @
273da9e8
...
...
@@ -10,6 +10,7 @@
define
([
"
jquery.noconflict
"
,
"
converse-core
"
,
"
converse-chatboxes
"
,
"
emojione
"
,
"
xss
"
,
"
tpl!chatbox
"
,
...
...
@@ -25,6 +26,7 @@
}(
this
,
function
(
$
,
converse
,
dummy
,
emojione
,
xss
,
tpl_chatbox
,
...
...
src/converse-core.js
View file @
273da9e8
...
...
@@ -51,6 +51,7 @@
_converse
.
core_plugins
=
[
'
converse-bookmarks
'
,
'
converse-chatboxes
'
,
'
converse-chatview
'
,
'
converse-controlbox
'
,
'
converse-core
'
,
...
...
@@ -112,8 +113,8 @@
9
:
'
REDIRECT
'
};
const
DEFAULT_IMAGE_TYPE
=
'
image/png
'
;
const
DEFAULT_IMAGE
=
"
iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAIAAABt+uBvAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gwHCy455JBsggAABkJJREFUeNrtnM1PE1sUwHvvTD8otWLHST/Gimi1CEgr6M6FEWuIBo2pujDVsNDEP8GN/4MbN7oxrlipG2OCgZgYlxAbkRYw1KqkIDRCSkM7nXvvW8x7vjyNeQ9m7p1p3z1LQk/v/Dhz7vkEXL161cHl9wI5Ag6IA+KAOCAOiAPigDggLhwQB2S+iNZ+PcYY/SWEEP2HAAAIoSAIoihCCP+ngDDGtVotGAz29/cfOXJEUZSOjg6n06lp2sbGRqlUWlhYyGazS0tLbrdbEASrzgksyeYJId3d3el0uqenRxRFAAAA4KdfIIRgjD9+/Pj8+fOpqSndslofEIQwHA6Pjo4mEon//qmFhYXHjx8vLi4ihBgDEnp7e9l8E0Jo165dQ0NDd+/eDYVC2/qsJElDQ0OEkKWlpa2tLZamxAhQo9EIBoOjo6MXL17csZLe3l5FUT59+lQul5l5JRaAVFWNRqN37tw5ceKEQVWRSOTw4cOFQuHbt2+iKLYCIISQLMu3b99OJpOmKAwEAgcPHszn8+vr6wzsiG6UQQhxuVyXLl0aGBgwUW0sFstkMl6v90fo1KyAMMYDAwPnzp0zXfPg4GAqlWo0Gk0MiBAiy/L58+edTqf5Aa4onj59OhaLYYybFRCEMBaL0fNxBw4cSCQStN0QRUBut3t4eJjq6U+dOiVJElVPRBFQIBDo6+ujCqirqyscDlONGykC2lYyYSR6pBoQQapHZwAoHo/TuARYAOrs7GQASFEUqn6aIiBJkhgA6ujooFpUo6iaTa7koFwnaoWadLNe81tbWwzoaJrWrICWl5cZAFpbW6OabVAEtLi4yABQsVjUNK0pAWWzWQaAcrlcswKanZ1VVZUqHYRQEwOq1Wpv3ryhCmh6erpcLjdrNl+v1ycnJ+l5UELI27dvv3//3qxxEADgy5cvExMT9Mznw4cPtFtAdAPFarU6Pj5eKpVM17yxsfHy5cvV1VXazXu62gVBKBQKT58+rdVqJqrFGL948eLdu3dU8/g/H4FBUaJYLAqC0NPTY9brMD4+PjY25mDSracOCABACJmZmXE6nUePHjWu8NWrV48ePSKEsGlAs7Agfd5nenq6Wq0mk0kjDzY2NvbkyRMIIbP2PLvhBUEQ8vl8NpuNx+M+n29bzhVjvLKycv/+/YmJCcazQuwA6YzW1tYmJyf1SY+2trZ/rRk1Go1SqfT69esHDx4UCgVmNaa/zZ/9ABUhRFXVYDB48uTJeDweiUQkSfL7/T9MA2NcqVTK5fLy8vL8/PzU1FSxWHS5XJaM4wGr9sUwxqqqer3eUCgkSZJuUBBCfTRvc3OzXC6vrKxUKhWn02nhCJ5lM4oQQo/HgxD6+vXr58+fHf8sDOp+HQDg8XgclorFU676dKLlo6yWRdItIBwQB8QBcUCtfosRQjRNQwhhjPUC4w46WXryBSHU1zgEQWBz99EFhDGu1+t+v//48ePxeFxRlD179ng8nh0Efgiher2+vr6ur3HMzMysrq7uTJVdACGEurq6Ll++nEgkPB7Pj9jPoDHqOxyqqubz+WfPnuVyuV9XPeyeagAAAoHArVu3BgcHab8CuVzu4cOHpVKJUnfA5GweY+xyuc6cOXPv3r1IJMLAR8iyPDw8XK/Xi8Wiqqqmm5KZgBBC7e3tN27cuHbtGuPVpf7+/lAoNDs7W61WzfVKpgHSSzw3b95MpVKW3MfRaDQSiczNzVUqFRMZmQOIEOL1eq9fv3727FlL1t50URRFluX5+flqtWpWEGAOIFEUU6nUlStXLKSjy759+xwOx9zcnKZpphzGHMzhcDiTydgk9r1w4YIp7RPTAAmCkMlk2FeLf/tIEKbTab/fbwtAhJBoNGrutpNx6e7uPnTokC1eMU3T0um0DZPMkZER6wERQnw+n/FFSxpy7Nix3bt3WwwIIcRgIWnHkkwmjecfRgGx7DtuV/r6+iwGhDHev3+/bQF1dnYaH6E2CkiWZdsC2rt3r8WAHA5HW1ubbQGZcjajgOwTH/4qNko1Wlg4IA6IA+KAOKBWBUQIsfNojyliKIoRRfH9+/dut9umf3wzpoUNNQ4BAJubmwz+ic+OxefzWWlBhJD29nbug7iT5sIBcUAcEAfEAXFAHBAHxOVn+QMrmWpuPZx12gAAAABJRU5ErkJggg==
"
;
_converse
.
DEFAULT_IMAGE_TYPE
=
'
image/png
'
;
_converse
.
DEFAULT_IMAGE
=
"
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
"
;
_converse
.
log
=
function
(
message
,
level
)
{
if
(
message
instanceof
Error
)
{
...
...
@@ -150,7 +151,6 @@
const
PROMISES
=
[
'
cachedRoster
'
,
'
chatBoxesFetched
'
,
'
pluginsInitialized
'
,
'
roster
'
,
'
rosterContactsFetched
'
,
...
...
@@ -182,7 +182,7 @@
_
.
each
(
PROMISES
,
addPromise
);
if
(
!
_
.
isUndefined
(
_converse
.
c
hatboxes
))
{
if
(
!
_
.
isUndefined
(
_converse
.
c
onnection
))
{
// Looks like _converse.initialized was called again without logging
// out or disconnecting in the previous session.
// This happens in tests. We therefore first clean up.
...
...
@@ -320,10 +320,6 @@
// Module-level functions
// ----------------------
this
.
getViewForChatBox
=
function
(
chatbox
)
{
if
(
!
chatbox
)
{
return
;
}
return
_converse
.
chatboxviews
.
get
(
chatbox
.
get
(
'
id
'
));
};
this
.
generateResource
=
()
=>
`/converse.js-
${
Math
.
floor
(
Math
.
random
()
*
139749825
).
toString
()}
`
;
...
...
@@ -455,7 +451,6 @@
delete
_converse
.
connection
.
reconnecting
;
_converse
.
connection
.
reset
();
_converse
.
_tearDown
();
_converse
.
chatboxviews
.
closeAllChatBoxes
();
_converse
.
emit
(
'
disconnected
'
);
};
...
...
@@ -596,9 +591,7 @@
};
this
.
logOut
=
function
()
{
_converse
.
chatboxviews
.
closeAllChatBoxes
();
_converse
.
clearSession
();
_converse
.
setDisconnectionCause
(
_converse
.
LOGOUT
,
undefined
,
true
);
if
(
!
_
.
isUndefined
(
_converse
.
connection
))
{
_converse
.
connection
.
disconnect
();
...
...
@@ -750,10 +743,7 @@
_converse
.
registerIntervalHandler
();
_converse
.
initRoster
();
}
// First set up chat boxes, before populating the roster, so that
// the controlbox is properly set up and ready for the rosterview.
_converse
.
roster
.
onConnected
();
_converse
.
chatboxes
.
onConnected
();
_converse
.
populateRoster
();
_converse
.
registerPresenceHandler
();
_converse
.
giveFeedback
(
__
(
'
Contacts
'
));
...
...
@@ -791,7 +781,6 @@
_converse
.
onStatusInitialized
(
true
);
_converse
.
emit
(
'
reconnected
'
);
}
else
{
_converse
.
chatboxviews
.
closeAllChatBoxes
();
_converse
.
initStatus
()
.
then
(
_
.
partial
(
_converse
.
onStatusInitialized
,
false
),
...
...
@@ -808,8 +797,8 @@
'
chat_state
'
:
undefined
,
'
chat_status
'
:
'
offline
'
,
'
groups
'
:
[],
'
image
'
:
DEFAULT_IMAGE
,
'
image_type
'
:
DEFAULT_IMAGE_TYPE
,
'
image
'
:
_converse
.
DEFAULT_IMAGE
,
'
image_type
'
:
_converse
.
DEFAULT_IMAGE_TYPE
,
'
num_unread
'
:
0
,
'
status
'
:
''
,
},
...
...
@@ -1519,267 +1508,6 @@
}
});
this
.
ChatBoxes
=
Backbone
.
Collection
.
extend
({
comparator
:
'
time_opened
'
,
model
(
attrs
,
options
)
{
return
new
_converse
.
ChatBox
(
attrs
,
options
);
},
registerMessageHandler
()
{
_converse
.
connection
.
addHandler
(
this
.
onMessage
.
bind
(
this
),
null
,
'
message
'
,
'
chat
'
);
_converse
.
connection
.
addHandler
(
this
.
onErrorMessage
.
bind
(
this
),
null
,
'
message
'
,
'
error
'
);
},
chatBoxMayBeShown
(
chatbox
)
{
return
true
;
},
onChatBoxesFetched
(
collection
)
{
/* Show chat boxes upon receiving them from sessionStorage
*
* This method gets overridden entirely in src/converse-controlbox.js
* if the controlbox plugin is active.
*/
collection
.
each
((
chatbox
)
=>
{
if
(
this
.
chatBoxMayBeShown
(
chatbox
))
{
chatbox
.
trigger
(
'
show
'
);
}
});
_converse
.
emit
(
'
chatBoxesFetched
'
);
},
onConnected
()
{
this
.
browserStorage
=
new
Backbone
.
BrowserStorage
[
_converse
.
storage
](
b64_sha1
(
`converse.chatboxes-
${
_converse
.
bare_jid
}
`
));
this
.
registerMessageHandler
();
this
.
fetch
({
add
:
true
,
success
:
this
.
onChatBoxesFetched
.
bind
(
this
)
});
},
onErrorMessage
(
message
)
{
/* Handler method for all incoming error message stanzas
*/
// TODO: we can likely just reuse "onMessage" below
const
from_jid
=
Strophe
.
getBareJidFromJid
(
message
.
getAttribute
(
'
from
'
));
if
(
utils
.
isSameBareJID
(
from_jid
,
_converse
.
bare_jid
))
{
return
true
;
}
// Get chat box, but only create a new one when the message has a body.
const
chatbox
=
this
.
getChatBox
(
from_jid
);
if
(
!
chatbox
)
{
return
true
;
}
chatbox
.
createMessage
(
message
,
null
,
message
);
return
true
;
},
onMessage
(
message
)
{
/* Handler method for all incoming single-user chat "message"
* stanzas.
*/
let
contact_jid
,
delay
,
resource
,
from_jid
=
message
.
getAttribute
(
'
from
'
),
to_jid
=
message
.
getAttribute
(
'
to
'
);
const
original_stanza
=
message
,
to_resource
=
Strophe
.
getResourceFromJid
(
to_jid
),
is_carbon
=
!
_
.
isNull
(
message
.
querySelector
(
`received[xmlns="
${
Strophe
.
NS
.
CARBONS
}
"]`
));
if
(
_converse
.
filter_by_resource
&&
(
to_resource
&&
to_resource
!==
_converse
.
resource
))
{
_converse
.
log
(
`onMessage: Ignoring incoming message intended for a different resource:
${
to_jid
}
`
,
Strophe
.
LogLevel
.
INFO
);
return
true
;
}
else
if
(
utils
.
isHeadlineMessage
(
message
))
{
// XXX: Ideally we wouldn't have to check for headline
// messages, but Prosody sends headline messages with the
// wrong type ('chat'), so we need to filter them out here.
_converse
.
log
(
`onMessage: Ignoring incoming headline message sent with type 'chat' from JID:
${
from_jid
}
`
,
Strophe
.
LogLevel
.
INFO
);
return
true
;
}
const
forwarded
=
message
.
querySelector
(
'
forwarded
'
);
if
(
!
_
.
isNull
(
forwarded
))
{
const
forwarded_message
=
forwarded
.
querySelector
(
'
message
'
);
const
forwarded_from
=
forwarded_message
.
getAttribute
(
'
from
'
);
if
(
is_carbon
&&
Strophe
.
getBareJidFromJid
(
forwarded_from
)
!==
from_jid
)
{
// Prevent message forging via carbons
//
// https://xmpp.org/extensions/xep-0280.html#security
return
true
;
}
message
=
forwarded_message
;
delay
=
forwarded
.
querySelector
(
'
delay
'
);
from_jid
=
message
.
getAttribute
(
'
from
'
);
to_jid
=
message
.
getAttribute
(
'
to
'
);
}
const
from_bare_jid
=
Strophe
.
getBareJidFromJid
(
from_jid
),
from_resource
=
Strophe
.
getResourceFromJid
(
from_jid
),
is_me
=
from_bare_jid
===
_converse
.
bare_jid
;
if
(
is_me
)
{
// I am the sender, so this must be a forwarded message...
contact_jid
=
Strophe
.
getBareJidFromJid
(
to_jid
);
resource
=
Strophe
.
getResourceFromJid
(
to_jid
);
}
else
{
contact_jid
=
from_bare_jid
;
resource
=
from_resource
;
}
// Get chat box, but only create a new one when the message has a body.
const
chatbox
=
this
.
getChatBox
(
contact_jid
,
!
_
.
isNull
(
message
.
querySelector
(
'
body
'
))),
msgid
=
message
.
getAttribute
(
'
id
'
);
if
(
chatbox
)
{
const
messages
=
msgid
&&
chatbox
.
messages
.
findWhere
({
msgid
})
||
[];
if
(
_
.
isEmpty
(
messages
))
{
// Only create the message when we're sure it's not a
// duplicate
chatbox
.
incrementUnreadMsgCounter
(
original_stanza
);
chatbox
.
createMessage
(
message
,
delay
,
original_stanza
);
}
}
_converse
.
emit
(
'
message
'
,
{
'
stanza
'
:
original_stanza
,
'
chatbox
'
:
chatbox
});
return
true
;
},
createChatBox
(
jid
,
attrs
)
{
/* Creates a chat box
*
* Parameters:
* (String) jid - The JID of the user for whom a chat box
* gets created.
* (Object) attrs - Optional chat box atributes.
*/
const
bare_jid
=
Strophe
.
getBareJidFromJid
(
jid
),
roster_item
=
_converse
.
roster
.
get
(
bare_jid
);
let
roster_info
=
{};
if
(
!
_
.
isUndefined
(
roster_item
))
{
roster_info
=
{
'
fullname
'
:
_
.
isEmpty
(
roster_item
.
get
(
'
fullname
'
))?
jid
:
roster_item
.
get
(
'
fullname
'
),
'
image_type
'
:
roster_item
.
get
(
'
image_type
'
),
'
image
'
:
roster_item
.
get
(
'
image
'
),
'
url
'
:
roster_item
.
get
(
'
url
'
),
};
}
else
if
(
!
_converse
.
allow_non_roster_messaging
)
{
_converse
.
log
(
`Could not get roster item for JID
${
bare_jid
}
`
+
'
and allow_non_roster_messaging is set to false
'
,
Strophe
.
LogLevel
.
ERROR
);
return
;
}
return
this
.
create
(
_
.
assignIn
({
'
id
'
:
bare_jid
,
'
jid
'
:
bare_jid
,
'
fullname
'
:
jid
,
'
image_type
'
:
DEFAULT_IMAGE_TYPE
,
'
image
'
:
DEFAULT_IMAGE
,
'
url
'
:
''
,
},
roster_info
,
attrs
||
{}));
},
getChatBox
(
jid
,
create
,
attrs
)
{
/* Returns a chat box or optionally return a newly
* created one if one doesn't exist.
*
* Parameters:
* (String) jid - The JID of the user whose chat box we want
* (Boolean) create - Should a new chat box be created if none exists?
* (Object) attrs - Optional chat box atributes.
*/
jid
=
jid
.
toLowerCase
();
let
chatbox
=
this
.
get
(
Strophe
.
getBareJidFromJid
(
jid
));
if
(
!
chatbox
&&
create
)
{
chatbox
=
this
.
createChatBox
(
jid
,
attrs
);
}
return
chatbox
;
}
});
this
.
ChatBoxViews
=
Backbone
.
Overview
.
extend
({
initialize
()
{
this
.
model
.
on
(
"
add
"
,
this
.
onChatBoxAdded
,
this
);
this
.
model
.
on
(
"
destroy
"
,
this
.
removeChat
,
this
);
},
_ensureElement
()
{
/* Override method from backbone.js
* If the #conversejs element doesn't exist, create it.
*/
if
(
!
this
.
el
)
{
let
el
=
document
.
querySelector
(
'
#conversejs
'
);
if
(
_
.
isNull
(
el
))
{
el
=
document
.
createElement
(
'
div
'
);
el
.
setAttribute
(
'
id
'
,
'
conversejs
'
);
// Converse.js expects a <body> tag to be present.
document
.
querySelector
(
'
body
'
).
appendChild
(
el
);
}
el
.
innerHTML
=
''
;
this
.
setElement
(
el
,
false
);
}
else
{
this
.
setElement
(
_
.
result
(
this
,
'
el
'
),
false
);
}
},
onChatBoxAdded
(
item
)
{
// Views aren't created here, since the core code doesn't
// contain any views. Instead, they're created in overrides in
// plugins, such as in converse-chatview.js and converse-muc.js
return
this
.
get
(
item
.
get
(
'
id
'
));
},
removeChat
(
item
)
{
this
.
remove
(
item
.
get
(
'
id
'
));
},
closeAllChatBoxes
()
{
/* This method gets overridden in src/converse-controlbox.js if
* the controlbox plugin is active.
*/
this
.
each
(
function
(
view
)
{
view
.
close
();
});
return
this
;
},
chatBoxMayBeShown
(
chatbox
)
{
return
this
.
model
.
chatBoxMayBeShown
(
chatbox
);
},
getChatBox
(
attrs
,
create
)
{
let
chatbox
=
this
.
model
.
get
(
attrs
.
jid
);
if
(
!
chatbox
&&
create
)
{
chatbox
=
this
.
model
.
create
(
attrs
,
{
'
error
'
(
model
,
response
)
{
_converse
.
log
(
response
.
responseText
);
}
});
}
return
chatbox
;
},
showChat
(
attrs
)
{
/* Find the chat box and show it (if it may be shown).
* If it doesn't exist, create it.
*/
const
chatbox
=
this
.
getChatBox
(
attrs
,
true
);
if
(
this
.
chatBoxMayBeShown
(
chatbox
))
{
chatbox
.
trigger
(
'
show
'
,
true
);
}
return
chatbox
;
}
});
this
.
XMPPStatus
=
Backbone
.
Model
.
extend
({
initialize
()
{
this
.
set
({
...
...
@@ -1886,7 +1614,7 @@
};
xhr
.
onerror
=
function
()
{
delete
_converse
.
connection
;
_converse
.
emit
(
'
noResumeableSession
'
);
_converse
.
emit
(
'
noResumeableSession
'
,
this
);
reject
(
xhr
.
responseText
);
};
xhr
.
send
();
...
...
@@ -1908,7 +1636,7 @@
};
xhr
.
onerror
=
function
()
{
delete
_converse
.
connection
;
_converse
.
emit
(
'
noResumeableSession
'
);
_converse
.
emit
(
'
noResumeableSession
'
,
this
);
};
xhr
.
send
();
};
...
...
@@ -2076,8 +1804,6 @@
if
(
this
.
roster
)
{
this
.
roster
.
off
().
reset
();
// Removes roster contacts
}
this
.
chatboxes
.
remove
();
// Don't call off(), events won't get re-registered upon reconnect.
delete
this
.
chatboxes
.
browserStorage
;
this
.
session
.
destroy
();
window
.
removeEventListener
(
'
click
'
,
_converse
.
onUserActivity
);
window
.
removeEventListener
(
'
focus
'
,
_converse
.
onUserActivity
);
...
...
@@ -2089,11 +1815,6 @@
return
this
;
};
this
.
initChatBoxes
=
function
()
{
this
.
chatboxes
=
new
this
.
ChatBoxes
();
this
.
chatboxviews
=
new
this
.
ChatBoxViews
({
model
:
this
.
chatboxes
});
};
this
.
initPlugins
=
function
()
{
// If initialize gets called a second time (e.g. during tests), then we
// need to re-apply all plugins (for a new converse instance), and we
...
...
@@ -2127,7 +1848,6 @@
this
.
connection
=
settings
.
connection
;
}
_converse
.
initPlugins
();
_converse
.
initChatBoxes
();
_converse
.
initConnection
();
_converse
.
setUpXMLLogging
();
_converse
.
logIn
();
...
...
@@ -2240,46 +1960,6 @@
_converse
.
roster
.
addAndSubscribe
(
jid
,
_
.
isEmpty
(
name
)?
jid
:
name
);
}
},
'
chats
'
:
{
'
open
'
(
jids
,
attrs
)
{
if
(
_
.
isUndefined
(
jids
))
{
_converse
.
log
(
"
chats.open: You need to provide at least one JID
"
,
Strophe
.
LogLevel
.
ERROR
);
return
null
;
}
else
if
(
_
.
isString
(
jids
))
{
return
_converse
.
getViewForChatBox
(
_converse
.
chatboxes
.
getChatBox
(
jids
,
true
,
attrs
).
trigger
(
'
show
'
)
);
}
return
_
.
map
(
jids
,
(
jid
)
=>
_converse
.
getViewForChatBox
(
_converse
.
chatboxes
.
getChatBox
(
jid
,
true
,
attrs
).
trigger
(
'
show
'
)
)
);
},
'
get
'
(
jids
)
{
if
(
_
.
isUndefined
(
jids
))
{
const
result
=
[];
_converse
.
chatboxes
.
each
(
function
(
chatbox
)
{
// FIXME: Leaky abstraction from MUC. We need to add a
// base type for chat boxes, and check for that.
if
(
chatbox
.
get
(
'
type
'
)
!==
'
chatroom
'
)
{
result
.
push
(
_converse
.
getViewForChatBox
(
chatbox
));
}
});
return
result
;
}
else
if
(
_
.
isString
(
jids
))
{
return
_converse
.
getViewForChatBox
(
_converse
.
chatboxes
.
getChatBox
(
jids
));
}
return
_
.
map
(
jids
,
_
.
partial
(
_
.
flow
(
_converse
.
chatboxes
.
getChatBox
.
bind
(
_converse
.
chatboxes
),
_converse
.
getViewForChatBox
.
bind
(
_converse
)
),
_
,
true
)
);
}
},
'
tokens
'
:
{
'
get
'
(
id
)
{
if
(
!
_converse
.
expose_rid_and_sid
||
_
.
isUndefined
(
_converse
.
connection
))
{
...
...
src/converse-minimize.js
View file @
273da9e8
...
...
@@ -13,8 +13,8 @@
"
tpl!toggle_chats
"
,
"
tpl!trimmed_chat
"
,
"
tpl!chats_panel
"
,
"
converse-controlbox
"
,
"
converse-chatview
"
,
"
converse-controlbox
"
,
"
converse-muc
"
],
factory
);
}(
this
,
function
(
...
...
src/converse-rosterview.js
View file @
273da9e8
...
...
@@ -14,7 +14,8 @@
"
tpl!requesting_contact
"
,
"
tpl!roster
"
,
"
tpl!roster_filter
"
,
"
tpl!roster_item
"
"
tpl!roster_item
"
,
"
converse-chatboxes
"
],
factory
);
}(
this
,
function
(
$
,
...
...
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