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
1ef29bee
Commit
1ef29bee
authored
May 24, 2019
by
JC Brand
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use composition instead of overrides
parent
d2b1f2c9
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
735 additions
and
784 deletions
+735
-784
docs/source/plugin_development.rst
docs/source/plugin_development.rst
+135
-147
src/converse-bookmark-views.js
src/converse-bookmark-views.js
+62
-66
src/converse-controlbox.js
src/converse-controlbox.js
+2
-18
src/converse-dragresize.js
src/converse-dragresize.js
+140
-158
src/converse-minimize.js
src/converse-minimize.js
+109
-88
src/converse-muc-views.js
src/converse-muc-views.js
+31
-28
src/converse-oauth.js
src/converse-oauth.js
+2
-2
src/converse-omemo.js
src/converse-omemo.js
+118
-123
src/converse-register.js
src/converse-register.js
+49
-45
src/converse-rosterview.js
src/converse-rosterview.js
+10
-61
src/converse-singleton.js
src/converse-singleton.js
+1
-1
src/headless/converse-bookmarks.js
src/headless/converse-bookmarks.js
+1
-3
src/headless/converse-core.js
src/headless/converse-core.js
+1
-1
src/headless/converse-mam.js
src/headless/converse-mam.js
+42
-43
src/headless/converse-roster.js
src/headless/converse-roster.js
+32
-0
No files found.
docs/source/plugin_development.rst
View file @
1ef29bee
...
...
@@ -189,14 +189,13 @@ The code for it would look something like this:
// Commonly used utilities and variables can be found under the "env"
// namespace of the "converse" global.
var Strophe = converse.env.Strophe,
$iq = converse.env.$iq,
$msg = converse.env.$msg,
$pres = converse.env.$pres,
$build = converse.env.$build,
b64_sha1 = converse.env.b64_sha1,
_ = converse.env._,
dayjs = converse.env.dayjs;
const Strophe = converse.env.Strophe,
$iq = converse.env.$iq,
$msg = converse.env.$msg,
$pres = converse.env.$pres,
$build = converse.env.$build,
_ = converse.env._,
dayjs = converse.env.dayjs;
These dependencies are closured so that they don't pollute the global
namespace, that's why you need to access them in such a way inside the module.
...
...
@@ -300,7 +299,7 @@ In this case, you should first listen for the ``connection`` event, and then do
converse.plugins.add('myplugin', {
initialize: function () {
var
_converse = this._converse;
const
_converse = this._converse;
_converse.api.listen.on('connected', function () {
_converse.api.archive.query({'with': 'admin2@localhost'});
...
...
@@ -363,152 +362,141 @@ generated by `generator-conversejs <https://github.com/jcbrand/generator-convers
.. code-block:: javascript
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as a module called "myplugin"
define(["converse"], factory);
} else {
// Browser globals. If you're not using a module loader such as require.js,
// then this line below executes. Make sure that your plugin's <script> tag
// appears after the one from converse.js.
factory(converse);
}
}(this, function (converse) {
import converse from "@converse/headless/converse-core";
// Commonly used utilities and variables can be found under the "env"
// namespace of the "converse" global.
const Strophe = converse.env.Strophe,
$iq = converse.env.$iq,
$msg = converse.env.$msg,
$pres = converse.env.$pres,
$build = converse.env.$build,
_ = converse.env._,
dayjs = converse.env.dayjs;
// The following line registers your plugin.
converse.plugins.add("myplugin", {
/* Dependencies are other plugins which might be
* overridden or relied upon, and therefore need to be loaded before
* this plugin. They are "optional" because they might not be
* available, in which case any overrides applicable to them will be
* ignored.
*
* NB: These plugins need to have already been imported or loaded,
* either in your plugin or somewhere else.
*
* It's possible to make these dependencies "non-optional".
* If the setting "strict_plugin_dependencies" is set to true,
* an error will be raised if the plugin is not found.
*/
'dependencies': [],
/* Converse.js's plugin mechanism will call the initialize
* method on any plugin (if it exists) as soon as the plugin has
* been loaded.
*/
'initialize': function () {
/* Inside this method, you have access to the private
* `_converse` object.
*/
const _converse = this._converse;
_converse.log("The \"myplugin\" plugin is being initialized");
/* From the `_converse` object you can get any configuration
* options that the user might have passed in via
* `converse.initialize`.
*
* You can also specify new configuration settings for this
* plugin, or override the default values of existing
* configuration settings. This is done like so:
*/
_converse.api.settings.update({
'initialize_message': 'Initializing myplugin!'
});
/* The user can then pass in values for the configuration
* settings when `converse.initialize` gets called.
* For example:
*
* converse.initialize({
* "initialize_message": "My plugin has been initialized"
* });
*/
alert(this._converse.initialize_message);
// Commonly used utilities and variables can be found under the "env"
// namespace of the "converse" global.
var Strophe = converse.env.Strophe,
$iq = converse.env.$iq,
$msg = converse.env.$msg,
$pres = converse.env.$pres,
$build = converse.env.$build,
b64_sha1 = converse.env.b64_sha1,
_ = converse.env._,
dayjs = converse.env.dayjs;
// The following line registers your plugin.
converse.plugins.add("myplugin", {
/* Dependencies are other plugins which might be
* overridden or relied upon, and therefore need to be loaded before
* this plugin. They are "optional" because they might not be
* available, in which case any overrides applicable to them will be
* ignored.
/* Besides `_converse.api.settings.update`, there is also a
* `_converse.api.promises.add` method, which allows you to
* add new promises that your plugin is obligated to fulfill.
*
* This method takes a string or a list of strings which
* represent the promise names:
*
* _converse.api.promises.add('myPromise');
*
* Your plugin should then, when appropriate, resolve the
* promise by calling `_converse.api.emit`, which will also
* emit an event with the same name as the promise.
* For example:
*
*
NB: These plugins need to have already been loaded via require.js.
*
_converse.api.trigger('operationCompleted');
*
* It's possible to make these dependencies "non-optional".
* If the setting "strict_plugin_dependencies" is set to true,
* an error will be raised if the plugin is not found.
* Other plugins can then either listen for the event
* `operationCompleted` like so:
*
* _converse.api.listen.on('operationCompleted', function { ... });
*
* or they can wait for the promise to be fulfilled like so:
*
* _converse.api.waitUntil('operationCompleted', function { ... });
*/
'dependencies': []
,
}
,
/* Converse.js's plugin mechanism will call the initialize
* method on any plugin (if it exists) as soon as the plugin has
* been loaded.
/* If you want to override some function or a Backbone model or
* view defined elsewhere in converse.js, then you do that under
* the "overrides" namespace.
*/
'overrides': {
/* For example, the private *_converse* object has a
* method "onConnected". You can override that method as follows:
*/
'initialize': function () {
/* Inside this method, you have access to the private
* `_converse` object.
*/
var _converse = this._converse;
_converse.log("The \"myplugin\" plugin is being initialized");
/* From the `_converse` object you can get any configuration
* options that the user might have passed in via
* `converse.initialize`.
*
* You can also specify new configuration settings for this
* plugin, or override the default values of existing
* configuration settings. This is done like so:
*/
_converse.api.settings.update({
'initialize_message': 'Initializing myplugin!'
});
/* The user can then pass in values for the configuration
* settings when `converse.initialize` gets called.
* For example:
*
* converse.initialize({
* "initialize_message": "My plugin has been initialized"
* });
*/
alert(this._converse.initialize_message);
/* Besides `_converse.api.settings.update`, there is also a
* `_converse.api.promises.add` method, which allows you to
* add new promises that your plugin is obligated to fulfill.
*
* This method takes a string or a list of strings which
* represent the promise names:
*
* _converse.api.promises.add('myPromise');
*
* Your plugin should then, when appropriate, resolve the
* promise by calling `_converse.api.emit`, which will also
* emit an event with the same name as the promise.
* For example:
*
* _converse.api.trigger('operationCompleted');
*
* Other plugins can then either listen for the event
* `operationCompleted` like so:
*
* _converse.api.listen.on('operationCompleted', function { ... });
*
* or they can wait for the promise to be fulfilled like so:
*
* _converse.api.waitUntil('operationCompleted', function { ... });
*/
'onConnected': function () {
// Overrides the onConnected method in converse.js
// Top-level functions in "overrides" are bound to the
// inner "_converse" object.
const _converse = this;
// Your custom code can come here ...
// You can access the original function being overridden
// via the __super__ attribute.
// Make sure to pass on the arguments supplied to this
// function and also to apply the proper "this" object.
_converse.__super__.onConnected.apply(this, arguments);
// Your custom code can come here ...
},
/* If you want to override some function or a Backbone model or
* view defined elsewhere in converse.js, then you do that under
* the "overrides" namespace.
/* Override converse.js's XMPPStatus Backbone model so that we can override the
* function that sends out the presence stanza.
*/
'overrides': {
/* For example, the private *_converse* object has a
* method "onConnected". You can override that method as follows:
*/
'onConnected': function () {
// Overrides the onConnected method in converse.js
// Top-level functions in "overrides" are bound to the
// inner "_converse" object.
var _converse = this;
// Your custom code can come here ...
// You can access the original function being overridden
// via the __super__ attribute.
// Make sure to pass on the arguments supplied to this
// function and also to apply the proper "this" object.
_converse.__super__.onConnected.apply(this, arguments);
// Your custom code can come here ...
},
/* Override converse.js's XMPPStatus Backbone model so that we can override the
* function that sends out the presence stanza.
*/
'XMPPStatus': {
'sendPresence': function (type, status_message, jid) {
// The "_converse" object is available via the __super__
// attribute.
var _converse = this.__super__._converse;
// Custom code can come here ...
// You can call the original overridden method, by
// accessing it via the __super__ attribute.
// When calling it, you need to apply the proper
// context as reference by the "this" variable.
this.__super__.sendPresence.apply(this, arguments);
// Custom code can come here ...
}
'XMPPStatus': {
'sendPresence': function (type, status_message, jid) {
// The "_converse" object is available via the __super__
// attribute.
const _converse = this.__super__._converse;
// Custom code can come here ...
// You can call the original overridden method, by
// accessing it via the __super__ attribute.
// When calling it, you need to apply the proper
// context as reference by the "this" variable.
this.__super__.sendPresence.apply(this, arguments);
// Custom code can come here ...
}
}
}
);
})
)
;
}
});
src/converse-bookmark-views.js
View file @
1ef29bee
...
...
@@ -42,20 +42,67 @@ converse.plugins.add('converse-bookmark-views', {
// Overrides mentioned here will be picked up by converse.js's
// plugin architecture they will replace existing methods on the
// relevant objects or classes.
//
// New functions which don't exist yet can also be added.
ChatRoomView
:
{
events
:
{
'
click .toggle-bookmark
'
:
'
toggleBookmark
'
},
async
renderHeading
()
{
this
.
__super__
.
renderHeading
.
apply
(
this
,
arguments
);
const
{
_converse
}
=
this
.
__super__
;
if
(
_converse
.
allow_bookmarks
)
{
const
supported
=
await
_converse
.
checkBookmarksSupport
();
if
(
supported
)
{
this
.
renderBookmarkToggle
();
}
}
}
}
},
initialize
()
{
this
.
__super__
.
initialize
.
apply
(
this
,
arguments
);
this
.
model
.
on
(
'
change:bookmarked
'
,
this
.
onBookmarked
,
this
);
this
.
setBookmarkState
();
initialize
()
{
/* The initialize function gets called as soon as the plugin is
* loaded by converse.js's plugin machinery.
*/
const
{
_converse
}
=
this
,
{
__
}
=
_converse
;
// Configuration values for this plugin
// ====================================
// Refer to docs/source/configuration.rst for explanations of these
// configuration settings.
_converse
.
api
.
settings
.
update
({
hide_open_bookmarks
:
true
,
muc_respect_autojoin
:
true
});
Object
.
assign
(
_converse
,
{
removeBookmarkViaEvent
(
ev
)
{
/* Remove a bookmark as determined by the passed in
* event.
*/
ev
.
preventDefault
();
const
name
=
ev
.
target
.
getAttribute
(
'
data-bookmark-name
'
);
const
jid
=
ev
.
target
.
getAttribute
(
'
data-room-jid
'
);
if
(
confirm
(
__
(
"
Are you sure you want to remove the bookmark
\"
%1$s
\"
?
"
,
name
)))
{
_
.
invokeMap
(
_converse
.
bookmarks
.
where
({
'
jid
'
:
jid
}),
Backbone
.
Model
.
prototype
.
destroy
);
}
},
addBookmarkViaEvent
(
ev
)
{
/* Add a bookmark as determined by the passed in
* event.
*/
ev
.
preventDefault
();
const
jid
=
ev
.
target
.
getAttribute
(
'
data-room-jid
'
);
const
chatroom
=
_converse
.
api
.
rooms
.
open
(
jid
,
{
'
bring_to_foreground
'
:
true
});
_converse
.
chatboxviews
.
get
(
jid
).
renderBookmarkForm
();
},
});
const
bookmarkableChatRoomView
=
{
renderBookmarkToggle
()
{
if
(
this
.
el
.
querySelector
(
'
.chat-head .toggle-bookmark
'
))
{
return
;
...
...
@@ -80,21 +127,7 @@ converse.plugins.add('converse-bookmark-views', {
}
},
async
renderHeading
()
{
this
.
__super__
.
renderHeading
.
apply
(
this
,
arguments
);
const
{
_converse
}
=
this
.
__super__
;
if
(
_converse
.
allow_bookmarks
)
{
const
supported
=
await
_converse
.
checkBookmarksSupport
();
if
(
supported
)
{
this
.
renderBookmarkToggle
();
}
}
},
onBookmarked
()
{
const
{
_converse
}
=
this
.
__super__
,
{
__
}
=
_converse
;
const
icon
=
this
.
el
.
querySelector
(
'
.toggle-bookmark
'
);
if
(
_
.
isNull
(
icon
))
{
return
;
...
...
@@ -111,7 +144,6 @@ converse.plugins.add('converse-bookmark-views', {
setBookmarkState
()
{
/* Set whether the groupchat is bookmarked or not.
*/
const
{
_converse
}
=
this
.
__super__
;
if
(
!
_
.
isUndefined
(
_converse
.
bookmarks
))
{
const
models
=
_converse
.
bookmarks
.
where
({
'
jid
'
:
this
.
model
.
get
(
'
jid
'
)});
if
(
!
models
.
length
)
{
...
...
@@ -125,7 +157,6 @@ converse.plugins.add('converse-bookmark-views', {
renderBookmarkForm
()
{
this
.
hideChatRoomContents
();
if
(
!
this
.
bookmark_form
)
{
const
{
_converse
}
=
this
.
__super__
;
this
.
bookmark_form
=
new
_converse
.
MUCBookmarkForm
({
'
model
'
:
this
.
model
,
'
chatroomview
'
:
this
...
...
@@ -141,7 +172,6 @@ converse.plugins.add('converse-bookmark-views', {
ev
.
preventDefault
();
ev
.
stopPropagation
();
}
const
{
_converse
}
=
this
.
__super__
;
const
models
=
_converse
.
bookmarks
.
where
({
'
jid
'
:
this
.
model
.
get
(
'
jid
'
)});
if
(
!
models
.
length
)
{
this
.
renderBookmarkForm
();
...
...
@@ -151,48 +181,7 @@ converse.plugins.add('converse-bookmark-views', {
}
}
}
},
initialize
()
{
/* The initialize function gets called as soon as the plugin is
* loaded by converse.js's plugin machinery.
*/
const
{
_converse
}
=
this
,
{
__
}
=
_converse
;
// Configuration values for this plugin
// ====================================
// Refer to docs/source/configuration.rst for explanations of these
// configuration settings.
_converse
.
api
.
settings
.
update
({
hide_open_bookmarks
:
true
,
muc_respect_autojoin
:
true
});
Object
.
assign
(
_converse
,
{
removeBookmarkViaEvent
(
ev
)
{
/* Remove a bookmark as determined by the passed in
* event.
*/
ev
.
preventDefault
();
const
name
=
ev
.
target
.
getAttribute
(
'
data-bookmark-name
'
);
const
jid
=
ev
.
target
.
getAttribute
(
'
data-room-jid
'
);
if
(
confirm
(
__
(
"
Are you sure you want to remove the bookmark
\"
%1$s
\"
?
"
,
name
)))
{
_
.
invokeMap
(
_converse
.
bookmarks
.
where
({
'
jid
'
:
jid
}),
Backbone
.
Model
.
prototype
.
destroy
);
}
},
addBookmarkViaEvent
(
ev
)
{
/* Add a bookmark as determined by the passed in
* event.
*/
ev
.
preventDefault
();
const
jid
=
ev
.
target
.
getAttribute
(
'
data-room-jid
'
);
const
chatroom
=
_converse
.
api
.
rooms
.
open
(
jid
,
{
'
bring_to_foreground
'
:
true
});
_converse
.
chatboxviews
.
get
(
jid
).
renderBookmarkForm
();
},
});
Object
.
assign
(
_converse
.
ChatRoomView
.
prototype
,
bookmarkableChatRoomView
);
_converse
.
MUCBookmarkForm
=
Backbone
.
VDOMView
.
extend
({
...
...
@@ -368,6 +357,7 @@ converse.plugins.add('converse-bookmark-views', {
}
});
/************************ BEGIN Event Handlers ************************/
const
initBookmarkViews
=
async
function
()
{
await
_converse
.
api
.
waitUntil
(
'
roomsPanelRendered
'
);
_converse
.
bookmarksview
=
new
_converse
.
BookmarksView
({
'
model
'
:
_converse
.
bookmarks
});
...
...
@@ -381,5 +371,11 @@ converse.plugins.add('converse-bookmark-views', {
}
_converse
.
api
.
listen
.
on
(
'
bookmarksInitialized
'
,
initBookmarkViews
);
_converse
.
api
.
listen
.
on
(
'
chatRoomOpened
'
,
view
=>
{
view
.
model
.
on
(
'
change:bookmarked
'
,
view
.
onBookmarked
,
view
);
view
.
setBookmarkState
();
});
/************************ END Event Handlers ************************/
}
});
src/converse-controlbox.js
View file @
1ef29bee
...
...
@@ -105,23 +105,6 @@ converse.plugins.add('converse-controlbox', {
view
.
close
();
});
return
this
;
},
getChatBoxWidth
(
view
)
{
const
{
_converse
}
=
this
.
__super__
;
const
controlbox
=
this
.
get
(
'
controlbox
'
);
if
(
view
.
model
.
get
(
'
id
'
)
===
'
controlbox
'
)
{
/* We return the width of the controlbox or its toggle,
* depending on which is visible.
*/
if
(
!
controlbox
||
!
u
.
isVisible
(
controlbox
.
el
))
{
return
u
.
getOuterWidth
(
_converse
.
controlboxtoggle
.
el
,
true
);
}
else
{
return
u
.
getOuterWidth
(
controlbox
.
el
,
true
);
}
}
else
{
return
this
.
__super__
.
getChatBoxWidth
.
apply
(
this
,
arguments
);
}
}
},
...
...
@@ -232,11 +215,12 @@ converse.plugins.add('converse-controlbox', {
* Triggered when the _converse.ControlBoxView has been initialized and therefore
* exists. The controlbox contains the login and register forms when the user is
* logged out and a list of the user's contacts and group chats when logged in.
* @event _converse#c
hatB
oxInitialized
* @event _converse#c
ontrolb
oxInitialized
* @type { _converse.ControlBoxView }
* @example _converse.api.listen.on('controlboxInitialized', view => { ... });
*/
_converse
.
api
.
trigger
(
'
controlboxInitialized
'
,
this
);
_converse
.
api
.
trigger
(
'
chatBoxInitialized
'
,
this
);
},
render
()
{
...
...
src/converse-dragresize.js
View file @
1ef29bee
...
...
@@ -45,42 +45,6 @@ converse.plugins.add('converse-dragresize', {
// Overrides mentioned here will be picked up by converse.js's
// plugin architecture they will replace existing methods on the
// relevant objects or classes.
//
// New functions which don't exist yet can also be added.
registerGlobalEventHandlers
()
{
const
that
=
this
;
document
.
addEventListener
(
'
mousemove
'
,
function
(
ev
)
{
if
(
!
that
.
resizing
||
!
that
.
allow_dragresize
)
{
return
true
;
}
ev
.
preventDefault
();
that
.
resizing
.
chatbox
.
resizeChatBox
(
ev
);
});
document
.
addEventListener
(
'
mouseup
'
,
function
(
ev
)
{
if
(
!
that
.
resizing
||
!
that
.
allow_dragresize
)
{
return
true
;
}
ev
.
preventDefault
();
const
height
=
that
.
applyDragResistance
(
that
.
resizing
.
chatbox
.
height
,
that
.
resizing
.
chatbox
.
model
.
get
(
'
default_height
'
)
);
const
width
=
that
.
applyDragResistance
(
that
.
resizing
.
chatbox
.
width
,
that
.
resizing
.
chatbox
.
model
.
get
(
'
default_width
'
)
);
if
(
that
.
connection
.
connected
)
{
that
.
resizing
.
chatbox
.
model
.
save
({
'
height
'
:
height
});
that
.
resizing
.
chatbox
.
model
.
save
({
'
width
'
:
width
});
}
else
{
that
.
resizing
.
chatbox
.
model
.
set
({
'
height
'
:
height
});
that
.
resizing
.
chatbox
.
model
.
set
({
'
width
'
:
width
});
}
that
.
resizing
=
null
;
});
return
this
.
__super__
.
registerGlobalEventHandlers
.
apply
(
this
,
arguments
);
},
ChatBox
:
{
initialize
()
{
const
{
_converse
}
=
this
.
__super__
;
...
...
@@ -102,9 +66,24 @@ converse.plugins.add('converse-dragresize', {
'
mousedown .dragresize-topleft
'
:
'
onStartDiagonalResize
'
},
initialize
()
{
window
.
addEventListener
(
'
resize
'
,
_
.
debounce
(
this
.
setDimensions
.
bind
(
this
),
100
));
this
.
__super__
.
initialize
.
apply
(
this
,
arguments
);
render
()
{
const
result
=
this
.
__super__
.
render
.
apply
(
this
,
arguments
);
renderDragResizeHandles
(
this
.
__super__
.
_converse
,
this
);
this
.
setWidth
();
return
result
;
},
_show
()
{
this
.
initDragResize
().
setDimensions
();
this
.
__super__
.
_show
.
apply
(
this
,
arguments
);
}
},
HeadlinesBoxView
:
{
events
:
{
'
mousedown .dragresize-top
'
:
'
onStartVerticalResize
'
,
'
mousedown .dragresize-left
'
:
'
onStartHorizontalResize
'
,
'
mousedown .dragresize-topleft
'
:
'
onStartDiagonalResize
'
},
render
()
{
...
...
@@ -112,27 +91,70 @@ converse.plugins.add('converse-dragresize', {
renderDragResizeHandles
(
this
.
__super__
.
_converse
,
this
);
this
.
setWidth
();
return
result
;
}
},
ControlBoxView
:
{
events
:
{
'
mousedown .dragresize-top
'
:
'
onStartVerticalResize
'
,
'
mousedown .dragresize-left
'
:
'
onStartHorizontalResize
'
,
'
mousedown .dragresize-topleft
'
:
'
onStartDiagonalResize
'
},
setWidth
()
{
// If a custom width is applied (due to drag-resizing),
// then we need to set the width of the .chatbox element as well.
if
(
this
.
model
.
get
(
'
width
'
))
{
this
.
el
.
style
.
width
=
this
.
model
.
get
(
'
width
'
);
}
render
()
{
const
result
=
this
.
__super__
.
render
.
apply
(
this
,
arguments
);
renderDragResizeHandles
(
this
.
__super__
.
_converse
,
this
);
this
.
setWidth
();
return
result
;
},
_show
()
{
renderLoginPanel
()
{
const
result
=
this
.
__super__
.
renderLoginPanel
.
apply
(
this
,
arguments
);
this
.
initDragResize
().
setDimensions
();
this
.
__super__
.
_show
.
apply
(
this
,
arguments
);
return
result
;
},
renderControlBoxPane
()
{
const
result
=
this
.
__super__
.
renderControlBoxPane
.
apply
(
this
,
arguments
);
this
.
initDragResize
().
setDimensions
();
return
result
;
}
},
ChatRoomView
:
{
events
:
{
'
mousedown .dragresize-top
'
:
'
onStartVerticalResize
'
,
'
mousedown .dragresize-left
'
:
'
onStartHorizontalResize
'
,
'
mousedown .dragresize-topleft
'
:
'
onStartDiagonalResize
'
},
render
()
{
const
result
=
this
.
__super__
.
render
.
apply
(
this
,
arguments
);
renderDragResizeHandles
(
this
.
__super__
.
_converse
,
this
);
this
.
setWidth
();
return
result
;
}
}
},
initialize
()
{
/* The initialize function gets called as soon as the plugin is
* loaded by converse.js's plugin machinery.
*/
const
{
_converse
}
=
this
;
_converse
.
api
.
settings
.
update
({
'
allow_dragresize
'
:
true
,
});
const
dragResizable
=
{
initDragResize
()
{
/* Determine and store the default box size.
* We need this information for the drag-resizing feature.
*/
const
{
_converse
}
=
this
.
__super__
,
flyout
=
this
.
el
.
querySelector
(
'
.box-flyout
'
),
const
flyout
=
this
.
el
.
querySelector
(
'
.box-flyout
'
),
style
=
window
.
getComputedStyle
(
flyout
);
if
(
_
.
isUndefined
(
this
.
model
.
get
(
'
height
'
)))
{
...
...
@@ -157,6 +179,34 @@ converse.plugins.add('converse-dragresize', {
return
this
;
},
resizeChatBox
(
ev
)
{
let
diff
;
if
(
_converse
.
resizing
.
direction
.
indexOf
(
'
top
'
)
===
0
)
{
diff
=
ev
.
pageY
-
this
.
prev_pageY
;
if
(
diff
)
{
this
.
height
=
((
this
.
height
-
diff
)
>
(
this
.
model
.
get
(
'
min_height
'
)
||
0
))
?
(
this
.
height
-
diff
)
:
this
.
model
.
get
(
'
min_height
'
);
this
.
prev_pageY
=
ev
.
pageY
;
this
.
setChatBoxHeight
(
this
.
height
);
}
}
if
(
_
.
includes
(
_converse
.
resizing
.
direction
,
'
left
'
))
{
diff
=
this
.
prev_pageX
-
ev
.
pageX
;
if
(
diff
)
{
this
.
width
=
((
this
.
width
+
diff
)
>
(
this
.
model
.
get
(
'
min_width
'
)
||
0
))
?
(
this
.
width
+
diff
)
:
this
.
model
.
get
(
'
min_width
'
);
this
.
prev_pageX
=
ev
.
pageX
;
this
.
setChatBoxWidth
(
this
.
width
);
}
}
},
setWidth
()
{
// If a custom width is applied (due to drag-resizing),
// then we need to set the width of the .chatbox element as well.
if
(
this
.
model
.
get
(
'
width
'
))
{
this
.
el
.
style
.
width
=
this
.
model
.
get
(
'
width
'
);
}
},
setDimensions
()
{
// Make sure the chat box has the right height and width.
this
.
adjustToViewport
();
...
...
@@ -165,7 +215,6 @@ converse.plugins.add('converse-dragresize', {
},
setChatBoxHeight
(
height
)
{
const
{
_converse
}
=
this
.
__super__
;
if
(
height
)
{
height
=
_converse
.
applyDragResistance
(
height
,
this
.
model
.
get
(
'
default_height
'
))
+
'
px
'
;
}
else
{
...
...
@@ -178,7 +227,6 @@ converse.plugins.add('converse-dragresize', {
},
setChatBoxWidth
(
width
)
{
const
{
_converse
}
=
this
.
__super__
;
if
(
width
)
{
width
=
_converse
.
applyDragResistance
(
width
,
this
.
model
.
get
(
'
default_width
'
))
+
'
px
'
;
}
else
{
...
...
@@ -208,7 +256,6 @@ converse.plugins.add('converse-dragresize', {
},
onStartVerticalResize
(
ev
)
{
const
{
_converse
}
=
this
.
__super__
;
if
(
!
_converse
.
allow_dragresize
)
{
return
true
;
}
// Record element attributes for mouseMove().
const
flyout
=
this
.
el
.
querySelector
(
'
.box-flyout
'
),
...
...
@@ -222,7 +269,6 @@ converse.plugins.add('converse-dragresize', {
},
onStartHorizontalResize
(
ev
)
{
const
{
_converse
}
=
this
.
__super__
;
if
(
!
_converse
.
allow_dragresize
)
{
return
true
;
}
const
flyout
=
this
.
el
.
querySelector
(
'
.box-flyout
'
),
style
=
window
.
getComputedStyle
(
flyout
);
...
...
@@ -235,116 +281,13 @@ converse.plugins.add('converse-dragresize', {
},
onStartDiagonalResize
(
ev
)
{
const
{
_converse
}
=
this
.
__super__
;
this
.
onStartHorizontalResize
(
ev
);
this
.
onStartVerticalResize
(
ev
);
_converse
.
resizing
.
direction
=
'
topleft
'
;
},
};
Object
.
assign
(
_converse
.
ChatBoxView
.
prototype
,
dragResizable
);
resizeChatBox
(
ev
)
{
let
diff
;
const
{
_converse
}
=
this
.
__super__
;
if
(
_converse
.
resizing
.
direction
.
indexOf
(
'
top
'
)
===
0
)
{
diff
=
ev
.
pageY
-
this
.
prev_pageY
;
if
(
diff
)
{
this
.
height
=
((
this
.
height
-
diff
)
>
(
this
.
model
.
get
(
'
min_height
'
)
||
0
))
?
(
this
.
height
-
diff
)
:
this
.
model
.
get
(
'
min_height
'
);
this
.
prev_pageY
=
ev
.
pageY
;
this
.
setChatBoxHeight
(
this
.
height
);
}
}
if
(
_
.
includes
(
_converse
.
resizing
.
direction
,
'
left
'
))
{
diff
=
this
.
prev_pageX
-
ev
.
pageX
;
if
(
diff
)
{
this
.
width
=
((
this
.
width
+
diff
)
>
(
this
.
model
.
get
(
'
min_width
'
)
||
0
))
?
(
this
.
width
+
diff
)
:
this
.
model
.
get
(
'
min_width
'
);
this
.
prev_pageX
=
ev
.
pageX
;
this
.
setChatBoxWidth
(
this
.
width
);
}
}
}
},
HeadlinesBoxView
:
{
events
:
{
'
mousedown .dragresize-top
'
:
'
onStartVerticalResize
'
,
'
mousedown .dragresize-left
'
:
'
onStartHorizontalResize
'
,
'
mousedown .dragresize-topleft
'
:
'
onStartDiagonalResize
'
},
initialize
()
{
window
.
addEventListener
(
'
resize
'
,
_
.
debounce
(
this
.
setDimensions
.
bind
(
this
),
100
));
return
this
.
__super__
.
initialize
.
apply
(
this
,
arguments
);
},
render
()
{
const
result
=
this
.
__super__
.
render
.
apply
(
this
,
arguments
);
renderDragResizeHandles
(
this
.
__super__
.
_converse
,
this
);
this
.
setWidth
();
return
result
;
}
},
ControlBoxView
:
{
events
:
{
'
mousedown .dragresize-top
'
:
'
onStartVerticalResize
'
,
'
mousedown .dragresize-left
'
:
'
onStartHorizontalResize
'
,
'
mousedown .dragresize-topleft
'
:
'
onStartDiagonalResize
'
},
initialize
()
{
window
.
addEventListener
(
'
resize
'
,
_
.
debounce
(
this
.
setDimensions
.
bind
(
this
),
100
));
this
.
__super__
.
initialize
.
apply
(
this
,
arguments
);
},
render
()
{
const
result
=
this
.
__super__
.
render
.
apply
(
this
,
arguments
);
renderDragResizeHandles
(
this
.
__super__
.
_converse
,
this
);
this
.
setWidth
();
return
result
;
},
renderLoginPanel
()
{
const
result
=
this
.
__super__
.
renderLoginPanel
.
apply
(
this
,
arguments
);
this
.
initDragResize
().
setDimensions
();
return
result
;
},
renderControlBoxPane
()
{
const
result
=
this
.
__super__
.
renderControlBoxPane
.
apply
(
this
,
arguments
);
this
.
initDragResize
().
setDimensions
();
return
result
;
}
},
ChatRoomView
:
{
events
:
{
'
mousedown .dragresize-top
'
:
'
onStartVerticalResize
'
,
'
mousedown .dragresize-left
'
:
'
onStartHorizontalResize
'
,
'
mousedown .dragresize-topleft
'
:
'
onStartDiagonalResize
'
},
initialize
()
{
window
.
addEventListener
(
'
resize
'
,
_
.
debounce
(
this
.
setDimensions
.
bind
(
this
),
100
));
this
.
__super__
.
initialize
.
apply
(
this
,
arguments
);
},
render
()
{
const
result
=
this
.
__super__
.
render
.
apply
(
this
,
arguments
);
renderDragResizeHandles
(
this
.
__super__
.
_converse
,
this
);
this
.
setWidth
();
return
result
;
}
}
},
initialize
()
{
/* The initialize function gets called as soon as the plugin is
* loaded by converse.js's plugin machinery.
*/
const
{
_converse
}
=
this
;
_converse
.
api
.
settings
.
update
({
allow_dragresize
:
true
,
});
_converse
.
applyDragResistance
=
function
(
value
,
default_value
)
{
/* This method applies some resistance around the
...
...
@@ -363,6 +306,45 @@ converse.plugins.add('converse-dragresize', {
}
return
value
;
};
/************************ BEGIN Event Handlers ************************/
function
registerGlobalEventHandlers
()
{
document
.
addEventListener
(
'
mousemove
'
,
function
(
ev
)
{
if
(
!
_converse
.
resizing
||
!
_converse
.
allow_dragresize
)
{
return
true
;
}
ev
.
preventDefault
();
_converse
.
resizing
.
chatbox
.
resizeChatBox
(
ev
);
});
document
.
addEventListener
(
'
mouseup
'
,
function
(
ev
)
{
if
(
!
_converse
.
resizing
||
!
_converse
.
allow_dragresize
)
{
return
true
;
}
ev
.
preventDefault
();
const
height
=
_converse
.
applyDragResistance
(
_converse
.
resizing
.
chatbox
.
height
,
_converse
.
resizing
.
chatbox
.
model
.
get
(
'
default_height
'
)
);
const
width
=
_converse
.
applyDragResistance
(
_converse
.
resizing
.
chatbox
.
width
,
_converse
.
resizing
.
chatbox
.
model
.
get
(
'
default_width
'
)
);
if
(
_converse
.
connection
.
connected
)
{
_converse
.
resizing
.
chatbox
.
model
.
save
({
'
height
'
:
height
});
_converse
.
resizing
.
chatbox
.
model
.
save
({
'
width
'
:
width
});
}
else
{
_converse
.
resizing
.
chatbox
.
model
.
set
({
'
height
'
:
height
});
_converse
.
resizing
.
chatbox
.
model
.
set
({
'
width
'
:
width
});
}
_converse
.
resizing
=
null
;
});
}
_converse
.
api
.
listen
.
on
(
'
registeredGlobalEventHandlers
'
,
registerGlobalEventHandlers
);
_converse
.
api
.
listen
.
on
(
'
chatBoxInitialized
'
,
view
=>
{
window
.
addEventListener
(
'
resize
'
,
_
.
debounce
(()
=>
view
.
setDimensions
(),
100
));
});
/************************ END Event Handlers ************************/
}
});
src/converse-minimize.js
View file @
1ef29bee
...
...
@@ -30,7 +30,7 @@ converse.plugins.add('converse-minimize', {
*
* NB: These plugins need to have already been loaded via require.js.
*/
dependencies
:
[
"
converse-chatview
"
,
"
converse-controlbox
"
,
"
converse-muc
"
,
"
converse-muc-views
"
,
"
converse-headlin
e
"
],
dependencies
:
[
"
converse-chatview
"
,
"
converse-controlbox
"
,
"
converse-muc
-views
"
,
"
converse-headline
"
,
"
converse-dragresiz
e
"
],
enabled
(
_converse
)
{
return
_converse
.
view_mode
===
'
overlayed
'
;
...
...
@@ -57,20 +57,6 @@ converse.plugins.add('converse-minimize', {
});
},
maximize
()
{
u
.
safeSave
(
this
,
{
'
minimized
'
:
false
,
'
time_opened
'
:
(
new
Date
()).
getTime
()
});
},
minimize
()
{
u
.
safeSave
(
this
,
{
'
minimized
'
:
true
,
'
time_minimized
'
:
(
new
Date
()).
toISOString
()
});
},
maybeShow
(
force
)
{
if
(
!
force
&&
this
.
get
(
'
minimized
'
))
{
// Must return the chatbox
...
...
@@ -122,65 +108,17 @@ converse.plugins.add('converse-minimize', {
if
(
!
this
.
model
.
get
(
'
minimized
'
))
{
return
this
.
__super__
.
setChatBoxWidth
.
apply
(
this
,
arguments
);
}
},
onMinimizedChanged
(
item
)
{
if
(
item
.
get
(
'
minimized
'
))
{
this
.
minimize
();
}
else
{
this
.
maximize
();
}
},
maximize
()
{
// Restores a minimized chat box
const
{
_converse
}
=
this
.
__super__
;
this
.
insertIntoDOM
();
if
(
!
this
.
model
.
isScrolledUp
())
{
this
.
model
.
clearUnreadMsgCounter
();
}
this
.
show
();
/**
* Triggered when a previously minimized chat gets maximized
* @event _converse#chatBoxMaximized
* @type { _converse.ChatBoxView }
* @example _converse.api.listen.on('chatBoxMaximized', view => { ... });
*/
_converse
.
api
.
trigger
(
'
chatBoxMaximized
'
,
this
);
return
this
;
},
minimize
(
ev
)
{
const
{
_converse
}
=
this
.
__super__
;
if
(
ev
&&
ev
.
preventDefault
)
{
ev
.
preventDefault
();
}
// save the scroll position to restore it on maximize
if
(
this
.
model
.
collection
&&
this
.
model
.
collection
.
browserStorage
)
{
this
.
model
.
save
({
'
scroll
'
:
this
.
content
.
scrollTop
});
}
else
{
this
.
model
.
set
({
'
scroll
'
:
this
.
content
.
scrollTop
});
}
this
.
setChatState
(
_converse
.
INACTIVE
).
model
.
minimize
();
this
.
hide
();
/**
* Triggered when a previously maximized chat gets Minimized
* @event _converse#chatBoxMinimized
* @type { _converse.ChatBoxView }
* @example _converse.api.listen.on('chatBoxMinimized', view => { ... });
*/
_converse
.
api
.
trigger
(
'
chatBoxMinimized
'
,
this
);
},
}
},
ChatBoxHeading
:
{
render
()
{
const
{
_converse
}
=
this
.
__super__
,
{
__
}
=
_converse
;
const
result
=
this
.
__super__
.
render
.
apply
(
this
,
arguments
);
const
new_html
=
tpl_chatbox_minimize
(
{
info_minimize
:
__
(
'
Minimize this chat box
'
)}
);
const
new_html
=
tpl_chatbox_minimize
(
{
'
info_minimize
'
:
__
(
'
Minimize this chat box
'
)
}
);
const
el
=
this
.
el
.
querySelector
(
'
.toggle-chatbox-button
'
);
if
(
el
)
{
el
.
outerHTML
=
new_html
;
...
...
@@ -227,11 +165,109 @@ converse.plugins.add('converse-minimize', {
}
return
div
.
innerHTML
;
}
},
}
},
initialize
()
{
/* The initialize function gets called as soon as the plugin is
* loaded by Converse.js's plugin machinery.
*/
const
{
_converse
}
=
this
,
{
__
}
=
_converse
;
// Add new HTML templates.
_converse
.
templates
.
chatbox_minimize
=
tpl_chatbox_minimize
;
_converse
.
templates
.
toggle_chats
=
tpl_toggle_chats
;
_converse
.
templates
.
trimmed_chat
=
tpl_trimmed_chat
;
_converse
.
templates
.
chats_panel
=
tpl_chats_panel
;
_converse
.
api
.
settings
.
update
({
'
no_trimming
'
:
false
,
// Set to true for tests
});
ChatBoxViews
:
{
const
minimizableChatBox
=
{
maximize
()
{
u
.
safeSave
(
this
,
{
'
minimized
'
:
false
,
'
time_opened
'
:
(
new
Date
()).
getTime
()
});
},
minimize
()
{
u
.
safeSave
(
this
,
{
'
minimized
'
:
true
,
'
time_minimized
'
:
(
new
Date
()).
toISOString
()
});
}
}
Object
.
assign
(
_converse
.
ChatBox
.
prototype
,
minimizableChatBox
);
const
minimizableChatBoxView
=
{
maximize
()
{
// Restores a minimized chat box
const
{
_converse
}
=
this
.
__super__
;
this
.
insertIntoDOM
();
if
(
!
this
.
model
.
isScrolledUp
())
{
this
.
model
.
clearUnreadMsgCounter
();
}
this
.
show
();
/**
* Triggered when a previously minimized chat gets maximized
* @event _converse#chatBoxMaximized
* @type { _converse.ChatBoxView }
* @example _converse.api.listen.on('chatBoxMaximized', view => { ... });
*/
_converse
.
api
.
trigger
(
'
chatBoxMaximized
'
,
this
);
return
this
;
},
minimize
(
ev
)
{
const
{
_converse
}
=
this
.
__super__
;
if
(
ev
&&
ev
.
preventDefault
)
{
ev
.
preventDefault
();
}
// save the scroll position to restore it on maximize
if
(
this
.
model
.
collection
&&
this
.
model
.
collection
.
browserStorage
)
{
this
.
model
.
save
({
'
scroll
'
:
this
.
content
.
scrollTop
});
}
else
{
this
.
model
.
set
({
'
scroll
'
:
this
.
content
.
scrollTop
});
}
this
.
setChatState
(
_converse
.
INACTIVE
).
model
.
minimize
();
this
.
hide
();
/**
* Triggered when a previously maximized chat gets Minimized
* @event _converse#chatBoxMinimized
* @type { _converse.ChatBoxView }
* @example _converse.api.listen.on('chatBoxMinimized', view => { ... });
*/
_converse
.
api
.
trigger
(
'
chatBoxMinimized
'
,
this
);
},
onMinimizedChanged
(
item
)
{
if
(
item
.
get
(
'
minimized
'
))
{
this
.
minimize
();
}
else
{
this
.
maximize
();
}
}
}
Object
.
assign
(
_converse
.
ChatBoxView
.
prototype
,
minimizableChatBoxView
);
const
chatTrimmer
=
{
getChatBoxWidth
(
view
)
{
if
(
!
view
.
model
.
get
(
'
minimized
'
)
&&
u
.
isVisible
(
view
.
el
))
{
if
(
view
.
model
.
get
(
'
id
'
)
===
'
controlbox
'
)
{
const
controlbox
=
this
.
get
(
'
controlbox
'
);
// We return the width of the controlbox or its toggle,
// depending on which is visible.
if
(
!
controlbox
||
!
u
.
isVisible
(
controlbox
.
el
))
{
return
u
.
getOuterWidth
(
_converse
.
controlboxtoggle
.
el
,
true
);
}
else
{
return
u
.
getOuterWidth
(
controlbox
.
el
,
true
);
}
}
else
if
(
!
view
.
model
.
get
(
'
minimized
'
)
&&
u
.
isVisible
(
view
.
el
))
{
return
u
.
getOuterWidth
(
view
.
el
,
true
);
}
return
0
;
...
...
@@ -315,25 +351,8 @@ converse.plugins.add('converse-minimize', {
return
model
;
}
}
},
Object
.
assign
(
_converse
.
ChatBoxViews
.
prototype
,
chatTrimmer
);
initialize
()
{
/* The initialize function gets called as soon as the plugin is
* loaded by Converse.js's plugin machinery.
*/
const
{
_converse
}
=
this
,
{
__
}
=
_converse
;
// Add new HTML templates.
_converse
.
templates
.
chatbox_minimize
=
tpl_chatbox_minimize
;
_converse
.
templates
.
toggle_chats
=
tpl_toggle_chats
;
_converse
.
templates
.
trimmed_chat
=
tpl_trimmed_chat
;
_converse
.
templates
.
chats_panel
=
tpl_chats_panel
;
_converse
.
api
.
settings
.
update
({
no_trimming
:
false
,
// Set to true for phantomjs tests (where browser apparently has no width)
});
_converse
.
api
.
promises
.
add
(
'
minimizedChatsInitialized
'
);
...
...
@@ -525,6 +544,7 @@ converse.plugins.add('converse-minimize', {
}
});
/************************ BEGIN Event Handlers ************************/
Promise
.
all
([
_converse
.
api
.
waitUntil
(
'
connectionInitialized
'
),
_converse
.
api
.
waitUntil
(
'
chatBoxViewsInitialized
'
)
...
...
@@ -559,5 +579,6 @@ converse.plugins.add('converse-minimize', {
_converse
.
chatboxviews
.
trimChats
(
chatbox
);
}
});
/************************ END Event Handlers ************************/
}
});
src/converse-muc-views.js
View file @
1ef29bee
...
...
@@ -62,41 +62,14 @@ converse.plugins.add('converse-muc-views', {
dependencies
:
[
"
converse-autocomplete
"
,
"
converse-modal
"
,
"
converse-controlbox
"
,
"
converse-chatview
"
],
overrides
:
{
ControlBoxView
:
{
renderRoomsPanel
()
{
const
{
_converse
}
=
this
.
__super__
;
if
(
this
.
roomspanel
&&
u
.
isVisible
(
this
.
roomspanel
.
el
))
{
return
;
}
this
.
roomspanel
=
new
_converse
.
RoomsPanel
({
'
model
'
:
new
(
_converse
.
RoomsPanelModel
.
extend
({
'
id
'
:
`converse.roomspanel
${
_converse
.
bare_jid
}
`
,
// Required by web storage
'
browserStorage
'
:
new
BrowserStorage
[
_converse
.
config
.
get
(
'
storage
'
)](
`converse.roomspanel
${
_converse
.
bare_jid
}
`
)
}))()
});
this
.
roomspanel
.
model
.
fetch
();
this
.
el
.
querySelector
(
'
.controlbox-pane
'
).
insertAdjacentElement
(
'
beforeEnd
'
,
this
.
roomspanel
.
render
().
el
);
/**
* Triggered once the section of the _converse.ControlBoxView
* which shows gropuchats has been rendered.
* @event _converse#roomsPanelRendered
* @example _converse.api.listen.on('roomsPanelRendered', () => { ... });
*/
_converse
.
api
.
trigger
(
'
roomsPanelRendered
'
);
},
renderControlBoxPane
()
{
const
{
_converse
}
=
this
.
__super__
;
this
.
__super__
.
renderControlBoxPane
.
apply
(
this
,
arguments
);
if
(
_converse
.
allow_muc
)
{
this
.
renderRoomsPanel
();
}
}
,
}
}
},
...
...
@@ -123,6 +96,35 @@ converse.plugins.add('converse-muc-views', {
}
});
Object
.
assign
(
_converse
.
ControlBoxView
.
prototype
,
{
renderRoomsPanel
()
{
if
(
this
.
roomspanel
&&
u
.
isVisible
(
this
.
roomspanel
.
el
))
{
return
;
}
this
.
roomspanel
=
new
_converse
.
RoomsPanel
({
'
model
'
:
new
(
_converse
.
RoomsPanelModel
.
extend
({
'
id
'
:
`converse.roomspanel
${
_converse
.
bare_jid
}
`
,
// Required by web storage
'
browserStorage
'
:
new
BrowserStorage
[
_converse
.
config
.
get
(
'
storage
'
)](
`converse.roomspanel
${
_converse
.
bare_jid
}
`
)
}))()
});
this
.
roomspanel
.
model
.
fetch
();
this
.
el
.
querySelector
(
'
.controlbox-pane
'
).
insertAdjacentElement
(
'
beforeEnd
'
,
this
.
roomspanel
.
render
().
el
);
/**
* Triggered once the section of the _converse.ControlBoxView
* which shows gropuchats has been rendered.
* @event _converse#roomsPanelRendered
* @example _converse.api.listen.on('roomsPanelRendered', () => { ... });
*/
_converse
.
api
.
trigger
(
'
roomsPanelRendered
'
);
}
});
function
___
(
str
)
{
/* This is part of a hack to get gettext to scan strings to be
* translated. Strings we cannot send to the function above because
...
...
@@ -572,6 +574,7 @@ converse.plugins.add('converse-muc-views', {
* @example _converse.api.listen.on('chatRoomOpened', view => { ... });
*/
_converse
.
api
.
trigger
(
'
chatRoomOpened
'
,
this
);
_converse
.
api
.
trigger
(
'
chatBoxInitialized
'
,
this
);
},
render
()
{
...
...
src/converse-oauth.js
View file @
1ef29bee
...
...
@@ -38,12 +38,12 @@ converse.plugins.add("converse-oauth", {
/* For example, the private *_converse* object has a
* method "onConnected". You can override that method as follows:
*/
'
LoginPanel
'
:
{
LoginPanel
:
{
insertOAuthProviders
()
{
const
{
_converse
}
=
this
.
__super__
;
if
(
_
.
isUndefined
(
this
.
oauth_providers_view
))
{
this
.
oauth_providers_view
=
this
.
oauth_providers_view
=
new
_converse
.
OAuthProvidersView
({
'
model
'
:
_converse
.
oauth_providers
});
this
.
oauth_providers_view
.
render
();
...
...
src/converse-omemo.js
View file @
1ef29bee
...
...
@@ -172,6 +172,90 @@ converse.plugins.add('converse-omemo', {
},
ChatBox
:
{
async
getMessageAttributesFromStanza
(
stanza
,
original_stanza
)
{
const
{
_converse
}
=
this
.
__super__
;
const
encrypted
=
sizzle
(
`encrypted[xmlns="
${
Strophe
.
NS
.
OMEMO
}
"]`
,
original_stanza
).
pop
(),
attrs
=
await
this
.
__super__
.
getMessageAttributesFromStanza
.
apply
(
this
,
arguments
);
if
(
!
encrypted
||
!
_converse
.
config
.
get
(
'
trusted
'
))
{
return
attrs
;
}
else
{
return
this
.
getEncryptionAttributesfromStanza
(
stanza
,
original_stanza
,
attrs
);
}
},
async
sendMessage
(
text
,
spoiler_hint
)
{
if
(
this
.
get
(
'
omemo_active
'
)
&&
text
)
{
const
{
_converse
}
=
this
.
__super__
;
const
attrs
=
this
.
getOutgoingMessageAttributes
(
text
,
spoiler_hint
);
attrs
[
'
is_encrypted
'
]
=
true
;
attrs
[
'
plaintext
'
]
=
attrs
.
message
;
try
{
const
devices
=
await
_converse
.
getBundlesAndBuildSessions
(
this
);
const
stanza
=
await
_converse
.
createOMEMOMessageStanza
(
this
,
this
.
messages
.
create
(
attrs
),
devices
);
_converse
.
api
.
send
(
stanza
);
}
catch
(
e
)
{
this
.
handleMessageSendError
(
e
);
return
false
;
}
return
true
;
}
else
{
return
this
.
__super__
.
sendMessage
.
apply
(
this
,
arguments
);
}
}
},
ChatBoxView
:
{
events
:
{
'
click .toggle-omemo
'
:
'
toggleOMEMO
'
},
initialize
()
{
this
.
__super__
.
initialize
.
apply
(
this
,
arguments
);
this
.
model
.
on
(
'
change:omemo_active
'
,
this
.
renderOMEMOToolbarButton
,
this
);
this
.
model
.
on
(
'
change:omemo_supported
'
,
this
.
onOMEMOSupportedDetermined
,
this
);
},
showMessage
(
message
)
{
// We don't show a message if it's only keying material
if
(
!
message
.
get
(
'
is_only_key
'
))
{
return
this
.
__super__
.
showMessage
.
apply
(
this
,
arguments
);
}
}
},
ChatRoomView
:
{
events
:
{
'
click .toggle-omemo
'
:
'
toggleOMEMO
'
},
initialize
()
{
this
.
__super__
.
initialize
.
apply
(
this
,
arguments
);
this
.
model
.
on
(
'
change:omemo_active
'
,
this
.
renderOMEMOToolbarButton
,
this
);
this
.
model
.
on
(
'
change:omemo_supported
'
,
this
.
onOMEMOSupportedDetermined
,
this
);
}
}
},
initialize
()
{
/* The initialize function gets called as soon as the plugin is
* loaded by Converse.js's plugin machinery.
*/
const
{
_converse
}
=
this
,
{
__
}
=
_converse
;
_converse
.
api
.
promises
.
add
([
'
OMEMOInitialized
'
]);
_converse
.
NUM_PREKEYS
=
100
;
// Set here so that tests can override
/**
* Mixin object that contains OMEMO-related methods for
* {@link _converse.ChatBox} or {@link _converse.ChatRoom} objects.
*
* @typedef {Object} OMEMOEnabledChatBox
*/
const
OMEMOEnabledChatBox
=
{
async
encryptMessage
(
plaintext
)
{
// The client MUST use fresh, randomly generated key/IV pairs
...
...
@@ -219,7 +303,6 @@ converse.plugins.add('converse-omemo', {
},
reportDecryptionError
(
e
)
{
const
{
_converse
}
=
this
.
__super__
;
if
(
_converse
.
debug
)
{
const
{
__
}
=
_converse
;
this
.
messages
.
create
({
...
...
@@ -231,8 +314,7 @@ converse.plugins.add('converse-omemo', {
},
async
handleDecryptedWhisperMessage
(
attrs
,
key_and_tag
)
{
const
{
_converse
}
=
this
.
__super__
,
encrypted
=
attrs
.
encrypted
,
const
encrypted
=
attrs
.
encrypted
,
devicelist
=
_converse
.
devicelists
.
getDeviceList
(
this
.
get
(
'
jid
'
));
this
.
save
(
'
omemo_supported
'
,
true
);
...
...
@@ -250,8 +332,7 @@ converse.plugins.add('converse-omemo', {
},
decrypt
(
attrs
)
{
const
{
_converse
}
=
this
.
__super__
,
session_cipher
=
this
.
getSessionCipher
(
attrs
.
from
,
parseInt
(
attrs
.
encrypted
.
device_id
,
10
));
const
session_cipher
=
this
.
getSessionCipher
(
attrs
.
from
,
parseInt
(
attrs
.
encrypted
.
device_id
,
10
));
// https://xmpp.org/extensions/xep-0384.html#usecases-receiving
if
(
attrs
.
encrypted
.
prekey
===
true
)
{
...
...
@@ -284,8 +365,7 @@ converse.plugins.add('converse-omemo', {
},
getEncryptionAttributesfromStanza
(
stanza
,
original_stanza
,
attrs
)
{
const
{
_converse
}
=
this
.
__super__
,
encrypted
=
sizzle
(
`encrypted[xmlns="
${
Strophe
.
NS
.
OMEMO
}
"]`
,
original_stanza
).
pop
(),
const
encrypted
=
sizzle
(
`encrypted[xmlns="
${
Strophe
.
NS
.
OMEMO
}
"]`
,
original_stanza
).
pop
(),
header
=
encrypted
.
querySelector
(
'
header
'
),
key
=
sizzle
(
`key[rid="
${
_converse
.
omemo_store
.
get
(
'
device_id
'
)}
"]`
,
encrypted
).
pop
();
if
(
key
)
{
...
...
@@ -303,22 +383,8 @@ converse.plugins.add('converse-omemo', {
}
},
async
getMessageAttributesFromStanza
(
stanza
,
original_stanza
)
{
const
{
_converse
}
=
this
.
__super__
,
encrypted
=
sizzle
(
`encrypted[xmlns="
${
Strophe
.
NS
.
OMEMO
}
"]`
,
original_stanza
).
pop
(),
attrs
=
await
this
.
__super__
.
getMessageAttributesFromStanza
.
apply
(
this
,
arguments
);
if
(
!
encrypted
||
!
_converse
.
config
.
get
(
'
trusted
'
))
{
return
attrs
;
}
else
{
return
this
.
getEncryptionAttributesfromStanza
(
stanza
,
original_stanza
,
attrs
);
}
},
getSessionCipher
(
jid
,
id
)
{
const
{
_converse
}
=
this
.
__super__
,
address
=
new
libsignal
.
SignalProtocolAddress
(
jid
,
id
);
const
address
=
new
libsignal
.
SignalProtocolAddress
(
jid
,
id
);
this
.
session_cipher
=
new
window
.
libsignal
.
SessionCipher
(
_converse
.
omemo_store
,
address
);
return
this
.
session_cipher
;
},
...
...
@@ -330,8 +396,6 @@ converse.plugins.add('converse-omemo', {
},
handleMessageSendError
(
e
)
{
const
{
_converse
}
=
this
.
__super__
,
{
__
}
=
_converse
;
if
(
e
.
name
===
'
IQError
'
)
{
this
.
save
(
'
omemo_supported
'
,
false
);
...
...
@@ -355,46 +419,12 @@ converse.plugins.add('converse-omemo', {
}
else
{
throw
e
;
}
},
async
sendMessage
(
text
,
spoiler_hint
)
{
if
(
this
.
get
(
'
omemo_active
'
)
&&
text
)
{
const
{
_converse
}
=
this
.
__super__
;
const
attrs
=
this
.
getOutgoingMessageAttributes
(
text
,
spoiler_hint
);
attrs
[
'
is_encrypted
'
]
=
true
;
attrs
[
'
plaintext
'
]
=
attrs
.
message
;
try
{
const
devices
=
await
_converse
.
getBundlesAndBuildSessions
(
this
);
const
stanza
=
await
_converse
.
createOMEMOMessageStanza
(
this
,
this
.
messages
.
create
(
attrs
),
devices
);
_converse
.
api
.
send
(
stanza
);
}
catch
(
e
)
{
this
.
handleMessageSendError
(
e
);
return
false
;
}
return
true
;
}
else
{
return
this
.
__super__
.
sendMessage
.
apply
(
this
,
arguments
);
}
}
},
}
Object
.
assign
(
_converse
.
ChatBox
.
prototype
,
OMEMOEnabledChatBox
);
ChatBoxView
:
{
events
:
{
'
click .toggle-omemo
'
:
'
toggleOMEMO
'
},
initialize
()
{
this
.
__super__
.
initialize
.
apply
(
this
,
arguments
);
this
.
model
.
on
(
'
change:omemo_active
'
,
this
.
renderOMEMOToolbarButton
,
this
);
this
.
model
.
on
(
'
change:omemo_supported
'
,
this
.
onOMEMOSupportedDetermined
,
this
);
},
showMessage
(
message
)
{
// We don't show a message if it's only keying material
if
(
!
message
.
get
(
'
is_only_key
'
))
{
return
this
.
__super__
.
showMessage
.
apply
(
this
,
arguments
);
}
},
const
OMEMOEnabledChatView
=
{
onOMEMOSupportedDetermined
()
{
if
(
!
this
.
model
.
get
(
'
omemo_supported
'
)
&&
this
.
model
.
get
(
'
omemo_active
'
))
{
...
...
@@ -405,82 +435,47 @@ converse.plugins.add('converse-omemo', {
},
renderOMEMOToolbarButton
()
{
const
{
_converse
}
=
this
.
__super__
,
{
__
}
=
_converse
,
icon
=
this
.
el
.
querySelector
(
'
.toggle-omemo
'
),
html
=
tpl_toolbar_omemo
(
Object
.
assign
(
this
.
model
.
toJSON
(),
{
'
__
'
:
__
}));
if
(
this
.
model
.
get
(
'
type
'
)
!==
_converse
.
CHATROOMS_TYPE
||
this
.
model
.
features
.
get
(
'
membersonly
'
)
&&
this
.
model
.
features
.
get
(
'
nonanonymous
'
))
{
if
(
icon
)
{
icon
.
outerHTML
=
html
;
const
icon
=
this
.
el
.
querySelector
(
'
.toggle-omemo
'
);
const
html
=
tpl_toolbar_omemo
(
Object
.
assign
(
this
.
model
.
toJSON
(),
{
'
__
'
:
__
}));
if
(
icon
)
{
icon
.
outerHTML
=
html
;
}
else
{
this
.
el
.
querySelector
(
'
.chat-toolbar
'
).
insertAdjacentHTML
(
'
beforeend
'
,
html
);
}
}
else
{
this
.
el
.
querySelector
(
'
.chat-toolbar
'
).
insertAdjacentHTML
(
'
beforeend
'
,
html
);
const
icon
=
this
.
el
.
querySelector
(
'
.toggle-omemo
'
);
if
(
icon
)
{
icon
.
parentElement
.
removeChild
(
icon
);
}
}
},
toggleOMEMO
(
ev
)
{
const
{
_converse
}
=
this
.
__super__
,
{
__
}
=
_converse
;
if
(
!
this
.
model
.
get
(
'
omemo_supported
'
))
{
return
_converse
.
api
.
alert
.
show
(
Strophe
.
LogLevel
.
ERROR
,
__
(
'
Error
'
),
[
__
(
"
Cannot use end-to-end encryption because %1$s uses a client that doesn't support OMEMO.
"
,
let
messages
;
if
(
this
.
model
.
get
(
'
type
'
)
===
_converse
.
CHATROOMS_TYPE
)
{
messages
=
[
__
(
'
Cannot use end-to-end encryption in this groupchat,
'
+
'
either the groupchat has some anonymity or not all participants support OMEMO.
'
)];
}
else
{
messages
=
[
__
(
"
Cannot use end-to-end encryption because %1$s uses a client that doesn't support OMEMO.
"
,
this
.
model
.
contact
.
getDisplayName
()
)]
)
}
ev
.
preventDefault
();
this
.
model
.
save
({
'
omemo_active
'
:
!
this
.
model
.
get
(
'
omemo_active
'
)});
}
},
ChatRoomView
:
{
events
:
{
'
click .toggle-omemo
'
:
'
toggleOMEMO
'
},
initialize
()
{
this
.
__super__
.
initialize
.
apply
(
this
,
arguments
);
this
.
model
.
on
(
'
change:omemo_active
'
,
this
.
renderOMEMOToolbarButton
,
this
);
this
.
model
.
on
(
'
change:omemo_supported
'
,
this
.
onOMEMOSupportedDetermined
,
this
);
},
toggleOMEMO
(
ev
)
{
const
{
_converse
}
=
this
.
__super__
,
{
__
}
=
_converse
;
if
(
!
this
.
model
.
get
(
'
omemo_supported
'
))
{
return
_converse
.
api
.
alert
.
show
(
Strophe
.
LogLevel
.
ERROR
,
__
(
'
Error
'
),
[
__
(
'
Cannot use end-to-end encryption in this groupchat,
'
+
'
either the groupchat has some anonymity or not all participants support OMEMO.
'
)]
);
)];
}
return
_converse
.
api
.
alert
.
show
(
Strophe
.
LogLevel
.
ERROR
,
__
(
'
Error
'
),
messages
);
}
ev
.
preventDefault
();
this
.
model
.
save
({
'
omemo_active
'
:
!
this
.
model
.
get
(
'
omemo_active
'
)});
},
renderOMEMOToolbarButton
()
{
if
(
this
.
model
.
features
.
get
(
'
membersonly
'
)
&&
this
.
model
.
features
.
get
(
'
nonanonymous
'
))
{
this
.
__super__
.
renderOMEMOToolbarButton
.
apply
(
arguments
);
}
else
{
const
icon
=
this
.
el
.
querySelector
(
'
.toggle-omemo
'
);
if
(
icon
)
{
icon
.
parentElement
.
removeChild
(
icon
);
}
}
}
}
},
Object
.
assign
(
_converse
.
ChatBoxView
.
prototype
,
OMEMOEnabledChatView
);
initialize
()
{
/* The initialize function gets called as soon as the plugin is
* loaded by Converse.js's plugin machinery.
*/
const
{
_converse
}
=
this
,
{
__
}
=
_converse
;
_converse
.
api
.
promises
.
add
([
'
OMEMOInitialized
'
]);
_converse
.
NUM_PREKEYS
=
100
;
// Set here so that tests can override
async
function
generateFingerprint
(
device
)
{
if
(
_
.
get
(
device
.
get
(
'
bundle
'
),
'
fingerprint
'
))
{
...
...
src/converse-register.js
View file @
1ef29bee
...
...
@@ -45,17 +45,6 @@ converse.plugins.add('converse-register', {
// New functions which don't exist yet can also be added.
LoginPanel
:
{
insertRegisterLink
()
{
const
{
_converse
}
=
this
.
__super__
;
if
(
_
.
isUndefined
(
this
.
registerlinkview
))
{
this
.
registerlinkview
=
new
_converse
.
RegisterLinkView
({
'
model
'
:
this
.
model
});
this
.
registerlinkview
.
render
();
this
.
el
.
querySelector
(
'
.buttons
'
).
insertAdjacentElement
(
'
afterend
'
,
this
.
registerlinkview
.
el
);
}
this
.
registerlinkview
.
render
();
},
render
(
cfg
)
{
const
{
_converse
}
=
this
.
__super__
;
this
.
__super__
.
render
.
apply
(
this
,
arguments
);
...
...
@@ -67,11 +56,50 @@ converse.plugins.add('converse-register', {
},
ControlBoxView
:
{
renderLoginPanel
()
{
/* Also render a registration panel, when rendering the
* login panel.
*/
this
.
__super__
.
renderLoginPanel
.
apply
(
this
,
arguments
);
this
.
renderRegistrationPanel
();
return
this
;
}
}
},
initialize
()
{
this
.
__super__
.
initialize
.
apply
(
this
,
arguments
);
this
.
model
.
on
(
'
change:active-form
'
,
this
.
showLoginOrRegisterForm
.
bind
(
this
))
},
initialize
()
{
/* The initialize function gets called as soon as the plugin is
* loaded by converse.js's plugin machinery.
*/
const
{
_converse
}
=
this
,
{
__
}
=
_converse
;
_converse
.
CONNECTION_STATUS
[
Strophe
.
Status
.
REGIFAIL
]
=
'
REGIFAIL
'
;
_converse
.
CONNECTION_STATUS
[
Strophe
.
Status
.
REGISTERED
]
=
'
REGISTERED
'
;
_converse
.
CONNECTION_STATUS
[
Strophe
.
Status
.
CONFLICT
]
=
'
CONFLICT
'
;
_converse
.
CONNECTION_STATUS
[
Strophe
.
Status
.
NOTACCEPTABLE
]
=
'
NOTACCEPTABLE
'
;
_converse
.
api
.
settings
.
update
({
'
allow_registration
'
:
true
,
'
domain_placeholder
'
:
__
(
"
e.g. conversejs.org
"
),
// Placeholder text shown in the domain input on the registration form
'
providers_link
'
:
'
https://compliance.conversations.im/
'
,
// Link to XMPP providers shown on registration page
'
registration_domain
'
:
''
});
Object
.
assign
(
_converse
.
LoginPanel
.
prototype
,
{
insertRegisterLink
()
{
if
(
_
.
isUndefined
(
this
.
registerlinkview
))
{
this
.
registerlinkview
=
new
_converse
.
RegisterLinkView
({
'
model
'
:
this
.
model
});
this
.
registerlinkview
.
render
();
this
.
el
.
querySelector
(
'
.buttons
'
).
insertAdjacentElement
(
'
afterend
'
,
this
.
registerlinkview
.
el
);
}
this
.
registerlinkview
.
render
();
}
});
Object
.
assign
(
_converse
.
ControlBoxView
.
prototype
,
{
showLoginOrRegisterForm
()
{
const
{
_converse
}
=
this
.
__super__
;
...
...
@@ -88,7 +116,6 @@ converse.plugins.add('converse-register', {
},
renderRegistrationPanel
()
{
const
{
_converse
}
=
this
.
__super__
;
if
(
_converse
.
allow_registration
)
{
this
.
registerpanel
=
new
_converse
.
RegisterPanel
({
'
model
'
:
this
.
model
...
...
@@ -102,36 +129,7 @@ converse.plugins.add('converse-register', {
this
.
showLoginOrRegisterForm
();
}
return
this
;
},
renderLoginPanel
()
{
/* Also render a registration panel, when rendering the
* login panel.
*/
this
.
__super__
.
renderLoginPanel
.
apply
(
this
,
arguments
);
this
.
renderRegistrationPanel
();
return
this
;
}
}
},
initialize
()
{
/* The initialize function gets called as soon as the plugin is
* loaded by converse.js's plugin machinery.
*/
const
{
_converse
}
=
this
,
{
__
}
=
_converse
;
_converse
.
CONNECTION_STATUS
[
Strophe
.
Status
.
REGIFAIL
]
=
'
REGIFAIL
'
;
_converse
.
CONNECTION_STATUS
[
Strophe
.
Status
.
REGISTERED
]
=
'
REGISTERED
'
;
_converse
.
CONNECTION_STATUS
[
Strophe
.
Status
.
CONFLICT
]
=
'
CONFLICT
'
;
_converse
.
CONNECTION_STATUS
[
Strophe
.
Status
.
NOTACCEPTABLE
]
=
'
NOTACCEPTABLE
'
;
_converse
.
api
.
settings
.
update
({
'
allow_registration
'
:
true
,
'
domain_placeholder
'
:
__
(
"
e.g. conversejs.org
"
),
// Placeholder text shown in the domain input on the registration form
'
providers_link
'
:
'
https://compliance.conversations.im/
'
,
// Link to XMPP providers shown on registration page
'
registration_domain
'
:
''
});
...
...
@@ -679,6 +677,12 @@ converse.plugins.add('converse-register', {
return
false
;
}
});
/************************ BEGIN Event Handlers ************************/
_converse
.
api
.
listen
.
on
(
'
controlboxInitialized
'
,
view
=>
{
view
.
model
.
on
(
'
change:active-form
'
,
view
.
showLoginOrRegisterForm
,
view
);
});
/************************ END Event Handlers ************************/
}
});
src/converse-rosterview.js
View file @
1ef29bee
...
...
@@ -29,27 +29,6 @@ converse.plugins.add('converse-rosterview', {
dependencies
:
[
"
converse-roster
"
,
"
converse-modal
"
],
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.
//
// New functions which don't exist yet can also be added.
afterReconnected
()
{
this
.
__super__
.
afterReconnected
.
apply
(
this
,
arguments
);
},
RosterGroups
:
{
comparator
()
{
// RosterGroupsComparator only gets set later (once i18n is
// set up), so we need to wrap it in this nameless function.
const
{
_converse
}
=
this
.
__super__
;
return
_converse
.
RosterGroupsComparator
.
apply
(
this
,
arguments
);
}
}
},
initialize
()
{
/* The initialize function gets called as soon as the plugin is
* loaded by converse.js's plugin machinery.
...
...
@@ -78,36 +57,6 @@ converse.plugins.add('converse-rosterview', {
'
away
'
:
__
(
'
This contact is away
'
)
};
const
LABEL_GROUPS
=
__
(
'
Groups
'
);
const
HEADER_CURRENT_CONTACTS
=
__
(
'
My contacts
'
);
const
HEADER_PENDING_CONTACTS
=
__
(
'
Pending contacts
'
);
const
HEADER_REQUESTING_CONTACTS
=
__
(
'
Contact requests
'
);
const
HEADER_UNGROUPED
=
__
(
'
Ungrouped
'
);
const
HEADER_WEIGHTS
=
{};
HEADER_WEIGHTS
[
HEADER_REQUESTING_CONTACTS
]
=
0
;
HEADER_WEIGHTS
[
HEADER_CURRENT_CONTACTS
]
=
1
;
HEADER_WEIGHTS
[
HEADER_UNGROUPED
]
=
2
;
HEADER_WEIGHTS
[
HEADER_PENDING_CONTACTS
]
=
3
;
_converse
.
RosterGroupsComparator
=
function
(
a
,
b
)
{
/* Groups are sorted alphabetically, ignoring case.
* However, Ungrouped, Requesting Contacts and Pending Contacts
* appear last and in that order.
*/
a
=
a
.
get
(
'
name
'
);
b
=
b
.
get
(
'
name
'
);
const
special_groups
=
Object
.
keys
(
HEADER_WEIGHTS
);
const
a_is_special
=
_
.
includes
(
special_groups
,
a
);
const
b_is_special
=
_
.
includes
(
special_groups
,
b
);
if
(
!
a_is_special
&&
!
b_is_special
)
{
return
a
.
toLowerCase
()
<
b
.
toLowerCase
()
?
-
1
:
(
a
.
toLowerCase
()
>
b
.
toLowerCase
()
?
1
:
0
);
}
else
if
(
a_is_special
&&
b_is_special
)
{
return
HEADER_WEIGHTS
[
a
]
<
HEADER_WEIGHTS
[
b
]
?
-
1
:
(
HEADER_WEIGHTS
[
a
]
>
HEADER_WEIGHTS
[
b
]
?
1
:
0
);
}
else
if
(
!
a_is_special
&&
b_is_special
)
{
return
(
b
===
HEADER_REQUESTING_CONTACTS
)
?
1
:
-
1
;
}
else
if
(
a_is_special
&&
!
b_is_special
)
{
return
(
a
===
HEADER_REQUESTING_CONTACTS
)
?
-
1
:
1
;
}
};
_converse
.
AddContactModal
=
_converse
.
BootstrapModal
.
extend
({
...
...
@@ -678,7 +627,7 @@ converse.plugins.add('converse-rosterview', {
let
matches
;
q
=
q
.
toLowerCase
();
if
(
type
===
'
state
'
)
{
if
(
this
.
model
.
get
(
'
name
'
)
===
HEADER_REQUESTING_CONTACTS
)
{
if
(
this
.
model
.
get
(
'
name
'
)
===
_converse
.
HEADER_REQUESTING_CONTACTS
)
{
// When filtering by chat state, we still want to
// show requesting contacts, even though they don't
// have the state in question.
...
...
@@ -747,13 +696,13 @@ converse.plugins.add('converse-rosterview', {
},
onContactSubscriptionChange
(
contact
)
{
if
((
this
.
model
.
get
(
'
name
'
)
===
HEADER_PENDING_CONTACTS
)
&&
contact
.
get
(
'
subscription
'
)
!==
'
from
'
)
{
if
((
this
.
model
.
get
(
'
name
'
)
===
_converse
.
HEADER_PENDING_CONTACTS
)
&&
contact
.
get
(
'
subscription
'
)
!==
'
from
'
)
{
this
.
removeContact
(
contact
);
}
},
onContactRequestChange
(
contact
)
{
if
((
this
.
model
.
get
(
'
name
'
)
===
HEADER_REQUESTING_CONTACTS
)
&&
!
contact
.
get
(
'
requesting
'
))
{
if
((
this
.
model
.
get
(
'
name
'
)
===
_converse
.
HEADER_REQUESTING_CONTACTS
)
&&
!
contact
.
get
(
'
requesting
'
))
{
this
.
removeContact
(
contact
);
}
},
...
...
@@ -926,16 +875,16 @@ converse.plugins.add('converse-rosterview', {
this
.
update
();
if
(
_
.
has
(
contact
.
changed
,
'
subscription
'
))
{
if
(
contact
.
changed
.
subscription
===
'
from
'
)
{
this
.
addContactToGroup
(
contact
,
HEADER_PENDING_CONTACTS
);
this
.
addContactToGroup
(
contact
,
_converse
.
HEADER_PENDING_CONTACTS
);
}
else
if
(
_
.
includes
([
'
both
'
,
'
to
'
],
contact
.
get
(
'
subscription
'
)))
{
this
.
addExistingContact
(
contact
);
}
}
if
(
_
.
has
(
contact
.
changed
,
'
ask
'
)
&&
contact
.
changed
.
ask
===
'
subscribe
'
)
{
this
.
addContactToGroup
(
contact
,
HEADER_PENDING_CONTACTS
);
this
.
addContactToGroup
(
contact
,
_converse
.
HEADER_PENDING_CONTACTS
);
}
if
(
_
.
has
(
contact
.
changed
,
'
subscription
'
)
&&
contact
.
changed
.
requesting
===
'
true
'
)
{
this
.
addContactToGroup
(
contact
,
HEADER_REQUESTING_CONTACTS
);
this
.
addContactToGroup
(
contact
,
_converse
.
HEADER_REQUESTING_CONTACTS
);
}
this
.
updateFilter
();
},
...
...
@@ -961,10 +910,10 @@ converse.plugins.add('converse-rosterview', {
if
(
_converse
.
roster_groups
)
{
groups
=
contact
.
get
(
'
groups
'
);
if
(
groups
.
length
===
0
)
{
groups
=
[
HEADER_UNGROUPED
];
groups
=
[
_converse
.
HEADER_UNGROUPED
];
}
}
else
{
groups
=
[
HEADER_CURRENT_CONTACTS
];
groups
=
[
_converse
.
HEADER_CURRENT_CONTACTS
];
}
_
.
each
(
groups
,
_
.
bind
(
this
.
addContactToGroup
,
this
,
contact
,
_
,
options
));
},
...
...
@@ -982,9 +931,9 @@ converse.plugins.add('converse-rosterview', {
return
;
}
if
((
contact
.
get
(
'
ask
'
)
===
'
subscribe
'
)
||
(
contact
.
get
(
'
subscription
'
)
===
'
from
'
))
{
this
.
addContactToGroup
(
contact
,
HEADER_PENDING_CONTACTS
,
options
);
this
.
addContactToGroup
(
contact
,
_converse
.
HEADER_PENDING_CONTACTS
,
options
);
}
else
if
(
contact
.
get
(
'
requesting
'
)
===
true
)
{
this
.
addContactToGroup
(
contact
,
HEADER_REQUESTING_CONTACTS
,
options
);
this
.
addContactToGroup
(
contact
,
_converse
.
HEADER_REQUESTING_CONTACTS
,
options
);
}
}
return
this
;
...
...
src/converse-singleton.js
View file @
1ef29bee
...
...
@@ -82,7 +82,7 @@ converse.plugins.add('converse-singleton', {
const
{
_converse
}
=
this
.
__super__
;
if
(
_converse
.
isUniView
())
{
return
false
;
}
else
{
}
else
{
return
this
.
__super__
.
shouldShowOnTextMessage
.
apply
(
this
,
arguments
);
}
},
...
...
src/headless/converse-bookmarks.js
View file @
1ef29bee
...
...
@@ -40,13 +40,11 @@ converse.plugins.add('converse-bookmarks', {
// New functions which don't exist yet can also be added.
ChatRoom
:
{
getAndPersistNickname
(
nick
)
{
const
{
_converse
}
=
this
.
__super__
;
nick
=
nick
||
_converse
.
getNicknameFromBookmark
(
this
.
get
(
'
jid
'
));
return
this
.
__super__
.
getAndPersistNickname
.
call
(
this
,
nick
);
},
}
}
},
...
...
src/headless/converse-core.js
View file @
1ef29bee
...
...
@@ -251,7 +251,7 @@ _converse.log = function (message, level, style='') {
message
=
message
.
outerHTML
;
}
const
prefix
=
style
?
'
%c
'
:
''
;
const
logger
=
_
.
assign
({
const
logger
=
Object
.
assign
({
'
debug
'
:
_
.
get
(
console
,
'
log
'
)
?
console
.
log
.
bind
(
console
)
:
_
.
noop
,
'
error
'
:
_
.
get
(
console
,
'
log
'
)
?
console
.
log
.
bind
(
console
)
:
_
.
noop
,
'
info
'
:
_
.
get
(
console
,
'
log
'
)
?
console
.
log
.
bind
(
console
)
:
_
.
noop
,
...
...
src/headless/converse-mam.js
View file @
1ef29bee
...
...
@@ -29,9 +29,40 @@ converse.plugins.add('converse-mam', {
// Overrides mentioned here will be picked up by converse.js's
// plugin architecture they will replace existing methods on the
// relevant objects or classes.
//
// New functions which don't exist yet can also be added.
ChatBox
:
{
async
getDuplicateMessage
(
stanza
)
{
const
message
=
await
this
.
__super__
.
getDuplicateMessage
.
apply
(
this
,
arguments
);
if
(
!
message
)
{
return
this
.
findDuplicateFromArchiveID
(
stanza
);
}
return
message
;
},
getUpdatedMessageAttributes
(
message
,
stanza
)
{
const
attrs
=
this
.
__super__
.
getUpdatedMessageAttributes
.
apply
(
this
,
arguments
);
if
(
message
&&
!
message
.
get
(
'
is_archived
'
))
{
return
Object
.
assign
(
attrs
,
{
'
is_archived
'
:
this
.
isArchived
(
stanza
)
},
this
.
getStanzaIDs
(
stanza
))
}
return
attrs
;
}
}
},
initialize
()
{
/* The initialize function gets called as soon as the plugin is
* loaded by Converse.js's plugin machinery.
*/
const
{
_converse
}
=
this
;
_converse
.
api
.
settings
.
update
({
archived_messages_page_size
:
'
50
'
,
message_archiving
:
undefined
,
// Supported values are 'always', 'never', 'roster' (https://xmpp.org/extensions/xep-0313.html#prefs)
message_archiving_timeout
:
20000
,
// Time (in milliseconds) to wait before aborting MAM request
});
const
MAMEnabledChat
=
{
fetchNewestMessages
()
{
/* Fetches messages that might have been archived *after*
...
...
@@ -40,7 +71,6 @@ converse.plugins.add('converse-mam', {
if
(
this
.
disable_mam
)
{
return
;
}
const
{
_converse
}
=
this
.
__super__
;
const
most_recent_msg
=
u
.
getMostRecentMessage
(
this
);
if
(
_
.
isNil
(
most_recent_msg
))
{
...
...
@@ -59,7 +89,6 @@ converse.plugins.add('converse-mam', {
if
(
this
.
disable_mam
)
{
return
;
}
const
{
_converse
}
=
this
.
__super__
;
const
is_groupchat
=
this
.
get
(
'
type
'
)
===
CHATROOMS_TYPE
;
const
mam_jid
=
is_groupchat
?
this
.
get
(
'
jid
'
)
:
_converse
.
bare_jid
;
if
(
!
(
await
_converse
.
api
.
disco
.
supports
(
Strophe
.
NS
.
MAM
,
mam_jid
)))
{
...
...
@@ -92,7 +121,6 @@ converse.plugins.add('converse-mam', {
},
async
findDuplicateFromArchiveID
(
stanza
)
{
const
{
_converse
}
=
this
.
__super__
;
const
result
=
sizzle
(
`result[xmlns="
${
Strophe
.
NS
.
MAM
}
"]`
,
stanza
).
pop
();
if
(
!
result
)
{
return
null
;
...
...
@@ -107,32 +135,11 @@ converse.plugins.add('converse-mam', {
return
this
.
messages
.
findWhere
(
query
);
},
async
getDuplicateMessage
(
stanza
)
{
const
message
=
await
this
.
__super__
.
getDuplicateMessage
.
apply
(
this
,
arguments
);
if
(
!
message
)
{
return
this
.
findDuplicateFromArchiveID
(
stanza
);
}
return
message
;
},
getUpdatedMessageAttributes
(
message
,
stanza
)
{
const
attrs
=
this
.
__super__
.
getUpdatedMessageAttributes
.
apply
(
this
,
arguments
);
if
(
message
&&
!
message
.
get
(
'
is_archived
'
))
{
return
Object
.
assign
(
attrs
,
{
'
is_archived
'
:
this
.
isArchived
(
stanza
)
},
this
.
getStanzaIDs
(
stanza
))
}
return
attrs
;
}
},
}
Object
.
assign
(
_converse
.
ChatBox
.
prototype
,
MAMEnabledChat
);
ChatRoom
:
{
initialize
()
{
this
.
__super__
.
initialize
.
apply
(
this
,
arguments
);
this
.
on
(
'
change:mam_enabled
'
,
this
.
fetchArchivedMessagesIfNecessary
,
this
);
this
.
on
(
'
change:connection_status
'
,
this
.
fetchArchivedMessagesIfNecessary
,
this
);
},
Object
.
assign
(
_converse
.
ChatRoom
.
prototype
,
{
fetchArchivedMessagesIfNecessary
()
{
if
(
this
.
get
(
'
connection_status
'
)
!==
converse
.
ROOMSTATUS
.
ENTERED
||
!
this
.
get
(
'
mam_enabled
'
)
||
...
...
@@ -142,22 +149,9 @@ converse.plugins.add('converse-mam', {
this
.
fetchArchivedMessages
();
this
.
save
({
'
mam_initialized
'
:
true
});
}
},
},
initialize
()
{
/* The initialize function gets called as soon as the plugin is
* loaded by Converse.js's plugin machinery.
*/
const
{
_converse
}
=
this
;
_converse
.
api
.
settings
.
update
({
archived_messages_page_size
:
'
50
'
,
message_archiving
:
undefined
,
// Supported values are 'always', 'never', 'roster' (https://xmpp.org/extensions/xep-0313.html#prefs)
message_archiving_timeout
:
20000
,
// Time (in milliseconds) to wait before aborting MAM request
});
_converse
.
onMAMError
=
function
(
iq
)
{
if
(
iq
.
querySelectorAll
(
'
feature-not-implemented
'
).
length
)
{
_converse
.
log
(
...
...
@@ -220,6 +214,11 @@ converse.plugins.add('converse-mam', {
_converse
.
api
.
listen
.
on
(
'
afterMessagesFetched
'
,
chat
=>
chat
.
fetchNewestMessages
());
_converse
.
api
.
listen
.
on
(
'
chatReconnected
'
,
chat
=>
chat
.
fetchNewestMessages
());
_converse
.
api
.
listen
.
on
(
'
addClientFeatures
'
,
()
=>
_converse
.
api
.
disco
.
own
.
features
.
add
(
Strophe
.
NS
.
MAM
));
_converse
.
api
.
listen
.
on
(
'
chatRoomOpened
'
,
(
room
)
=>
{
room
.
on
(
'
change:mam_enabled
'
,
room
.
fetchArchivedMessagesIfNecessary
,
room
);
room
.
on
(
'
change:connection_status
'
,
room
.
fetchArchivedMessagesIfNecessary
,
room
);
});
/************************ END Event Handlers **************************/
...
...
src/headless/converse-roster.js
View file @
1ef29bee
...
...
@@ -36,6 +36,17 @@ converse.plugins.add('converse-roster', {
'
rosterInitialized
'
,
]);
_converse
.
HEADER_CURRENT_CONTACTS
=
__
(
'
My contacts
'
);
_converse
.
HEADER_PENDING_CONTACTS
=
__
(
'
Pending contacts
'
);
_converse
.
HEADER_REQUESTING_CONTACTS
=
__
(
'
Contact requests
'
);
_converse
.
HEADER_UNGROUPED
=
__
(
'
Ungrouped
'
);
const
HEADER_WEIGHTS
=
{};
HEADER_WEIGHTS
[
_converse
.
HEADER_REQUESTING_CONTACTS
]
=
0
;
HEADER_WEIGHTS
[
_converse
.
HEADER_CURRENT_CONTACTS
]
=
1
;
HEADER_WEIGHTS
[
_converse
.
HEADER_UNGROUPED
]
=
2
;
HEADER_WEIGHTS
[
_converse
.
HEADER_PENDING_CONTACTS
]
=
3
;
_converse
.
registerPresenceHandler
=
function
()
{
_converse
.
unregisterPresenceHandler
();
...
...
@@ -381,6 +392,10 @@ converse.plugins.add('converse-roster', {
model
:
_converse
.
RosterContact
,
comparator
(
contact1
,
contact2
)
{
/* Groups are sorted alphabetically, ignoring case.
* However, Ungrouped, Requesting Contacts and Pending Contacts
* appear last and in that order.
*/
const
status1
=
contact1
.
presence
.
get
(
'
show
'
)
||
'
offline
'
;
const
status2
=
contact2
.
presence
.
get
(
'
show
'
)
||
'
offline
'
;
if
(
_converse
.
STATUS_WEIGHTS
[
status1
]
===
_converse
.
STATUS_WEIGHTS
[
status2
])
{
...
...
@@ -854,6 +869,23 @@ converse.plugins.add('converse-roster', {
_converse
.
RosterGroups
=
Backbone
.
Collection
.
extend
({
model
:
_converse
.
RosterGroup
,
comparator
(
a
,
b
)
{
a
=
a
.
get
(
'
name
'
);
b
=
b
.
get
(
'
name
'
);
const
special_groups
=
Object
.
keys
(
HEADER_WEIGHTS
);
const
a_is_special
=
_
.
includes
(
special_groups
,
a
);
const
b_is_special
=
_
.
includes
(
special_groups
,
b
);
if
(
!
a_is_special
&&
!
b_is_special
)
{
return
a
.
toLowerCase
()
<
b
.
toLowerCase
()
?
-
1
:
(
a
.
toLowerCase
()
>
b
.
toLowerCase
()
?
1
:
0
);
}
else
if
(
a_is_special
&&
b_is_special
)
{
return
HEADER_WEIGHTS
[
a
]
<
HEADER_WEIGHTS
[
b
]
?
-
1
:
(
HEADER_WEIGHTS
[
a
]
>
HEADER_WEIGHTS
[
b
]
?
1
:
0
);
}
else
if
(
!
a_is_special
&&
b_is_special
)
{
return
(
b
===
_converse
.
HEADER_REQUESTING_CONTACTS
)
?
1
:
-
1
;
}
else
if
(
a_is_special
&&
!
b_is_special
)
{
return
(
a
===
_converse
.
HEADER_REQUESTING_CONTACTS
)
?
-
1
:
1
;
}
},
fetchRosterGroups
()
{
/* Fetches all the roster groups from sessionStorage.
*
...
...
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