Merge branch 'master' into converse-omemo
This commit is contained in:
commit
4c3645c559
@ -30,6 +30,7 @@
|
||||
- Documentation includes utf-8 charset to make minfied versions compatible across platforms. #1017
|
||||
- #1026 Typing in MUC shows "Typing from another device"
|
||||
- #1039 Multi-option data form elements not shown and saved correctly
|
||||
- #1143 Able to send blank message
|
||||
|
||||
### API changes
|
||||
|
||||
@ -39,6 +40,9 @@
|
||||
- New API method `_converse.api.vcard.update`.
|
||||
- The `contactStatusChanged` event has been renamed to `contactPresenceChanged`
|
||||
and a event `presenceChanged` is now also triggered on the contact.
|
||||
- `_converse.api.chats.open` and `_converse.api.rooms.open` now returns a
|
||||
`Presence` which resolves with the `Backbone.Model` representing the chat
|
||||
object.
|
||||
|
||||
## UI changes
|
||||
|
||||
|
1
Makefile
1
Makefile
@ -227,6 +227,7 @@ check: eslint
|
||||
html:
|
||||
rm -rf $(BUILDDIR)/html
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
make apidoc
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
|
289
dist/converse.js
vendored
289
dist/converse.js
vendored
@ -4529,7 +4529,7 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod
|
||||
/*! no static exports found */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
/* WEBPACK VAR INJECTION */(function(global) {var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;// Native Javascript for Bootstrap 4 v2.0.22 | © dnp_theme | MIT-License
|
||||
/* WEBPACK VAR INJECTION */(function(global) {var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;// Native Javascript for Bootstrap 4 v2.0.23 | © dnp_theme | MIT-License
|
||||
(function (root, factory) {
|
||||
if (true) {
|
||||
// AMD support:
|
||||
@ -4638,12 +4638,14 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod
|
||||
getBoundingClientRect = 'getBoundingClientRect',
|
||||
querySelectorAll = 'querySelectorAll',
|
||||
getElementsByCLASSNAME = 'getElementsByClassName',
|
||||
getComputedStyle = 'getComputedStyle',
|
||||
|
||||
indexOf = 'indexOf',
|
||||
parentNode = 'parentNode',
|
||||
length = 'length',
|
||||
toLowerCase = 'toLowerCase',
|
||||
Transition = 'Transition',
|
||||
Duration = 'Duration',
|
||||
Webkit = 'Webkit',
|
||||
style = 'style',
|
||||
push = 'push',
|
||||
@ -4672,6 +4674,7 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod
|
||||
// transitionEnd since 2.0.4
|
||||
supportTransitions = Webkit+Transition in HTML[style] || Transition[toLowerCase]() in HTML[style],
|
||||
transitionEndEvent = Webkit+Transition in HTML[style] ? Webkit[toLowerCase]()+Transition+'End' : Transition[toLowerCase]()+'end',
|
||||
transitionDuration = Webkit+Duration in HTML[style] ? Webkit[toLowerCase]()+Transition+Duration : Transition[toLowerCase]()+Duration,
|
||||
|
||||
// set new focus element since 2.0.3
|
||||
setFocus = function(element){
|
||||
@ -4725,9 +4728,16 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod
|
||||
off(element, event, handlerWrapper);
|
||||
});
|
||||
},
|
||||
getTransitionDurationFromElement = function(element) {
|
||||
var duration = globalObject[getComputedStyle](element)[transitionDuration];
|
||||
duration = parseFloat(duration);
|
||||
duration = typeof duration === 'number' && !isNaN(duration) ? duration * 1000 : 0;
|
||||
return duration + 50; // we take a short offset to make sure we fire on the next frame after animation
|
||||
},
|
||||
emulateTransitionEnd = function(element,handler){ // emulateTransitionEnd since 2.0.4
|
||||
if (supportTransitions) { one(element, transitionEndEvent, function(e){ handler(e); }); }
|
||||
else { handler(); }
|
||||
var called = 0, duration = getTransitionDurationFromElement(element);
|
||||
supportTransitions && one(element, transitionEndEvent, function(e){ handler(e); called = 1; });
|
||||
setTimeout(function() { !called && handler(); }, duration);
|
||||
},
|
||||
bootstrapCustomEvent = function (eventName, componentName, related) {
|
||||
var OriginalCustomEvent = new CustomEvent( eventName + '.bs.' + componentName);
|
||||
@ -4823,7 +4833,7 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod
|
||||
arrowLeft && (arrow[style][left] = arrowLeft + 'px');
|
||||
};
|
||||
|
||||
BSN.version = '2.0.22';
|
||||
BSN.version = '2.0.23';
|
||||
|
||||
/* Native Javascript for Bootstrap 4 | Alert
|
||||
-------------------------------------------*/
|
||||
@ -4993,7 +5003,7 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod
|
||||
// DATA API
|
||||
var intervalAttribute = element[getAttribute](dataInterval),
|
||||
intervalOption = options[interval],
|
||||
intervalData = intervalAttribute === 'false' ? 0 : parseInt(intervalAttribute) || 5000, // bootstrap carousel default interval
|
||||
intervalData = intervalAttribute === 'false' ? 0 : parseInt(intervalAttribute),
|
||||
pauseData = element[getAttribute](dataPause) === hoverEvent || false,
|
||||
keyboardData = element[getAttribute](dataKeyboard) === 'true' || false,
|
||||
|
||||
@ -5008,8 +5018,8 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod
|
||||
this[pause] = (options[pause] === hoverEvent || pauseData) ? hoverEvent : false; // false / hover
|
||||
|
||||
this[interval] = typeof intervalOption === 'number' ? intervalOption
|
||||
: intervalData === 0 ? 0
|
||||
: intervalData;
|
||||
: intervalOption === false || intervalData === 0 || intervalData === false ? 0
|
||||
: 5000; // bootstrap carousel default interval
|
||||
|
||||
// bind, event targets
|
||||
var self = this, index = element.index = 0, timer = element.timer = 0,
|
||||
@ -5128,10 +5138,10 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod
|
||||
addClass(slides[next],carouselItem +'-'+ slideDirection);
|
||||
addClass(slides[activeItem],carouselItem +'-'+ slideDirection);
|
||||
|
||||
one(slides[activeItem], transitionEndEvent, function(e) {
|
||||
var timeout = e[target] !== slides[activeItem] ? e.elapsedTime*1000 : 0;
|
||||
one(slides[next], transitionEndEvent, function(e) {
|
||||
var timeout = e[target] !== slides[next] ? e.elapsedTime*1000+100 : 20;
|
||||
|
||||
setTimeout(function(){
|
||||
isSliding && setTimeout(function(){
|
||||
isSliding = false;
|
||||
|
||||
addClass(slides[next],active);
|
||||
@ -5146,7 +5156,7 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod
|
||||
if ( !DOC.hidden && self[interval] && !hasClass(element,paused) ) {
|
||||
self.cycle();
|
||||
}
|
||||
},timeout+100);
|
||||
}, timeout);
|
||||
});
|
||||
|
||||
} else {
|
||||
@ -5211,23 +5221,24 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod
|
||||
|
||||
// event targets and constants
|
||||
var accordion = null, collapse = null, self = this,
|
||||
isAnimating = false, // when true it will prevent click handlers
|
||||
accordionData = element[getAttribute]('data-parent'),
|
||||
activeCollapse, activeElement,
|
||||
|
||||
// component strings
|
||||
component = 'collapse',
|
||||
collapsed = 'collapsed',
|
||||
isAnimating = 'isAnimating',
|
||||
|
||||
// private methods
|
||||
openAction = function(collapseElement,toggle) {
|
||||
bootstrapCustomEvent.call(collapseElement, showEvent, component);
|
||||
isAnimating = true;
|
||||
collapseElement[isAnimating] = true;
|
||||
addClass(collapseElement,collapsing);
|
||||
removeClass(collapseElement,component);
|
||||
collapseElement[style][height] = collapseElement[scrollHeight] + 'px';
|
||||
|
||||
emulateTransitionEnd(collapseElement, function() {
|
||||
isAnimating = false;
|
||||
collapseElement[isAnimating] = false;
|
||||
collapseElement[setAttribute](ariaExpanded,'true');
|
||||
toggle[setAttribute](ariaExpanded,'true');
|
||||
removeClass(collapseElement,collapsing);
|
||||
@ -5239,7 +5250,7 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod
|
||||
},
|
||||
closeAction = function(collapseElement,toggle) {
|
||||
bootstrapCustomEvent.call(collapseElement, hideEvent, component);
|
||||
isAnimating = true;
|
||||
collapseElement[isAnimating] = true;
|
||||
collapseElement[style][height] = collapseElement[scrollHeight] + 'px'; // set height first
|
||||
removeClass(collapseElement,component);
|
||||
removeClass(collapseElement,showClass);
|
||||
@ -5248,7 +5259,7 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod
|
||||
collapseElement[style][height] = '0px';
|
||||
|
||||
emulateTransitionEnd(collapseElement, function() {
|
||||
isAnimating = false;
|
||||
collapseElement[isAnimating] = false;
|
||||
collapseElement[setAttribute](ariaExpanded,'false');
|
||||
toggle[setAttribute](ariaExpanded,'false');
|
||||
removeClass(collapseElement,collapsing);
|
||||
@ -5267,29 +5278,29 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod
|
||||
// public methods
|
||||
this.toggle = function(e) {
|
||||
e[preventDefault]();
|
||||
if (isAnimating) return;
|
||||
if (!hasClass(collapse,showClass)) { self.show(); }
|
||||
else { self.hide(); }
|
||||
};
|
||||
this.hide = function() {
|
||||
if ( collapse[isAnimating] ) return;
|
||||
closeAction(collapse,element);
|
||||
addClass(element,collapsed);
|
||||
};
|
||||
this.show = function() {
|
||||
if ( accordion ) {
|
||||
var activeCollapse = queryElement('.'+component+'.'+showClass,accordion),
|
||||
toggle = activeCollapse && (queryElement('['+dataToggle+'="'+component+'"]['+dataTarget+'="#'+activeCollapse.id+'"]',accordion)
|
||||
|| queryElement('['+dataToggle+'="'+component+'"][href="#'+activeCollapse.id+'"]',accordion) ),
|
||||
correspondingCollapse = toggle && (toggle[getAttribute](dataTarget) || toggle.href);
|
||||
if ( activeCollapse && toggle && activeCollapse !== collapse ) {
|
||||
closeAction(activeCollapse,toggle);
|
||||
if ( correspondingCollapse.split('#')[1] !== collapse.id ) { addClass(toggle,collapsed); }
|
||||
else { removeClass(toggle,collapsed); }
|
||||
}
|
||||
activeCollapse = queryElement('.'+component+'.'+showClass,accordion);
|
||||
activeElement = activeCollapse && (queryElement('['+dataToggle+'="'+component+'"]['+dataTarget+'="#'+activeCollapse.id+'"]',accordion)
|
||||
|| queryElement('['+dataToggle+'="'+component+'"][href="#'+activeCollapse.id+'"]',accordion) );
|
||||
}
|
||||
|
||||
if ( !collapse[isAnimating] || activeCollapse && !activeCollapse[isAnimating] ) {
|
||||
if ( activeElement && activeCollapse !== collapse ) {
|
||||
closeAction(activeCollapse,activeElement);
|
||||
addClass(activeElement,collapsed);
|
||||
}
|
||||
openAction(collapse,element);
|
||||
removeClass(element,collapsed);
|
||||
}
|
||||
};
|
||||
|
||||
// init
|
||||
@ -5297,6 +5308,7 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod
|
||||
on(element, clickEvent, self.toggle);
|
||||
}
|
||||
collapse = getTarget();
|
||||
collapse[isAnimating] = false; // when true it will prevent click handlers
|
||||
accordion = queryElement(options.parent) || accordionData && getClosest(element, accordionData);
|
||||
element[stringCollapse] = self;
|
||||
};
|
||||
@ -5454,6 +5466,7 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod
|
||||
var btnCheck = element[getAttribute](dataTarget)||element[getAttribute]('href'),
|
||||
checkModal = queryElement( btnCheck ),
|
||||
modal = hasClass(element,'modal') ? element : checkModal,
|
||||
overlayDelay,
|
||||
|
||||
// strings
|
||||
component = 'modal',
|
||||
@ -5487,13 +5500,13 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod
|
||||
return globalObject[innerWidth] || (htmlRect[right] - Math.abs(htmlRect[left]));
|
||||
},
|
||||
setScrollbar = function () {
|
||||
var bodyStyle = globalObject.getComputedStyle(DOC[body]),
|
||||
var bodyStyle = globalObject[getComputedStyle](DOC[body]),
|
||||
bodyPad = parseInt((bodyStyle[paddingRight]), 10), itemPad;
|
||||
if (bodyIsOverflowing) {
|
||||
DOC[body][style][paddingRight] = (bodyPad + scrollbarWidth) + 'px';
|
||||
if (fixedItems[length]){
|
||||
for (var i = 0; i < fixedItems[length]; i++) {
|
||||
itemPad = globalObject.getComputedStyle(fixedItems[i])[paddingRight];
|
||||
itemPad = globalObject[getComputedStyle](fixedItems[i])[paddingRight];
|
||||
fixedItems[i][style][paddingRight] = ( parseInt(itemPad) + scrollbarWidth) + 'px';
|
||||
}
|
||||
}
|
||||
@ -5635,6 +5648,7 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod
|
||||
|
||||
if ( overlay && modalOverlay && !hasClass(overlay,showClass)) {
|
||||
overlay[offsetWidth]; // force reflow to enable trasition
|
||||
overlayDelay = getTransitionDurationFromElement(overlay);
|
||||
addClass(overlay, showClass);
|
||||
}
|
||||
|
||||
@ -5654,18 +5668,19 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod
|
||||
keydownHandlerToggle();
|
||||
|
||||
hasClass(modal,'fade') ? emulateTransitionEnd(modal, triggerShow) : triggerShow();
|
||||
}, supportTransitions ? 150 : 0);
|
||||
}, supportTransitions && overlay ? overlayDelay : 0);
|
||||
};
|
||||
this.hide = function() {
|
||||
bootstrapCustomEvent.call(modal, hideEvent, component);
|
||||
overlay = queryElement('.'+modalBackdropString);
|
||||
overlayDelay = overlay && getTransitionDurationFromElement(overlay);
|
||||
|
||||
removeClass(modal,showClass);
|
||||
modal[setAttribute](ariaHidden, true);
|
||||
|
||||
(function(){
|
||||
setTimeout(function(){
|
||||
hasClass(modal,'fade') ? emulateTransitionEnd(modal, triggerHide) : triggerHide();
|
||||
}());
|
||||
}, supportTransitions && overlay ? overlayDelay : 0);
|
||||
};
|
||||
this.setContent = function( content ) {
|
||||
queryElement('.'+component+'-content',modal)[innerHTML] = content;
|
||||
@ -6021,7 +6036,7 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod
|
||||
tabsContentContainer[style][height] = nextHeight + 'px'; // height animation
|
||||
tabsContentContainer[offsetWidth];
|
||||
emulateTransitionEnd(tabsContentContainer, triggerEnd);
|
||||
},1);
|
||||
},50);
|
||||
}
|
||||
} else {
|
||||
tabs[isAnimating] = false;
|
||||
@ -62132,9 +62147,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
return _converse.log(`Invalid JID "${jid}" provided in URL fragment`, Strophe.LogLevel.WARN);
|
||||
}
|
||||
|
||||
Promise.all([_converse.api.waitUntil('rosterContactsFetched'), _converse.api.waitUntil('chatBoxesFetched')]).then(() => {
|
||||
_converse.api.chats.open(jid);
|
||||
});
|
||||
}
|
||||
|
||||
_converse.router.route('converse/chat?jid=:jid', openChat);
|
||||
@ -62589,7 +62602,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
attrs.from = stanza.getAttribute('from');
|
||||
attrs.nick = Strophe.unescapeNode(Strophe.getResourceFromJid(attrs.from));
|
||||
|
||||
if (attrs.from === this.get('nick')) {
|
||||
if (Strophe.getResourceFromJid(attrs.from) === this.get('nick')) {
|
||||
attrs.sender = 'me';
|
||||
} else {
|
||||
attrs.sender = 'them';
|
||||
@ -63023,6 +63036,11 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
|
||||
|
||||
_.extend(_converse.api, {
|
||||
/**
|
||||
* The "chats" grouping (used for one-on-one chats)
|
||||
*
|
||||
* @namespace
|
||||
*/
|
||||
'chats': {
|
||||
'create'(jids, attrs) {
|
||||
if (_.isUndefined(jids)) {
|
||||
@ -63053,21 +63071,78 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Opens a new one-on-one chat.
|
||||
*
|
||||
* @function
|
||||
*
|
||||
* @param {String|string[]} name - e.g. 'buddy@example.com' or ['buddy1@example.com', 'buddy2@example.com']
|
||||
* @returns {Promise} Promise which resolves with the Backbone.Model representing the chat.
|
||||
*
|
||||
* @example
|
||||
* // To open a single chat, provide the JID of the contact you're chatting with in that chat:
|
||||
* converse.plugins.add('myplugin', {
|
||||
* initialize: function() {
|
||||
* var _converse = this._converse;
|
||||
* // Note, buddy@example.org must be in your contacts roster!
|
||||
* _converse.api.chats.open('buddy@example.com').then((chat) => {
|
||||
* // Now you can do something with the chat model
|
||||
* });
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* @example
|
||||
* // To open an array of chats, provide an array of JIDs:
|
||||
* converse.plugins.add('myplugin', {
|
||||
* initialize: function () {
|
||||
* var _converse = this._converse;
|
||||
* // Note, these users must first be in your contacts roster!
|
||||
* _converse.api.chats.open(['buddy1@example.com', 'buddy2@example.com']).then((chats) => {
|
||||
* // Now you can do something with the chat models
|
||||
* });
|
||||
* }
|
||||
* });
|
||||
*
|
||||
*/
|
||||
'open'(jids, attrs) {
|
||||
return new Promise((resolve, reject) => {
|
||||
Promise.all([_converse.api.waitUntil('rosterContactsFetched'), _converse.api.waitUntil('chatBoxesFetched')]).then(() => {
|
||||
if (_.isUndefined(jids)) {
|
||||
_converse.log("chats.open: You need to provide at least one JID", Strophe.LogLevel.ERROR);
|
||||
const err_msg = "chats.open: You need to provide at least one JID";
|
||||
|
||||
return null;
|
||||
_converse.log(err_msg, Strophe.LogLevel.ERROR);
|
||||
|
||||
reject(new Error(err_msg));
|
||||
} else if (_.isString(jids)) {
|
||||
const chatbox = _converse.api.chats.create(jids, attrs);
|
||||
|
||||
chatbox.trigger('show');
|
||||
return chatbox;
|
||||
resolve(_converse.api.chats.create(jids, attrs).trigger('show'));
|
||||
} else {
|
||||
resolve(_.map(jids, jid => _converse.api.chats.create(jid, attrs).trigger('show')));
|
||||
}
|
||||
|
||||
return _.map(jids, jid => _converse.api.chats.create(jid, attrs).trigger('show'));
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a chat model. The chat should already be open.
|
||||
*
|
||||
* @function
|
||||
*
|
||||
* @param {String|string[]} name - e.g. 'buddy@example.com' or ['buddy1@example.com', 'buddy2@example.com']
|
||||
* @returns {Backbone.Model}
|
||||
*
|
||||
* @example
|
||||
* // To return a single chat, provide the JID of the contact you're chatting with in that chat:
|
||||
* const model = _converse.api.chats.get('buddy@example.com');
|
||||
*
|
||||
* @example
|
||||
* // To return an array of chats, provide an array of JIDs:
|
||||
* const models = _converse.api.chats.get(['buddy1@example.com', 'buddy2@example.com']);
|
||||
*
|
||||
* @example
|
||||
* // To return all open chats, call the method without any parameters::
|
||||
* const models = _converse.api.chats.get();
|
||||
*
|
||||
*/
|
||||
'get'(jids) {
|
||||
if (_.isUndefined(jids)) {
|
||||
const result = [];
|
||||
@ -63975,6 +64050,11 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
ev.preventDefault();
|
||||
const textarea = this.el.querySelector('.chat-textarea'),
|
||||
message = textarea.value;
|
||||
|
||||
if (!message.replace(/\s/g, '').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
let spoiler_hint;
|
||||
|
||||
if (this.model.get('composing_spoiler')) {
|
||||
@ -63989,12 +64069,9 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
const event = document.createEvent('Event');
|
||||
event.initEvent('input', true, true);
|
||||
textarea.dispatchEvent(event);
|
||||
|
||||
if (message !== '') {
|
||||
this.onMessageSubmitted(message, spoiler_hint);
|
||||
|
||||
_converse.emit('messageSend', message);
|
||||
}
|
||||
|
||||
this.setChatState(_converse.ACTIVE);
|
||||
},
|
||||
@ -65155,7 +65232,11 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
_.extend(_converse, Backbone.Events); // Core plugins are whitelisted automatically
|
||||
|
||||
|
||||
_converse.core_plugins = ['converse-bookmarks', 'converse-caps', 'converse-chatboxes', 'converse-chatview', 'converse-controlbox', 'converse-core', 'converse-disco', 'converse-dragresize', 'converse-embedded', 'converse-fullscreen', 'converse-headline', 'converse-mam', 'converse-message-view', 'converse-minimize', 'converse-modal', 'converse-muc', 'converse-muc-views', 'converse-notification', 'converse-omemo', 'converse-oauth', 'converse-ping', 'converse-profile', 'converse-push', 'converse-register', 'converse-roomslist', 'converse-roster', 'converse-rosterview', 'converse-singleton', 'converse-spoilers', 'converse-vcard']; // Make converse pluggable
|
||||
_converse.core_plugins = ['converse-bookmarks', 'converse-caps', 'converse-chatboxes', 'converse-chatview', 'converse-controlbox', 'converse-core', 'converse-disco', 'converse-dragresize', 'converse-embedded', 'converse-fullscreen', 'converse-headline', 'converse-mam', 'converse-message-view', 'converse-minimize', 'converse-modal', 'converse-muc', 'converse-muc-views', 'converse-notification', 'converse-omemo', 'converse-oauth', 'converse-ping', 'converse-profile', 'converse-push', 'converse-register', 'converse-roomslist', 'converse-roster', 'converse-rosterview', 'converse-singleton', 'converse-spoilers', 'converse-vcard']; // Setting wait to 59 instead of 60 to avoid timing conflicts with the
|
||||
// webserver, which is often also set to 60 and might therefore sometimes
|
||||
// return a 504 error page instead of passing through to the BOSH proxy.
|
||||
|
||||
const BOSH_WAIT = 59; // Make converse pluggable
|
||||
|
||||
pluggable.enable(_converse, '_converse', 'pluggable'); // Module-level constants
|
||||
|
||||
@ -66159,7 +66240,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
this.connection.reset();
|
||||
}
|
||||
|
||||
this.connection.connect(this.jid.toLowerCase(), null, this.onConnectStatusChanged);
|
||||
this.connection.connect(this.jid.toLowerCase(), null, this.onConnectStatusChanged, BOSH_WAIT);
|
||||
} else if (this.authentication === _converse.LOGIN) {
|
||||
const password = _.isNil(credentials) ? _converse.connection.pass || this.password : credentials.password;
|
||||
|
||||
@ -66187,7 +66268,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
this.connection.reset();
|
||||
}
|
||||
|
||||
this.connection.connect(this.jid, password, this.onConnectStatusChanged);
|
||||
this.connection.connect(this.jid, password, this.onConnectStatusChanged, BOSH_WAIT);
|
||||
}
|
||||
};
|
||||
|
||||
@ -66850,6 +66931,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
});
|
||||
}
|
||||
|
||||
iqresult.c('query', attrs);
|
||||
|
||||
_.each(plugin._identities, identity => {
|
||||
const attrs = {
|
||||
'category': identity.category,
|
||||
@ -67605,8 +67688,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
throw new Error("converse-embedded: auto_join_rooms must be an Array");
|
||||
}
|
||||
|
||||
if (_converse.auto_join_rooms.length !== 1 && _converse.auto_join_private_chats.length !== 1) {
|
||||
throw new Error("converse-embedded: It doesn't make " + "sense to have the auto_join_rooms setting to zero or " + "more then one, since only one chat room can be open " + "at any time.");
|
||||
if (_converse.auto_join_rooms.length > 1 && _converse.auto_join_private_chats.length > 1) {
|
||||
throw new Error("converse-embedded: It doesn't make " + "sense to have the auto_join_rooms setting more then one, " + "since only one chat room can be open at any time.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -69911,17 +69994,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
this.model.on('show', this.show, this);
|
||||
this.model.occupants.on('add', this.showJoinNotification, this);
|
||||
this.model.occupants.on('remove', this.showLeaveNotification, this);
|
||||
this.model.occupants.on('change:show', occupant => {
|
||||
if (!occupant.isMember() || _.includes(occupant.get('states'), '303')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (occupant.get('show') === 'offline') {
|
||||
this.showLeaveNotification(occupant);
|
||||
} else if (occupant.get('show') === 'online') {
|
||||
this.showJoinNotification(occupant);
|
||||
}
|
||||
});
|
||||
this.model.occupants.on('change:show', this.showJoinOrLeaveNotification, this);
|
||||
this.createEmojiPicker();
|
||||
this.createOccupantsView();
|
||||
this.render().insertIntoDOM();
|
||||
@ -69931,8 +70004,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
const handler = () => {
|
||||
if (!u.isPersistableModel(this.model)) {
|
||||
// Happens during tests, nothing to do if this
|
||||
// is a hanging chatbox (i.e. not in the
|
||||
// collection anymore).
|
||||
// is a hanging chatbox (i.e. not in the collection anymore).
|
||||
return;
|
||||
}
|
||||
|
||||
@ -70809,6 +70881,18 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
}
|
||||
},
|
||||
|
||||
showJoinOrLeaveNotification(occupant) {
|
||||
if (!occupant.isMember() || _.includes(occupant.get('states'), '303')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (occupant.get('show') === 'offline') {
|
||||
this.showLeaveNotification(occupant);
|
||||
} else if (occupant.get('show') === 'online') {
|
||||
this.showJoinNotification(occupant);
|
||||
}
|
||||
},
|
||||
|
||||
showJoinNotification(occupant) {
|
||||
if (this.model.get('connection_status') !== converse.ROOMSTATUS.ENTERED) {
|
||||
return;
|
||||
@ -70856,10 +70940,9 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
showLeaveNotification(occupant) {
|
||||
const nick = occupant.get('nick'),
|
||||
stat = occupant.get('status'),
|
||||
last_el = this.content.lastElementChild,
|
||||
last_msg_date = last_el.getAttribute('data-isodate');
|
||||
last_el = this.content.lastElementChild;
|
||||
|
||||
if (_.includes(_.get(last_el, 'classList', []), 'chat-info') && moment(last_msg_date).isSame(new Date(), "day") && _.get(last_el, 'dataset', {}).join === `"${nick}"`) {
|
||||
if (last_el && _.includes(_.get(last_el, 'classList', []), 'chat-info') && moment(last_el.getAttribute('data-isodate')).isSame(new Date(), "day") && _.get(last_el, 'dataset', {}).join === `"${nick}"`) {
|
||||
let message;
|
||||
|
||||
if (_.isNil(stat)) {
|
||||
@ -70890,7 +70973,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
'data': `data-leave="${nick}"`
|
||||
};
|
||||
|
||||
if (_.includes(_.get(last_el, 'classList', []), 'chat-info') && _.get(last_el, 'dataset', {}).leavejoin === `"${nick}"`) {
|
||||
if (last_el && _.includes(_.get(last_el, 'classList', []), 'chat-info') && _.get(last_el, 'dataset', {}).leavejoin === `"${nick}"`) {
|
||||
last_el.outerHTML = tpl_info(data);
|
||||
} else {
|
||||
const el = u.stringToElement(tpl_info(data));
|
||||
@ -72789,13 +72872,21 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
},
|
||||
|
||||
'open'(jids, attrs) {
|
||||
return new Promise((resolve, reject) => {
|
||||
_converse.api.waitUntil('chatBoxesFetched').then(() => {
|
||||
if (_.isUndefined(jids)) {
|
||||
throw new TypeError('rooms.open: You need to provide at least one JID');
|
||||
} else if (_.isString(jids)) {
|
||||
return _converse.api.rooms.create(jids, attrs).trigger('show');
|
||||
}
|
||||
const err_msg = 'rooms.open: You need to provide at least one JID';
|
||||
|
||||
return _.map(jids, jid => _converse.api.rooms.create(jid, attrs).trigger('show'));
|
||||
_converse.log(err_msg, Strophe.LogLevel.ERROR);
|
||||
|
||||
reject(new TypeError(err_msg));
|
||||
} else if (_.isString(jids)) {
|
||||
resolve(_converse.api.rooms.create(jids, attrs).trigger('show'));
|
||||
} else {
|
||||
resolve(_.map(jids, jid => _converse.api.rooms.create(jid, attrs).trigger('show')));
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
'get'(jids, attrs, create) {
|
||||
@ -73262,7 +73353,12 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
getBundlesAndBuildSessions() {
|
||||
const _converse = this.__super__._converse;
|
||||
return new Promise((resolve, reject) => {
|
||||
_converse.getDevicesForContact(this.get('jid')).then(devices => {
|
||||
_converse.getDevicesForContact(this.get('jid')).then(their_devices => {
|
||||
const device_id = _converse.omemo_store.get('device_id'),
|
||||
devicelist = _converse.devicelists.get(_converse.bare_jid),
|
||||
own_devices = devicelist.devices.filter(device => device.get('id') !== device_id),
|
||||
devices = _.concat(own_devices, their_devices.models);
|
||||
|
||||
Promise.all(devices.map(device => device.getBundle())).then(() => this.buildSessions(devices)).then(() => resolve(devices)).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
|
||||
});
|
||||
@ -73329,19 +73425,23 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
const _converse = this.__super__._converse,
|
||||
address = new libsignal.SignalProtocolAddress(this.get('jid'), device.get('id')),
|
||||
sessionCipher = new window.libsignal.SessionCipher(_converse.omemo_store, address);
|
||||
return sessionCipher.encrypt(plaintext);
|
||||
return new Promise((resolve, reject) => {
|
||||
sessionCipher.encrypt(plaintext).then(payload => resolve({
|
||||
'payload': payload,
|
||||
'device': device
|
||||
})).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
|
||||
});
|
||||
},
|
||||
|
||||
addKeysToMessageStanza(stanza, devices, payloads) {
|
||||
for (var i in payloads) {
|
||||
if (Object.prototype.hasOwnProperty.call(payloads, i)) {
|
||||
const payload = btoa(JSON.stringify(payloads[i]));
|
||||
const prekey = 3 == parseInt(payloads[i].type, 10);
|
||||
|
||||
if (i == payloads.length - 1) {
|
||||
addKeysToMessageStanza(stanza, dicts, iv) {
|
||||
for (var i in dicts) {
|
||||
if (Object.prototype.hasOwnProperty.call(dicts, i)) {
|
||||
const payload = dicts[i].payload,
|
||||
device = dicts[i].device,
|
||||
prekey = 3 == parseInt(payload.type, 10);
|
||||
stanza.c('key', {
|
||||
'rid': devices.get('id')
|
||||
}).t(payload);
|
||||
'rid': device.get('id')
|
||||
}).t(btoa(JSON.stringify(dicts[i].payload)));
|
||||
|
||||
if (prekey) {
|
||||
stanza.attrs({
|
||||
@ -73349,12 +73449,10 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
});
|
||||
}
|
||||
|
||||
stanza.up().c('iv').t(payloads[0].iv).up().up();
|
||||
} else {
|
||||
stanza.c('key', {
|
||||
prekey: prekey,
|
||||
rid: devices.get('id')
|
||||
}).t(payload).up();
|
||||
stanza.up();
|
||||
|
||||
if (i == dicts.length - 1) {
|
||||
stanza.c('iv').t(iv).up().up();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -73389,8 +73487,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
// concatenation is encrypted using the corresponding
|
||||
// long-standing SignalProtocol session.
|
||||
// TODO: need to include own devices here as well (and filter out distrusted devices)
|
||||
const promises = devices.map(device => this.encryptKey(payload.key_str + payload.tag, device));
|
||||
return Promise.all(promises).then(payloads => this.addKeysToMessageStanza(stanza, devices, payloads));
|
||||
const promises = devices.filter(device => device.get('trusted') != UNTRUSTED).map(device => this.encryptKey(payload.key_str + payload.tag, device));
|
||||
return Promise.all(promises).then(dicts => this.addKeysToMessageStanza(stanza, dicts, payload.iv)).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
|
||||
});
|
||||
},
|
||||
|
||||
@ -78295,8 +78393,13 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||
|
||||
xhr.onload = function () {
|
||||
if (xhr.status >= 200 && xhr.status < 400) {
|
||||
jed_instance = new Jed(window.JSON.parse(xhr.responseText));
|
||||
try {
|
||||
const data = window.JSON.parse(xhr.responseText);
|
||||
jed_instance = new Jed(data);
|
||||
resolve();
|
||||
} catch (e) {
|
||||
xhr.onerror(e);
|
||||
}
|
||||
} else {
|
||||
xhr.onerror();
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Converse.js documentation build configuration file, created by
|
||||
# Converse documentation build configuration file, created by
|
||||
# sphinx-quickstart on Fri Apr 26 20:48:03 2013.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
@ -40,8 +40,8 @@ source_suffix = '.rst'
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Converse.js'
|
||||
copyright = u'2017, JC Brand'
|
||||
project = u'Converse'
|
||||
copyright = u'2018, JC Brand'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
@ -108,7 +108,7 @@ html_logo = "_static/conversejs_small.png"
|
||||
# theme further.
|
||||
html_theme_options = {
|
||||
# Navigation bar title. (Default: ``project`` value)
|
||||
'navbar_title': "Converse.js",
|
||||
'navbar_title': "Converse",
|
||||
# Tab name for entire site. (Default: "Site")
|
||||
'navbar_site_name': "Table of Contents",
|
||||
# A list of tuples containing pages or urls to link to.
|
||||
@ -229,7 +229,7 @@ latex_elements = {
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'Conversejs.tex', u'Converse.js Documentation',
|
||||
('index', 'Conversejs.tex', u'Converse Documentation',
|
||||
u'JC Brand', 'manual'),
|
||||
]
|
||||
|
||||
@ -259,7 +259,7 @@ latex_documents = [
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'conversejs', u'Converse.js Documentation',
|
||||
('index', 'conversejs', u'Converse Documentation',
|
||||
[u'JC Brand'], 1)
|
||||
]
|
||||
|
||||
@ -273,8 +273,8 @@ man_pages = [
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'Conversejs', u'Converse.js Documentation',
|
||||
u'JC Brand', 'Conversejs', 'Open Source XMPP webchat',
|
||||
('index', 'Conversejs', u'Converse Documentation',
|
||||
u'JC Brand', 'Converse', 'Open Source XMPP webchat',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
@ -2,12 +2,12 @@
|
||||
|
||||
<div id="banner"><a href="https://github.com/jcbrand/converse.js/blob/master/docs/source/theming.rst">Edit me on GitHub</a></div>
|
||||
|
||||
=============================
|
||||
The converse.js developer API
|
||||
=============================
|
||||
=========================
|
||||
The old API documentation
|
||||
=========================
|
||||
|
||||
.. note:: The API documented here is available in Converse.js 0.8.4 and higher.
|
||||
Earlier versions of Converse.js might have different API methods or none at all.
|
||||
.. note:: The API documented here is available in Converse 0.8.4 and higher.
|
||||
Earlier versions of Converse might have different API methods or none at all.
|
||||
|
||||
.. note:: From version 3.0.0 and onwards many API methods have been made
|
||||
private and available to plugins only. This means that if you want to
|
||||
@ -15,7 +15,7 @@ The converse.js developer API
|
||||
access it. This change is done to avoid leakage of sensitive data to
|
||||
malicious or non-whitelisted scripts.
|
||||
|
||||
The Converse.js API is broken up into different logical "groupings" (for
|
||||
The Converse API is broken up into different logical "groupings" (for
|
||||
example ``converse.plugins`` or ``converse.contacts``).
|
||||
|
||||
There are some exceptions to this, like ``converse.initialize``, which aren't
|
||||
@ -58,8 +58,8 @@ initialize
|
||||
|
||||
.. note:: This method is the one exception of a method which is not logically grouped as explained above.
|
||||
|
||||
Publich API method which initializes converse.js.
|
||||
This method must always be called when using converse.js.
|
||||
Publich API method which initializes Converse.
|
||||
This method must always be called when using Converse.
|
||||
|
||||
The `initialize` method takes a map of :ref:`configuration-settings`.
|
||||
|
||||
@ -105,7 +105,7 @@ Registers a new plugin.
|
||||
|
||||
// Inside this method, you have access to the closured
|
||||
// _converse object, which contains the core logic and data
|
||||
// structures of converse.js
|
||||
// structures of Converse
|
||||
}
|
||||
}
|
||||
converse.plugins.add('myplugin', plugin);
|
||||
@ -182,7 +182,7 @@ two important ways:
|
||||
* A handler registered for a promise, will still fire *after* the promise has
|
||||
been resolved, which is not the case with an event handler.
|
||||
|
||||
Converse.js has the following promises:
|
||||
Converse has the following promises:
|
||||
|
||||
* :ref:`cachedRoster`
|
||||
* :ref:`chatBoxesFetched`
|
||||
@ -210,7 +210,7 @@ already by that time.
|
||||
The **archive** grouping
|
||||
------------------------
|
||||
|
||||
Converse.js supports the *Message Archive Management*
|
||||
Converse supports the *Message Archive Management*
|
||||
(`XEP-0313 <https://xmpp.org/extensions/xep-0313.html>`_) protocol,
|
||||
through which it is able to query an XMPP server for archived messages.
|
||||
|
||||
@ -263,12 +263,12 @@ the returned messages.
|
||||
|
||||
**Waiting until server support has been determined**
|
||||
|
||||
The query method will only work if converse.js has been able to determine that
|
||||
The query method will only work if Converse has been able to determine that
|
||||
the server supports MAM queries, otherwise the following error will be raised:
|
||||
|
||||
- *This server does not support XEP-0313, Message Archive Management*
|
||||
|
||||
The very first time converse.js loads in a browser tab, if you call the query
|
||||
The very first time Converse loads in a browser tab, if you call the query
|
||||
API too quickly, the above error might appear because service discovery has not
|
||||
yet been completed.
|
||||
|
||||
@ -453,7 +453,7 @@ Paramters:
|
||||
get
|
||||
***
|
||||
|
||||
Returns all of the identities registered for this client (i.e. instance of Converse.js).
|
||||
Returns all of the identities registered for this client (i.e. instance of Converse).
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
@ -473,17 +473,17 @@ Paramters:
|
||||
* (String) name
|
||||
* (String) lang
|
||||
|
||||
Lets you add new identities for this client (i.e. instance of Converse.js).
|
||||
Lets you add new identities for this client (i.e. instance of Converse).
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
_converse.api.disco.own.identities.add('client', 'web', 'Converse.js');
|
||||
_converse.api.disco.own.identities.add('client', 'web', 'Converse');
|
||||
|
||||
|
||||
get
|
||||
***
|
||||
|
||||
Returns all of the identities registered for this client (i.e. instance of Converse.js).
|
||||
Returns all of the identities registered for this client (i.e. instance of Converse).
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
@ -602,7 +602,7 @@ Logs the user in. This method can accept a map with the credentials, like this:
|
||||
}
|
||||
});
|
||||
|
||||
or it can be called without any parameters, in which case converse.js will try
|
||||
or it can be called without any parameters, in which case Converse will try
|
||||
to log the user in by calling the `prebind_url` or `credentials_url` depending
|
||||
on whether prebinding is used or not.
|
||||
|
||||
@ -816,112 +816,67 @@ Note, for MUC chatrooms, you need to use the "rooms" grouping instead.
|
||||
get
|
||||
~~~
|
||||
|
||||
Returns an object representing a chatbox. The chatbox should already be open.
|
||||
Returns an object representing a chat. The chat should already be open.
|
||||
|
||||
To return a single chatbox, provide the JID of the contact you're chatting
|
||||
with in that chatbox:
|
||||
To return a single chat, provide the JID of the contact you're chatting
|
||||
with in that chat:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
_converse.api.chats.get('buddy@example.com')
|
||||
|
||||
To return an array of chatboxes, provide an array of JIDs:
|
||||
To return an array of chats, provide an array of JIDs:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
_converse.api.chats.get(['buddy1@example.com', 'buddy2@example.com'])
|
||||
|
||||
To return all open chatboxes, call the method without any JIDs::
|
||||
To return all open chats, call the method without any JIDs::
|
||||
|
||||
_converse.api.chats.get()
|
||||
|
||||
open
|
||||
~~~~
|
||||
|
||||
Opens a chatbox and returns a `Backbone.View <http://backbonejs.org/#View>`_ object
|
||||
representing a chatbox.
|
||||
Opens a new chat.
|
||||
|
||||
It returns an promise which will resolve with a `Backbone.Model <https://backbonejs.org/#Model>`_ representing the chat.
|
||||
|
||||
Note that converse doesn't allow opening chats with users who aren't in your roster
|
||||
(unless you have set :ref:`allow_non_roster_messaging` to ``true``).
|
||||
|
||||
Before opening a chat, you should first wait until the roster has been populated.
|
||||
This is the :ref:`rosterContactsFetched` event/promise.
|
||||
|
||||
Besides that, it's a good idea to also first wait until already opened chatboxes
|
||||
(which are cached in sessionStorage) have also been fetched from the cache.
|
||||
This is the :ref:`chatBoxesFetched` event/promise.
|
||||
|
||||
These two events fire only once per session, so they're also available as promises.
|
||||
|
||||
So, to open a single chatbox:
|
||||
So, to open a single chat:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
converse.plugins.add('myplugin', {
|
||||
initialize: function() {
|
||||
var _converse = this._converse;
|
||||
Promise.all([
|
||||
_converse.api.waitUntil('rosterContactsFetched'),
|
||||
_converse.api.waitUntil('chatBoxesFetched')
|
||||
]).then(function() {
|
||||
|
||||
// Note, buddy@example.org must be in your contacts roster!
|
||||
_converse.api.chats.open('buddy@example.com')
|
||||
_converse.api.chats.open('buddy@example.com').then((chat) => {
|
||||
// Now you can do something with the chat model
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
To return an array of chatboxes, provide an array of JIDs:
|
||||
To return an array of chats, provide an array of JIDs:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
converse.plugins.add('myplugin', {
|
||||
initialize: function () {
|
||||
var _converse = this._converse;
|
||||
Promise.all([
|
||||
_converse.api.waitUntil('rosterContactsFetched'),
|
||||
_converse.api.waitUntil('chatBoxesFetched')
|
||||
]).then(function() {
|
||||
// Note, these users must first be in your contacts roster!
|
||||
_converse.api.chats.open(['buddy1@example.com', 'buddy2@example.com'])
|
||||
_converse.api.chats.open(['buddy1@example.com', 'buddy2@example.com']).then((chats) => {
|
||||
// Now you can do something with the chat models
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
*The returned chatbox object contains the following methods:*
|
||||
|
||||
+-------------------+------------------------------------------+
|
||||
| Method | Description |
|
||||
+===================+==========================================+
|
||||
| close | Close the chatbox. |
|
||||
+-------------------+------------------------------------------+
|
||||
| focus | Focuses the chatbox textarea |
|
||||
+-------------------+------------------------------------------+
|
||||
| model.endOTR | End an OTR (Off-the-record) session. |
|
||||
+-------------------+------------------------------------------+
|
||||
| model.get | Get an attribute (i.e. accessor). |
|
||||
+-------------------+------------------------------------------+
|
||||
| model.initiateOTR | Start an OTR (off-the-record) session. |
|
||||
+-------------------+------------------------------------------+
|
||||
| model.maximize | Minimize the chatbox. |
|
||||
+-------------------+------------------------------------------+
|
||||
| model.minimize | Maximize the chatbox. |
|
||||
+-------------------+------------------------------------------+
|
||||
| model.set | Set an attribute (i.e. mutator). |
|
||||
+-------------------+------------------------------------------+
|
||||
| show | Opens/shows the chatbox. |
|
||||
+-------------------+------------------------------------------+
|
||||
|
||||
*The get and set methods can be used to retrieve and change the following attributes:*
|
||||
|
||||
+-------------+-----------------------------------------------------+
|
||||
| Attribute | Description |
|
||||
+=============+=====================================================+
|
||||
| height | The height of the chatbox. |
|
||||
+-------------+-----------------------------------------------------+
|
||||
| url | The URL of the chatbox heading. |
|
||||
+-------------+-----------------------------------------------------+
|
||||
|
||||
The **chatviews** grouping
|
||||
--------------------------
|
||||
|
||||
@ -952,7 +907,7 @@ To return an array of views, provide an array of JIDs:
|
||||
The **listen** grouping
|
||||
-----------------------
|
||||
|
||||
Converse.js emits events to which you can subscribe from your own JavaScript.
|
||||
Converse emits events to which you can subscribe from your own JavaScript.
|
||||
|
||||
Concerning events, the following methods are available under the "listen"
|
||||
grouping:
|
||||
@ -1014,7 +969,7 @@ The **rooms** grouping
|
||||
get
|
||||
~~~
|
||||
|
||||
Returns an object representing a multi user chatbox (room).
|
||||
Returns an object representing a multi user chat (room).
|
||||
It takes 3 parameters:
|
||||
|
||||
* the room JID (if not specified, all rooms will be returned).
|
||||
@ -1046,7 +1001,7 @@ It takes 3 parameters:
|
||||
open
|
||||
~~~~
|
||||
|
||||
Opens a multi user chatbox and returns an object representing it.
|
||||
Opens a multi user chat and returns an object representing it.
|
||||
Similar to the ``chats.get`` API.
|
||||
|
||||
It takes 2 parameters:
|
||||
@ -1055,7 +1010,7 @@ It takes 2 parameters:
|
||||
* A map (object) containing any extra room attributes. For example, if you want
|
||||
to specify the nickname, use ``{'nick': 'bloodninja'}``.
|
||||
|
||||
To open a single multi user chatbox, provide the JID of the room:
|
||||
To open a single multi user chat, provide the JID of the room:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
@ -1150,7 +1105,7 @@ JIDs.
|
||||
The **promises** grouping
|
||||
-------------------------
|
||||
|
||||
Converse.js and its plugins emit various events which you can listen to via the
|
||||
Converse and its plugins emit various events which you can listen to via the
|
||||
:ref:`listen-grouping`.
|
||||
|
||||
Some of these events are also available as `ES2015 Promises <http://es6-features.org/#PromiseUsage>`_,
|
||||
@ -1209,7 +1164,7 @@ For example:
|
||||
The **settings** grouping
|
||||
-------------------------
|
||||
|
||||
This grouping allows access to the configuration settings of converse.js.
|
||||
This grouping allows access to the configuration settings of Converse.
|
||||
|
||||
.. _`settings-update`:
|
||||
|
||||
@ -1290,7 +1245,7 @@ or :
|
||||
});
|
||||
|
||||
Note, this is not an alternative to calling ``converse.initialize``, which still needs
|
||||
to be called. Generally, you'd use this method after converse.js is already
|
||||
to be called. Generally, you'd use this method after Converse is already
|
||||
running and you want to change the configuration on-the-fly.
|
||||
|
||||
The **tokens** grouping
|
||||
@ -1328,7 +1283,7 @@ Parameters:
|
||||
|
||||
Returns a Promise which results with the VCard data for a particular JID or for
|
||||
a `Backbone.Model` instance which represents an entity with a JID (such as a roster contact,
|
||||
chatbox or chatroom occupant).
|
||||
chat or chatroom occupant).
|
||||
|
||||
If a `Backbone.Model` instance is passed in, then it must have either a `jid`
|
||||
attribute or a `muc_jid` attribute.
|
||||
|
@ -8,13 +8,13 @@
|
||||
Development
|
||||
===========
|
||||
|
||||
Welcome to the developer documentation of converse.js. Read the documentation
|
||||
Welcome to the developer documentation of Converse. Read the documentation
|
||||
linked to below, if you want to add new features or create your own customized
|
||||
version of converse.js.
|
||||
version of Converse.
|
||||
|
||||
Converse.js itself composed of plugins, and exposes an API with which you can
|
||||
Converse itself composed of plugins, and exposes an API with which you can
|
||||
create and register your own plugins. This is the recommended way to customize
|
||||
or add new functionality to converse.js.
|
||||
or add new functionality to Converse.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
@ -22,6 +22,7 @@ or add new functionality to converse.js.
|
||||
developer_guidelines
|
||||
style_guide
|
||||
plugin_development
|
||||
api/index
|
||||
developer_api
|
||||
events
|
||||
other_frameworks
|
||||
|
@ -8,19 +8,19 @@
|
||||
Setup and integration
|
||||
=====================
|
||||
|
||||
This page documents what you'll need to do to be able to connect Converse.js with
|
||||
This page documents what you'll need to do to be able to connect Converse with
|
||||
your own XMPP server and to better integrate it into your website.
|
||||
|
||||
At the very least you'll need Converse.js and an :ref:`XMPP server` with
|
||||
At the very least you'll need Converse and an :ref:`XMPP server` with
|
||||
:ref:`websocket-section` or :ref:`BOSH-section` enabled. That's definitely
|
||||
enough to simply demo Converse.js or to do development work on it.
|
||||
enough to simply demo Converse or to do development work on it.
|
||||
|
||||
However, if you want to more fully integrate it into a website or intranet,
|
||||
However, if you want to more fully integrate it into a website
|
||||
then you'll likely need to set up more services and components.
|
||||
|
||||
The diagram below shows a fairly common setup for a website or intranet:
|
||||
|
||||
* Converse.js runs in the web-browser on the user's device.
|
||||
* Converse runs in the web-browser on the user's device.
|
||||
|
||||
* It communicates with the XMPP server via BOSH or websocket which is usually
|
||||
reverse-proxied by a web-server in order to overcome cross-site scripting
|
||||
@ -34,13 +34,12 @@ The diagram below shows a fairly common setup for a website or intranet:
|
||||
the XMPP server is configured to use, so that users can log in with those
|
||||
credentials.
|
||||
|
||||
|
||||
* Usually (but optionally) there is a backend web application which hosts a
|
||||
website in which Converse.js appears.
|
||||
website in which Converse appears.
|
||||
|
||||
.. figure:: images/diagram.png
|
||||
:align: center
|
||||
:alt: A diagram of a possible setup, consisting of Converse.js, a web server, a backend web application, an XMPP server, a user directory such as LDAP and an XMPP server.
|
||||
:alt: A diagram of a possible setup, consisting of Converse, a web server, a backend web application, an XMPP server, a user directory such as LDAP and an XMPP server.
|
||||
|
||||
This diagram shows the various services in a fairly common setup (image generated with `draw.io <https://draw.io>`_).
|
||||
|
||||
@ -53,11 +52,11 @@ The various components
|
||||
An XMPP server
|
||||
==============
|
||||
|
||||
*Converse.js* implements `XMPP <http://xmpp.org/about-xmpp/>`_ as its
|
||||
*Converse* uses `XMPP <http://xmpp.org/about-xmpp/>`_ as its
|
||||
messaging protocol, and therefore needs to connect to an XMPP/Jabber
|
||||
server (Jabber® is an older and more user-friendly synonym for XMPP).
|
||||
|
||||
You can connect to public XMPP servers like ``jabber.org`` but if you want to
|
||||
You can connect to public XMPP servers like ``conversejs.org`` but if you want to
|
||||
have :ref:`session support <session-support>` you'll have to set up your own XMPP server.
|
||||
|
||||
You can find a list of public XMPP servers/providers on `xmpp.net <https://list.jabber.at>`_
|
||||
@ -79,7 +78,7 @@ stanzas to be sent over an HTTP connection.
|
||||
HTTP connections are stateless and usually shortlived.
|
||||
XMPP connections on the other hand are stateful and usually last much longer.
|
||||
|
||||
So to enable a web application like *Converse.js* to communicate with an XMPP
|
||||
So to enable a web application like *Converse* to communicate with an XMPP
|
||||
server, we need a proxy which acts as a bridge between these two protocols.
|
||||
|
||||
This is the job of a BOSH connection manager. BOSH (Bidirectional-streams Over
|
||||
@ -87,7 +86,7 @@ Synchronous HTTP) is a protocol for allowing XMPP communication over HTTP. The
|
||||
protocol is defined in `XEP-0206: XMPP Over BOSH <http://xmpp.org/extensions/xep-0206.html>`_.
|
||||
|
||||
Popular XMPP servers such as `Ejabberd <http://www.ejabberd.im>`_,
|
||||
prosody `(mod_bosh) <http://prosody.im/doc/setting_up_bosh>`_ and
|
||||
Prosody `(mod_bosh) <http://prosody.im/doc/setting_up_bosh>`_ and
|
||||
`OpenFire <http://www.igniterealtime.org/projects/openfire/>`_ all include
|
||||
their own BOSH connection managers (but you usually have to enable them in the
|
||||
configuration).
|
||||
@ -98,14 +97,15 @@ https://conversejs.org does), then you'll need a standalone connection manager.
|
||||
For a standalone manager, see for example `Punjab <https://github.com/twonds/punjab>`_
|
||||
and `node-xmpp-bosh <https://github.com/dhruvbird/node-xmpp-bosh>`_.
|
||||
|
||||
The demo on the `Converse.js homepage <http://conversejs.org>`_ uses a connection
|
||||
The demo on the `Converse homepage <http://conversejs.org>`_ uses a connection
|
||||
manager located at https://conversejs.org/http-bind.
|
||||
|
||||
This connection manager is available for testing purposes only, please don't
|
||||
use it in production.
|
||||
|
||||
Refer to the :ref:`bosh-service-url` configuration setting for information on
|
||||
how to configure Converse.js to connect to a BOSH URL.
|
||||
how to configure Converse to connect to a BOSH URL.
|
||||
|
||||
|
||||
.. _`websocket-section`:
|
||||
|
||||
@ -122,7 +122,7 @@ HTTP. Therefore BOSH, which operates over HTTP, doesn't apply to websockets.
|
||||
does the node-xmpp-bosh connection manager.
|
||||
|
||||
Refer to the :ref:`websocket-url` configuration setting for information on how to
|
||||
configure Converse.js to connect to a websocket URL.
|
||||
configure Converse to connect to a websocket URL.
|
||||
|
||||
The Webserver
|
||||
=============
|
||||
@ -133,7 +133,7 @@ Overcoming cross-domain request restrictions
|
||||
Lets say your domain is *example.org*, but the domain of your connection
|
||||
manager is *example.com*.
|
||||
|
||||
HTTP requests are made by *Converse.js* to the BOSH connection manager via
|
||||
HTTP requests are made by *Converse* to the BOSH connection manager via
|
||||
XmlHttpRequests (XHR). Until recently, it was not possible to make such
|
||||
requests to a different domain than the one currently being served
|
||||
(to prevent XSS attacks).
|
||||
@ -159,7 +159,7 @@ Examples:
|
||||
Assuming your site is accessible on port ``80`` for the domain ``mysite.com``
|
||||
and your connection manager manager is running at ``someothersite.com/http-bind``.
|
||||
|
||||
The *bosh_service_url* value you want to give Converse.js to overcome
|
||||
The *bosh_service_url* value you want to give Converse to overcome
|
||||
the cross-domain restriction is ``mysite.com/http-bind`` and not
|
||||
``someothersite.com/http-bind``.
|
||||
|
||||
@ -192,6 +192,32 @@ Apache
|
||||
</VirtualHost>
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
If you're getting XML parsing errors for your BOSH endpoint, for
|
||||
example::
|
||||
|
||||
XML Parsing Error: mismatched tag. Expected: </hr>.
|
||||
Location: https://example.org/http-bind/
|
||||
Line Number 6, Column 3: bosh-anon:6:3
|
||||
Also ERROR: request id 12.2 error 504 happened
|
||||
|
||||
Then your BOSH proxy is returning an HTML error page (for a 504 error in
|
||||
the above example).
|
||||
|
||||
This might be because your webserver and BOSH proxy have the same timeout
|
||||
for BOSH requests. Because the webserver receives the request slightly earlier,
|
||||
it gives up a few microseconds before the XMPP server’s empty result and thus returns a
|
||||
504 error page containing HTML to browser, which then gets parsed as if its
|
||||
XML.
|
||||
|
||||
To fix this, make sure that the webserver's timeout is slightly higher.
|
||||
In Nginx you can do this by adding ``proxy_read_timeout 61;``;
|
||||
|
||||
From Converse 4.0.0 onwards the default ``wait`` time is set to 59 seconds, to avoid
|
||||
this problem.
|
||||
|
||||
|
||||
.. _`session-support`:
|
||||
|
||||
Single Session Support
|
||||
@ -215,7 +241,7 @@ authenticated BOSH session with the XMPP server or a standalone `BOSH <http://xm
|
||||
connection manager.
|
||||
|
||||
Once authenticated, it receives RID and SID tokens which need to be passed
|
||||
on to converse.js upon pa. Converse.js will then attach to that same session using
|
||||
on to converse.js upon pa. Converse will then attach to that same session using
|
||||
those tokens.
|
||||
|
||||
It's called "prebind" because you bind to the BOSH session beforehand, and then
|
||||
@ -250,7 +276,7 @@ converse.js can then attach to.
|
||||
A BOSH server acts as a bridge between HTTP, the protocol of the web, and
|
||||
XMPP, the instant messaging protocol.
|
||||
|
||||
Converse.js can only communicate via HTTP (or websocket, in which case BOSH can't be used).
|
||||
Converse can only communicate via HTTP (or websocket, in which case BOSH can't be used).
|
||||
It cannot open TCP sockets to communicate to an XMPP server directly.
|
||||
|
||||
So the BOSH server acts as a middle man, translating our HTTP requests into XMPP stanzas and vice versa.
|
||||
@ -303,7 +329,7 @@ authentication to external services. They are listed in the `Prosody community m
|
||||
page <https://modules.prosody.im/>`_. Other XMPP servers have similar plugin modules.
|
||||
|
||||
If your web-application has access to the same credentials, it can send those
|
||||
credentials to Converse.js so that user's are automatically logged in when the
|
||||
credentials to Converse so that user's are automatically logged in when the
|
||||
page loads.
|
||||
|
||||
This is can be done by setting :ref:`auto_login` to true and configuring the
|
||||
@ -316,7 +342,7 @@ The first option has the drawback that your web-application needs to know the
|
||||
XMPP credentials of your users and that they need to be stored in the clear.
|
||||
|
||||
The second option has that same drawback and it also needs to pass those
|
||||
credentials to Converse.js.
|
||||
credentials to Converse.
|
||||
|
||||
To avoid these drawbacks, you can instead let your backend web application
|
||||
generate temporary authentication tokens which are then sent to the XMPP server
|
||||
|
File diff suppressed because one or more lines are too long
@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: Converse.js 3.3.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-07-22 11:17+0200\n"
|
||||
"PO-Revision-Date: 2018-07-22 11:49+0200\n"
|
||||
"PO-Revision-Date: 2018-08-02 05:34+0000\n"
|
||||
"Last-Translator: ButterflyOfFire <ButterflyOfFire@protonmail.com>\n"
|
||||
"Language-Team: Arabic <https://hosted.weblate.org/projects/conversejs/"
|
||||
"translations/ar/>\n"
|
||||
@ -18,28 +18,25 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
|
||||
"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
|
||||
"X-Generator: Weblate 3.0\n"
|
||||
"X-Generator: Weblate 3.1.1\n"
|
||||
|
||||
#: dist/converse-no-dependencies.js:40690
|
||||
#: dist/converse-no-dependencies.js:40775
|
||||
#: dist/converse-no-dependencies.js:53689
|
||||
#, fuzzy
|
||||
msgid "Bookmark this groupchat"
|
||||
msgstr "إضافة هذه الغرفة إلى الفواصل المرجعية"
|
||||
msgstr "إضافة فريق المحادثة هذا إلى الفواصل المرجعية"
|
||||
|
||||
#: dist/converse-no-dependencies.js:40776
|
||||
msgid "The name for this bookmark:"
|
||||
msgstr "تسمية الفاصلة المرجعية :"
|
||||
|
||||
#: dist/converse-no-dependencies.js:40777
|
||||
#, fuzzy
|
||||
msgid "Would you like this groupchat to be automatically joined upon startup?"
|
||||
msgstr "هل تود الإلتحاق بهذه الغرفة آليا مباشَرةً بعد الإتصال ؟"
|
||||
msgstr "هل تريد الإلتحاق آليًا بفريق المحادثة هذا مباشَرةً بعد الإتصال ؟"
|
||||
|
||||
#: dist/converse-no-dependencies.js:40778
|
||||
#, fuzzy
|
||||
msgid "What should your nickname for this groupchat be?"
|
||||
msgstr "ما هو الإسم المُستعار الذي تريد استخدامه في غرفة المحادثة هذه ؟"
|
||||
msgstr "ما هو الإسم المُستعار الذي تريد استخدامه في فريق المحادثة هذا ؟"
|
||||
|
||||
#: dist/converse-no-dependencies.js:40780
|
||||
#: dist/converse-no-dependencies.js:49483
|
||||
@ -66,9 +63,8 @@ msgstr "المعذرة، لقد طرأ هناك خطأ أثناء محاولة
|
||||
|
||||
#: dist/converse-no-dependencies.js:41055
|
||||
#: dist/converse-no-dependencies.js:53687
|
||||
#, fuzzy
|
||||
msgid "Leave this groupchat"
|
||||
msgstr "الخروج مِن هذه الغرفة"
|
||||
msgstr "مغادرة فريق المحادثة"
|
||||
|
||||
#: dist/converse-no-dependencies.js:41056
|
||||
msgid "Remove this bookmark"
|
||||
@ -76,23 +72,20 @@ msgstr "إزالة هذه الفاصلة المرجعية"
|
||||
|
||||
#: dist/converse-no-dependencies.js:41057
|
||||
#: dist/converse-no-dependencies.js:53688
|
||||
#, fuzzy
|
||||
msgid "Unbookmark this groupchat"
|
||||
msgstr "تنحية غرفة المحادثة مِن الفواصل المرجعية"
|
||||
msgstr "تنحية فريق المحادثة مِن الفواصل المرجعية"
|
||||
|
||||
#: dist/converse-no-dependencies.js:41058
|
||||
#: dist/converse-no-dependencies.js:48755
|
||||
#: dist/converse-no-dependencies.js:53690
|
||||
#, fuzzy
|
||||
msgid "Show more information on this groupchat"
|
||||
msgstr "عرض المزيد مِن التفاصيل عن هذه الغرفة"
|
||||
msgstr "عرض المزيد مِن التفاصيل عن فريق المحادثة هذا"
|
||||
|
||||
#: dist/converse-no-dependencies.js:41061
|
||||
#: dist/converse-no-dependencies.js:48754
|
||||
#: dist/converse-no-dependencies.js:53692
|
||||
#, fuzzy
|
||||
msgid "Click to open this groupchat"
|
||||
msgstr "أنقر لفتح غرفة المحادثة هذه"
|
||||
msgstr "أنقر لفتح فريق المحادثة هذا"
|
||||
|
||||
#: dist/converse-no-dependencies.js:41097
|
||||
msgid "Click to toggle the bookmarks list"
|
||||
@ -111,11 +104,11 @@ msgid "Sorry, could not determine upload URL."
|
||||
msgstr ""
|
||||
|
||||
#: dist/converse-no-dependencies.js:41573
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid ""
|
||||
"Sorry, could not succesfully upload your file. Your server’s response: \"%1$s"
|
||||
"\""
|
||||
msgstr "للأسف لم نتمكّن مِن القيام برفع ملفك بنجاح."
|
||||
msgstr "للأسف لم نتمكّن مِن القيام برفع ملفك بنجاح. أجاب خادومك : \"%1$s\""
|
||||
|
||||
#: dist/converse-no-dependencies.js:41575
|
||||
msgid "Sorry, could not succesfully upload your file."
|
||||
@ -163,9 +156,8 @@ msgid "Full Name"
|
||||
msgstr ""
|
||||
|
||||
#: dist/converse-no-dependencies.js:42572
|
||||
#, fuzzy
|
||||
msgid "Jabber ID"
|
||||
msgstr "مُعرَّف حساب جابر :"
|
||||
msgstr "مُعرَّف حساب جابر"
|
||||
|
||||
#: dist/converse-no-dependencies.js:42573
|
||||
#: dist/converse-no-dependencies.js:49639
|
||||
@ -174,9 +166,8 @@ msgid "Nickname"
|
||||
msgstr "الإسم المُستعار"
|
||||
|
||||
#: dist/converse-no-dependencies.js:42574
|
||||
#, fuzzy
|
||||
msgid "Remove as contact"
|
||||
msgstr "إضافة مراسل"
|
||||
msgstr "إزالة مِن المراسِلين"
|
||||
|
||||
#: dist/converse-no-dependencies.js:42575
|
||||
msgid "Refresh"
|
||||
@ -248,7 +239,6 @@ msgid "Clear all messages"
|
||||
msgstr "تنظيف كافة الرسائل"
|
||||
|
||||
#: dist/converse-no-dependencies.js:42815
|
||||
#, fuzzy
|
||||
msgid "Insert emojis"
|
||||
msgstr "إدراج وجه مبتسم"
|
||||
|
||||
@ -275,25 +265,25 @@ msgid "Are you sure you want to clear the messages from this conversation?"
|
||||
msgstr "هل أنت متأكد أنك تود مسح الرسائل مِن نافذة المحادثة هذه ؟"
|
||||
|
||||
#: dist/converse-no-dependencies.js:43413
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s has gone offline"
|
||||
msgstr "قد قطع الإتصال"
|
||||
msgstr "%1$s قد قطع الإتصال"
|
||||
|
||||
#: dist/converse-no-dependencies.js:43415
|
||||
#: dist/converse-no-dependencies.js:47662
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s has gone away"
|
||||
msgstr "قد غاب"
|
||||
msgstr "%1$s قد غاب"
|
||||
|
||||
#: dist/converse-no-dependencies.js:43417
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s is busy"
|
||||
msgstr "مشغول"
|
||||
msgstr "%1$s مشغول"
|
||||
|
||||
#: dist/converse-no-dependencies.js:43419
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s is online"
|
||||
msgstr "متصل"
|
||||
msgstr "%1$s متصل"
|
||||
|
||||
#: dist/converse-no-dependencies.js:44042
|
||||
msgid "Username"
|
||||
@ -346,18 +336,18 @@ msgid "Typing from another device"
|
||||
msgstr "يكتب عبر جهاز آخَر"
|
||||
|
||||
#: dist/converse-no-dependencies.js:47653
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s is typing"
|
||||
msgstr "يكتب حاليا"
|
||||
msgstr "%1$s يكتب حاليا"
|
||||
|
||||
#: dist/converse-no-dependencies.js:47657
|
||||
msgid "Stopped typing on the other device"
|
||||
msgstr "توقّف عن الكتابة عبر الجهاز الآخَر"
|
||||
|
||||
#: dist/converse-no-dependencies.js:47659
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s has stopped typing"
|
||||
msgstr "توقّفَ عن الكتابة"
|
||||
msgstr "%1$s توقّفَ عن الكتابة"
|
||||
|
||||
#: dist/converse-no-dependencies.js:47905
|
||||
#: dist/converse-no-dependencies.js:47948
|
||||
@ -373,29 +363,24 @@ msgid "Minimized"
|
||||
msgstr "تصغير"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48597
|
||||
#, fuzzy
|
||||
msgid "This groupchat is not anonymous"
|
||||
msgstr "غرفة المحادثة هذه ليست مجهولة"
|
||||
msgstr "فريق المحادثة هذا ليس مجهولًا"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48598
|
||||
#, fuzzy
|
||||
msgid "This groupchat now shows unavailable members"
|
||||
msgstr "هذه القاعة لا تقوم بعرض الأعضاء المشغولين"
|
||||
msgstr ""
|
||||
|
||||
#: dist/converse-no-dependencies.js:48599
|
||||
#, fuzzy
|
||||
msgid "This groupchat does not show unavailable members"
|
||||
msgstr "هذه القاعة لا تقوم بعرض الأعضاء المشغولين"
|
||||
msgstr "فريق المحادثة هذا لا يعرض الأعضاء المشغولين"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48600
|
||||
#, fuzzy
|
||||
msgid "The groupchat configuration has changed"
|
||||
msgstr "تم تعديل إعدادات غرفة المحادثة"
|
||||
msgstr "تم تعديل خيارات فريق المحادثة"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48601
|
||||
#, fuzzy
|
||||
msgid "groupchat logging is now enabled"
|
||||
msgstr "الإلتحاق بالغرفة مسموح للجميع الآن"
|
||||
msgstr "الإلتحاق بفريق المحادثة مسموح الآن للجميع"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48602
|
||||
#, fuzzy
|
||||
@ -403,34 +388,28 @@ msgid "groupchat logging is now disabled"
|
||||
msgstr "مُنِع الآن الإلتحاق بغرفة المحادثة"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48603
|
||||
#, fuzzy
|
||||
msgid "This groupchat is now no longer anonymous"
|
||||
msgstr "لم تَعُد غرفة المحادثة مجهولة الآن"
|
||||
msgstr "لم يَعُد فريق المحادثة مجهولا بعد الآن"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48604
|
||||
#, fuzzy
|
||||
msgid "This groupchat is now semi-anonymous"
|
||||
msgstr "أصبحت غرفة المحادثة مجهولة نسبيًا"
|
||||
msgstr "أصبح فريق المحادثة مجهولا نسبيًا"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48605
|
||||
#, fuzzy
|
||||
msgid "This groupchat is now fully-anonymous"
|
||||
msgstr "أصبحت غرفة المحادثة الآن مجهولة تمامًا"
|
||||
msgstr "أصبح فريق المحادثة الآن مجهولا تمامًا"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48606
|
||||
#, fuzzy
|
||||
msgid "A new groupchat has been created"
|
||||
msgstr "تم إنشاء غرفة محادثة جديدة"
|
||||
msgstr "تم إنشاء فريق محادثة جديد"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48609
|
||||
#, fuzzy
|
||||
msgid "You have been banned from this groupchat"
|
||||
msgstr "لقد تم طردُك مِن غرفة المحادثة هذه"
|
||||
msgstr "لقد تم طردُك مِن فريق المحادثة هذا"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48610
|
||||
#, fuzzy
|
||||
msgid "You have been kicked from this groupchat"
|
||||
msgstr "لقد تم طردُك مؤقتًا مِن غرفة المحادثة هذه"
|
||||
msgstr "لقد تم طردُك مؤقتًا مِن فريق المحادثة هذا"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48611
|
||||
msgid ""
|
||||
@ -499,14 +478,12 @@ msgid "Description:"
|
||||
msgstr "التفاصيل :"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48666
|
||||
#, fuzzy
|
||||
msgid "Groupchat Address (JID):"
|
||||
msgstr "عنوان غرفة المحادثة (JID) :"
|
||||
msgstr "عنوان فريق المحادثة (JID) :"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48667
|
||||
#, fuzzy
|
||||
msgid "Participants:"
|
||||
msgstr "المستخدِمون المُقِيمون :"
|
||||
msgstr "المشتركون :"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48668
|
||||
msgid "Features:"
|
||||
@ -543,9 +520,8 @@ msgid "Open"
|
||||
msgstr "مفتوحة"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48675
|
||||
#, fuzzy
|
||||
msgid "Permanent"
|
||||
msgstr "غرفة محادثة دائمة"
|
||||
msgstr "دائم"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48676
|
||||
#: dist/converse-no-dependencies.js:57167
|
||||
@ -570,32 +546,28 @@ msgid "Unmoderated"
|
||||
msgstr "ليست تحت الإشراف"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48715
|
||||
#, fuzzy
|
||||
msgid "Query for Groupchats"
|
||||
msgstr "البحث عن قاعات"
|
||||
msgstr "البحث عن فِرق محادثة"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48716
|
||||
msgid "Server address"
|
||||
msgstr "عنوان الخادوم"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48717
|
||||
#, fuzzy
|
||||
msgid "Show groupchats"
|
||||
msgstr "عرض غُرف المحادثة"
|
||||
msgstr "عرض فِرَق المحادثة"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48718
|
||||
msgid "conference.example.org"
|
||||
msgstr "conference.example.org"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48767
|
||||
#, fuzzy
|
||||
msgid "No groupchats found"
|
||||
msgstr "لم يتم العثور على أية غُرفة محادثة"
|
||||
msgstr "لم يتم العثور على أي فريق محادثة"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48784
|
||||
#, fuzzy
|
||||
msgid "groupchats found:"
|
||||
msgstr "تم العثور على غرف المحادثة :"
|
||||
msgstr "تم العثور على فِرَق المحادثة :"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48836
|
||||
#, fuzzy
|
||||
@ -603,9 +575,8 @@ msgid "Enter a new Groupchat"
|
||||
msgstr "الدخول إلى غرفة محادثة جديدة"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48837
|
||||
#, fuzzy
|
||||
msgid "Groupchat address"
|
||||
msgstr "عنوان غرفة المحادثة"
|
||||
msgstr "عنوان فريق المحادثة"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48838
|
||||
#: dist/converse-no-dependencies.js:55005
|
||||
@ -621,18 +592,18 @@ msgid "Join"
|
||||
msgstr "الإلتحاق بالغرفة"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48884
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "Groupchat info for %1$s"
|
||||
msgstr "إشعار مِن %1$s"
|
||||
msgstr ""
|
||||
|
||||
#: dist/converse-no-dependencies.js:48990
|
||||
msgid "Message"
|
||||
msgstr "رسالة"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49036
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s is no longer a moderator"
|
||||
msgstr "لم يعُد %1$s مِن مُشْرِفي غرفة المحادثة"
|
||||
msgstr "لم يعُد %1$s مِن المُشْرِفين"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49040
|
||||
#, fuzzy, javascript-format
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -7,7 +7,7 @@ msgstr ""
|
||||
"Project-Id-Version: Converse.js 0.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-07-22 11:17+0200\n"
|
||||
"PO-Revision-Date: 2018-07-22 11:50+0200\n"
|
||||
"PO-Revision-Date: 2018-08-02 08:49+0000\n"
|
||||
"Last-Translator: Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>\n"
|
||||
"Language-Team: French <https://hosted.weblate.org/projects/conversejs/"
|
||||
"translations/fr/>\n"
|
||||
@ -16,7 +16,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||
"X-Generator: Weblate 3.1-dev\n"
|
||||
"X-Generator: Weblate 3.1.1\n"
|
||||
"plural_forms: nplurals=2; plural=(n != 1);\n"
|
||||
"lang: fr\n"
|
||||
"Language-Code: fr\n"
|
||||
@ -27,9 +27,8 @@ msgstr ""
|
||||
#: dist/converse-no-dependencies.js:40690
|
||||
#: dist/converse-no-dependencies.js:40775
|
||||
#: dist/converse-no-dependencies.js:53689
|
||||
#, fuzzy
|
||||
msgid "Bookmark this groupchat"
|
||||
msgstr "Marquer ce salon"
|
||||
msgstr "Mettre ce salon en marque-page"
|
||||
|
||||
#: dist/converse-no-dependencies.js:40776
|
||||
msgid "The name for this bookmark:"
|
||||
@ -37,64 +36,60 @@ msgstr "Nom de ce marque-page :"
|
||||
|
||||
#: dist/converse-no-dependencies.js:40777
|
||||
msgid "Would you like this groupchat to be automatically joined upon startup?"
|
||||
msgstr ""
|
||||
msgstr "Voulez-vous que ce salon soit automatiquement rejoint au démarrage ?"
|
||||
|
||||
#: dist/converse-no-dependencies.js:40778
|
||||
msgid "What should your nickname for this groupchat be?"
|
||||
msgstr ""
|
||||
msgstr "Que devrait être votre pseudo sur ce salon ?"
|
||||
|
||||
#: dist/converse-no-dependencies.js:40780
|
||||
#: dist/converse-no-dependencies.js:49483
|
||||
#: dist/converse-no-dependencies.js:52484
|
||||
#: dist/converse-no-dependencies.js:52568
|
||||
msgid "Save"
|
||||
msgstr ""
|
||||
msgstr "Sauvegarder"
|
||||
|
||||
#: dist/converse-no-dependencies.js:40781
|
||||
#: dist/converse-no-dependencies.js:49484
|
||||
#: dist/converse-no-dependencies.js:52564
|
||||
#: dist/converse-no-dependencies.js:58864
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
msgstr "Annuler"
|
||||
|
||||
#: dist/converse-no-dependencies.js:40854
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "Are you sure you want to remove the bookmark \"%1$s\"?"
|
||||
msgstr "Voulez-vous vraiment quitter le salon « %1$s » ?"
|
||||
msgstr "Voulez-vous vraiment supprimer le marque-page « %1$s » ?"
|
||||
|
||||
#: dist/converse-no-dependencies.js:40970
|
||||
#, fuzzy
|
||||
msgid "Sorry, something went wrong while trying to save your bookmark."
|
||||
msgstr ""
|
||||
"Désolé, quelque chose s’est mal passé pendant la sauvegarde de votre profil."
|
||||
"Désolé, quelque chose s’est mal passé pendant la sauvegarde de ce marque-"
|
||||
"page."
|
||||
|
||||
#: dist/converse-no-dependencies.js:41055
|
||||
#: dist/converse-no-dependencies.js:53687
|
||||
msgid "Leave this groupchat"
|
||||
msgstr ""
|
||||
msgstr "Quitter ce salon"
|
||||
|
||||
#: dist/converse-no-dependencies.js:41056
|
||||
#, fuzzy
|
||||
msgid "Remove this bookmark"
|
||||
msgstr "Nom de ce marque-page :"
|
||||
msgstr "Supprimer ce marque-page"
|
||||
|
||||
#: dist/converse-no-dependencies.js:41057
|
||||
#: dist/converse-no-dependencies.js:53688
|
||||
#, fuzzy
|
||||
msgid "Unbookmark this groupchat"
|
||||
msgstr "Marquer ce salon"
|
||||
msgstr "Retirer ce salon des marque-pages"
|
||||
|
||||
#: dist/converse-no-dependencies.js:41058
|
||||
#: dist/converse-no-dependencies.js:48755
|
||||
#: dist/converse-no-dependencies.js:53690
|
||||
#, fuzzy
|
||||
msgid "Show more information on this groupchat"
|
||||
msgstr "Afficher davantage d’informations sur ce salon"
|
||||
|
||||
#: dist/converse-no-dependencies.js:41061
|
||||
#: dist/converse-no-dependencies.js:48754
|
||||
#: dist/converse-no-dependencies.js:53692
|
||||
#, fuzzy
|
||||
msgid "Click to open this groupchat"
|
||||
msgstr "Cliquer pour ouvrir ce salon"
|
||||
|
||||
@ -115,11 +110,11 @@ msgid "Sorry, could not determine upload URL."
|
||||
msgstr "Désolé, impossible de déterminer l’URL d’envoi de fichier."
|
||||
|
||||
#: dist/converse-no-dependencies.js:41573
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid ""
|
||||
"Sorry, could not succesfully upload your file. Your server’s response: \"%1$s"
|
||||
"\""
|
||||
msgstr "Désolé, l’envoi de fichier a échoué."
|
||||
msgstr "Désolé, l’envoi de fichier a échoué. Votre serveur a répondu : « %1$s »"
|
||||
|
||||
#: dist/converse-no-dependencies.js:41575
|
||||
msgid "Sorry, could not succesfully upload your file."
|
||||
@ -140,7 +135,7 @@ msgstr ""
|
||||
|
||||
#: dist/converse-no-dependencies.js:41996
|
||||
msgid "Sorry, an error occurred:"
|
||||
msgstr ""
|
||||
msgstr "Désolé, une erreur s’est produite :"
|
||||
|
||||
#: dist/converse-no-dependencies.js:42538
|
||||
msgid "Close this chat box"
|
||||
@ -280,25 +275,25 @@ msgid "Are you sure you want to clear the messages from this conversation?"
|
||||
msgstr "Voulez-vous vraiment effacer les messages de cette conversation ?"
|
||||
|
||||
#: dist/converse-no-dependencies.js:43413
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s has gone offline"
|
||||
msgstr "s’est déconnecté"
|
||||
msgstr "%1$s s’est déconnecté"
|
||||
|
||||
#: dist/converse-no-dependencies.js:43415
|
||||
#: dist/converse-no-dependencies.js:47662
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s has gone away"
|
||||
msgstr "%1$s a été banni"
|
||||
msgstr "%1$s n’est plus disponible"
|
||||
|
||||
#: dist/converse-no-dependencies.js:43417
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s is busy"
|
||||
msgstr "est occupé"
|
||||
msgstr "%1$s est occupé"
|
||||
|
||||
#: dist/converse-no-dependencies.js:43419
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s is online"
|
||||
msgstr "est en ligne"
|
||||
msgstr "%1$s est en ligne"
|
||||
|
||||
#: dist/converse-no-dependencies.js:44042
|
||||
msgid "Username"
|
||||
@ -354,21 +349,21 @@ msgstr "Afficher plus"
|
||||
|
||||
#: dist/converse-no-dependencies.js:47651
|
||||
msgid "Typing from another device"
|
||||
msgstr ""
|
||||
msgstr "En train d’écrire depuis un autre client"
|
||||
|
||||
#: dist/converse-no-dependencies.js:47653
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s is typing"
|
||||
msgstr "%1$s dit"
|
||||
msgstr "%1$s est en train d’écrire"
|
||||
|
||||
#: dist/converse-no-dependencies.js:47657
|
||||
msgid "Stopped typing on the other device"
|
||||
msgstr ""
|
||||
msgstr "A arrêté d’écrire sur l’autre client"
|
||||
|
||||
#: dist/converse-no-dependencies.js:47659
|
||||
#, javascript-format
|
||||
msgid "%1$s has stopped typing"
|
||||
msgstr ""
|
||||
msgstr "%1$s a arrêté d’écrire"
|
||||
|
||||
#: dist/converse-no-dependencies.js:47905
|
||||
#: dist/converse-no-dependencies.js:47948
|
||||
@ -384,73 +379,59 @@ msgid "Minimized"
|
||||
msgstr "Réduit(s)"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48597
|
||||
#, fuzzy
|
||||
msgid "This groupchat is not anonymous"
|
||||
msgstr "Ce salon n’est pas anonyme"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48598
|
||||
#, fuzzy
|
||||
msgid "This groupchat now shows unavailable members"
|
||||
msgstr "Ce salon affiche maintenant les membres indisponibles"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48599
|
||||
#, fuzzy
|
||||
msgid "This groupchat does not show unavailable members"
|
||||
msgstr "Ce salon n’affiche pas les membres indisponibles"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48600
|
||||
#, fuzzy
|
||||
msgid "The groupchat configuration has changed"
|
||||
msgstr "Les paramètres de ce salon ont été modifiés"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48601
|
||||
#, fuzzy
|
||||
msgid "groupchat logging is now enabled"
|
||||
msgstr "Le logging du salon est activé"
|
||||
msgstr "L’enregistrement des logs de ce salon est maintenant activé"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48602
|
||||
#, fuzzy
|
||||
msgid "groupchat logging is now disabled"
|
||||
msgstr "Le logging du salon est désactivé"
|
||||
msgstr "L’enregistrement des logs de ce salon est maintenant désactivé"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48603
|
||||
#, fuzzy
|
||||
msgid "This groupchat is now no longer anonymous"
|
||||
msgstr "Ce salon n’est plus anonyme"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48604
|
||||
#, fuzzy
|
||||
msgid "This groupchat is now semi-anonymous"
|
||||
msgstr "Ce salon est maintenant semi-anonyme"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48605
|
||||
#, fuzzy
|
||||
msgid "This groupchat is now fully-anonymous"
|
||||
msgstr "Ce salon est maintenant entièrement anonyme"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48606
|
||||
#, fuzzy
|
||||
msgid "A new groupchat has been created"
|
||||
msgstr "Un nouveau salon a été créé"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48609
|
||||
#, fuzzy
|
||||
msgid "You have been banned from this groupchat"
|
||||
msgstr "Vous avez été banni de ce salon"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48610
|
||||
#, fuzzy
|
||||
msgid "You have been kicked from this groupchat"
|
||||
msgstr "Vous avez été expulsé de ce salon"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48611
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"You have been removed from this groupchat because of an affiliation change"
|
||||
msgstr "Vous avez été retiré de ce salon du fait d’un changement d’affiliation"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48612
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"You have been removed from this groupchat because the groupchat has changed "
|
||||
"to members-only and you're not a member"
|
||||
@ -459,13 +440,12 @@ msgstr ""
|
||||
"membres et vous n’êtes pas membre"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48613
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"You have been removed from this groupchat because the MUC (Multi-user chat) "
|
||||
"service is being shut down"
|
||||
msgstr ""
|
||||
"Vous avez été retiré de ce salon parce que le service de chat multi-"
|
||||
"utilisateur (MUC) est en cours d’extinction"
|
||||
"Vous avez été retiré de ce salon parce que le service sur lequel il est "
|
||||
"hébergé est en cours d’extinction"
|
||||
|
||||
#. XXX: Note the triple underscore function and not double
|
||||
#. * underscore.
|
||||
@ -517,12 +497,10 @@ msgid "Description:"
|
||||
msgstr "Description :"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48666
|
||||
#, fuzzy
|
||||
msgid "Groupchat Address (JID):"
|
||||
msgstr "Adresse du salon (JID) :"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48667
|
||||
#, fuzzy
|
||||
msgid "Participants:"
|
||||
msgstr "Participants :"
|
||||
|
||||
@ -561,9 +539,8 @@ msgid "Open"
|
||||
msgstr "Ouvert"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48675
|
||||
#, fuzzy
|
||||
msgid "Permanent"
|
||||
msgstr "Salon permanent"
|
||||
msgstr "Permanent"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48676
|
||||
#: dist/converse-no-dependencies.js:57167
|
||||
@ -588,7 +565,6 @@ msgid "Unmoderated"
|
||||
msgstr "Non modéré"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48715
|
||||
#, fuzzy
|
||||
msgid "Query for Groupchats"
|
||||
msgstr "Chercher un salon"
|
||||
|
||||
@ -597,7 +573,6 @@ msgid "Server address"
|
||||
msgstr "Adresse du serveur"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48717
|
||||
#, fuzzy
|
||||
msgid "Show groupchats"
|
||||
msgstr "Afficher les salons"
|
||||
|
||||
@ -606,22 +581,18 @@ msgid "conference.example.org"
|
||||
msgstr "chat.exemple.org"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48767
|
||||
#, fuzzy
|
||||
msgid "No groupchats found"
|
||||
msgstr "Aucun salon trouvé"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48784
|
||||
#, fuzzy
|
||||
msgid "groupchats found:"
|
||||
msgstr "Salons trouvés :"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48836
|
||||
#, fuzzy
|
||||
msgid "Enter a new Groupchat"
|
||||
msgstr "Entrer dans un nouveau salon"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48837
|
||||
#, fuzzy
|
||||
msgid "Groupchat address"
|
||||
msgstr "Adresse du salon"
|
||||
|
||||
@ -639,9 +610,9 @@ msgid "Join"
|
||||
msgstr "Rejoindre"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48884
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "Groupchat info for %1$s"
|
||||
msgstr "Notification depuis %1$s"
|
||||
msgstr "Informations sur le salon %1$s"
|
||||
|
||||
#: dist/converse-no-dependencies.js:48990
|
||||
msgid "Message"
|
||||
@ -668,22 +639,18 @@ msgid "%1$s is now a moderator"
|
||||
msgstr "%1$s est désormais un modérateur"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49056
|
||||
#, fuzzy
|
||||
msgid "Close and leave this groupchat"
|
||||
msgstr "Fermer et quitter ce salon"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49057
|
||||
#, fuzzy
|
||||
msgid "Configure this groupchat"
|
||||
msgstr "Configurer ce salon"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49058
|
||||
#, fuzzy
|
||||
msgid "Show more details about this groupchat"
|
||||
msgstr "Afficher davantage d’informations sur ce salon"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49098
|
||||
#, fuzzy
|
||||
msgid "Hide the list of participants"
|
||||
msgstr "Cacher la liste des participants"
|
||||
|
||||
@ -710,7 +677,6 @@ msgid "Change user's affiliation to admin"
|
||||
msgstr "Changer le rôle de l’utilisateur en administrateur"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49282
|
||||
#, fuzzy
|
||||
msgid "Ban user from groupchat"
|
||||
msgstr "Bannir l’utilisateur du salon"
|
||||
|
||||
@ -719,7 +685,6 @@ msgid "Change user role to participant"
|
||||
msgstr "Changer le rôle de l’utilisateur en participant"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49282
|
||||
#, fuzzy
|
||||
msgid "Kick user from groupchat"
|
||||
msgstr "Expulser l’utilisateur du salon"
|
||||
|
||||
@ -744,7 +709,6 @@ msgid "Grant moderator role to user"
|
||||
msgstr "Changer le rôle de l’utilisateur en modérateur"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49282
|
||||
#, fuzzy
|
||||
msgid "Grant ownership of this groupchat"
|
||||
msgstr "Accorder la propriété à ce salon"
|
||||
|
||||
@ -753,14 +717,12 @@ msgid "Revoke user's membership"
|
||||
msgstr "Révoquer l’utilisateur des membres"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49282
|
||||
#, fuzzy
|
||||
msgid "Set groupchat subject"
|
||||
msgstr "Indiquer le sujet du salon"
|
||||
msgstr "Définir le sujet du salon"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49282
|
||||
#, fuzzy
|
||||
msgid "Set groupchat subject (alias for /subject)"
|
||||
msgstr "Définir le sujet de la salle (alias pour /subject)"
|
||||
msgstr "Définir le sujet du salon (alias pour /subject)"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49282
|
||||
msgid "Allow muted user to post messages"
|
||||
@ -779,12 +741,10 @@ msgid "Please choose your nickname"
|
||||
msgstr "Veuillez choisir votre alias"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49640
|
||||
#, fuzzy
|
||||
msgid "Enter groupchat"
|
||||
msgstr "Entrer dans le salon"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49661
|
||||
#, fuzzy
|
||||
msgid "This groupchat requires a password"
|
||||
msgstr "Ce salon nécessite un mot de passe"
|
||||
|
||||
@ -808,47 +768,45 @@ msgid "The reason given is: \"%1$s\"."
|
||||
msgstr "La raison indiquée est : « %1$s »."
|
||||
|
||||
#: dist/converse-no-dependencies.js:49828
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s has left and re-entered the groupchat"
|
||||
msgstr "%1$s a quitté puis rejoint le salon"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49834
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s has entered the groupchat"
|
||||
msgstr "%1$s a rejoint le salon"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49836
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s has entered the groupchat. \"%2$s\""
|
||||
msgstr "%1$s a rejoint le salon. « %2$s »"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49867
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s has entered and left the groupchat"
|
||||
msgstr "%1$s a rejoint puis quitté le salon"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49869
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s has entered and left the groupchat. \"%2$s\""
|
||||
msgstr "%1$s a rejoint puis quitté le salon. « %2$s »"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49882
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s has left the groupchat"
|
||||
msgstr "%1$s a quitté le salon"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49884
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s has left the groupchat. \"%2$s\""
|
||||
msgstr "%1$s a quitté le salon. « %2$s »"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49930
|
||||
#, fuzzy
|
||||
msgid "You are not on the member list of this groupchat."
|
||||
msgstr "Vous n’êtes pas dans la liste des membres de ce salon."
|
||||
|
||||
#: dist/converse-no-dependencies.js:49932
|
||||
#, fuzzy
|
||||
msgid "You have been banned from this groupchat."
|
||||
msgstr "Vous avez été banni de ce salon."
|
||||
|
||||
@ -857,31 +815,27 @@ msgid "No nickname was specified."
|
||||
msgstr "Aucun alias n’a été indiqué."
|
||||
|
||||
#: dist/converse-no-dependencies.js:49940
|
||||
#, fuzzy
|
||||
msgid "You are not allowed to create new groupchats."
|
||||
msgstr "Vous n’êtes pas autorisé à créer des salons."
|
||||
|
||||
#: dist/converse-no-dependencies.js:49942
|
||||
#, fuzzy
|
||||
msgid "Your nickname doesn't conform to this groupchat's policies."
|
||||
msgstr "Votre alias n’est pas conforme à la politique de ce salon."
|
||||
msgstr "Votre pseudo n’est pas conforme à la politique de ce salon."
|
||||
|
||||
#: dist/converse-no-dependencies.js:49946
|
||||
#, fuzzy
|
||||
msgid "This groupchat does not (yet) exist."
|
||||
msgstr "Ce salon n’existe pas (pour l’instant)."
|
||||
|
||||
#: dist/converse-no-dependencies.js:49948
|
||||
#, fuzzy
|
||||
msgid "This groupchat has reached its maximum number of participants."
|
||||
msgstr "Ce salon a atteint sa limite maximale d’occupants."
|
||||
|
||||
#: dist/converse-no-dependencies.js:49950
|
||||
msgid "Remote server not found"
|
||||
msgstr ""
|
||||
msgstr "Serveur distant introuvable"
|
||||
|
||||
#: dist/converse-no-dependencies.js:49955
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "The explanation given is: \"%1$s\"."
|
||||
msgstr "La raison indiquée est : « %1$s »."
|
||||
|
||||
@ -891,17 +845,14 @@ msgid "Topic set by %1$s"
|
||||
msgstr "Le sujet a été défini par %1$s"
|
||||
|
||||
#: dist/converse-no-dependencies.js:50031
|
||||
#, fuzzy
|
||||
msgid "Groupchats"
|
||||
msgstr "Groupes"
|
||||
msgstr "Salons"
|
||||
|
||||
#: dist/converse-no-dependencies.js:50032
|
||||
#, fuzzy
|
||||
msgid "Add a new groupchat"
|
||||
msgstr "Ajouter un nouveau salon"
|
||||
|
||||
#: dist/converse-no-dependencies.js:50033
|
||||
#, fuzzy
|
||||
msgid "Query for groupchats"
|
||||
msgstr "Chercher un salon"
|
||||
|
||||
@ -915,12 +866,10 @@ msgid "This user is a moderator."
|
||||
msgstr "Cet utilisateur est un modérateur."
|
||||
|
||||
#: dist/converse-no-dependencies.js:50073
|
||||
#, fuzzy
|
||||
msgid "This user can send messages in this groupchat."
|
||||
msgstr "Cet utilisateur peut envoyer des messages dans ce salon."
|
||||
|
||||
#: dist/converse-no-dependencies.js:50074
|
||||
#, fuzzy
|
||||
msgid "This user can NOT send messages in this groupchat."
|
||||
msgstr "Cet utilisateur ne peut PAS envoyer de messages dans ce salon."
|
||||
|
||||
@ -946,7 +895,7 @@ msgstr "Administrateur"
|
||||
|
||||
#: dist/converse-no-dependencies.js:50121
|
||||
msgid "Participants"
|
||||
msgstr ""
|
||||
msgstr "Participants"
|
||||
|
||||
#: dist/converse-no-dependencies.js:50138
|
||||
#: dist/converse-no-dependencies.js:50219
|
||||
@ -954,31 +903,31 @@ msgid "Invite"
|
||||
msgstr "Inviter"
|
||||
|
||||
#: dist/converse-no-dependencies.js:50196
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid ""
|
||||
"You are about to invite %1$s to the groupchat \"%2$s\". You may optionally "
|
||||
"include a message, explaining the reason for the invitation."
|
||||
msgstr ""
|
||||
"Vous allez inviter %1$s dans le salon %2$s. Vous pouvez facultativement "
|
||||
"ajouter un message, expliquant la raison de cette invitation."
|
||||
"ajouter un message expliquant la raison de cette invitation."
|
||||
|
||||
#: dist/converse-no-dependencies.js:50218
|
||||
msgid "Please enter a valid XMPP username"
|
||||
msgstr "Veuillez saisir un identifiant utilisateur XMPP valide"
|
||||
|
||||
#: dist/converse-no-dependencies.js:51591
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "%1$s has invited you to join a groupchat: %2$s"
|
||||
msgstr "%1$s vous invite à rejoindre le salon : %2$s"
|
||||
|
||||
#: dist/converse-no-dependencies.js:51593
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid ""
|
||||
"%1$s has invited you to join a groupchat: %2$s, and left the following "
|
||||
"reason: \"%3$s\""
|
||||
msgstr ""
|
||||
"%1$s vous invite à rejoindre le salon : %2$s, avec le message suivant: "
|
||||
"« %3$s »"
|
||||
"%1$s vous invite à rejoindre le salon : %2$s, avec le message suivant: « %3$"
|
||||
"s »"
|
||||
|
||||
#. workaround for Prosody which doesn't give type "headline"
|
||||
#: dist/converse-no-dependencies.js:51974
|
||||
@ -999,9 +948,8 @@ msgid "has gone offline"
|
||||
msgstr "s’est déconnecté"
|
||||
|
||||
#: dist/converse-no-dependencies.js:52026
|
||||
#, fuzzy
|
||||
msgid "has gone away"
|
||||
msgstr "s’est déconnecté"
|
||||
msgstr "est absent"
|
||||
|
||||
#: dist/converse-no-dependencies.js:52028
|
||||
msgid "is busy"
|
||||
@ -1018,7 +966,7 @@ msgstr "veut être votre contact"
|
||||
#: dist/converse-no-dependencies.js:52229
|
||||
#, javascript-format
|
||||
msgid "Log in with %1$s"
|
||||
msgstr ""
|
||||
msgstr "Se connecter avec %1$s"
|
||||
|
||||
#: dist/converse-no-dependencies.js:52476
|
||||
msgid "Your Profile"
|
||||
@ -1187,16 +1135,15 @@ msgstr ""
|
||||
"les données que vous avez fournies sont correctes."
|
||||
|
||||
#: dist/converse-no-dependencies.js:53748
|
||||
#, fuzzy
|
||||
msgid "Click to toggle the list of open groupchats"
|
||||
msgstr "Cliquer pour ouvrir la liste des salons"
|
||||
msgstr "Cliquer pour ouvrir la liste des salons ouverts"
|
||||
|
||||
#: dist/converse-no-dependencies.js:53749
|
||||
msgid "Open Groupchats"
|
||||
msgstr ""
|
||||
msgstr "Ouvrir les salons"
|
||||
|
||||
#: dist/converse-no-dependencies.js:53793
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "Are you sure you want to leave the groupchat %1$s?"
|
||||
msgstr "Voulez-vous vraiment quitter le salon « %1$s » ?"
|
||||
|
||||
@ -1345,32 +1292,28 @@ msgid "Add a contact"
|
||||
msgstr "Ajouter un contact"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57111
|
||||
#, fuzzy
|
||||
msgid "Name"
|
||||
msgstr "Nom complet"
|
||||
msgstr "Nom"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57115
|
||||
#, fuzzy
|
||||
msgid "Groupchat address (JID)"
|
||||
msgstr "Adresse du salon (JID) :"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57119
|
||||
#, fuzzy
|
||||
msgid "Description"
|
||||
msgstr "Description :"
|
||||
msgstr "Description"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57125
|
||||
msgid "Topic"
|
||||
msgstr ""
|
||||
msgstr "Sujet"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57129
|
||||
msgid "Topic author"
|
||||
msgstr ""
|
||||
msgstr "Auteur du sujet"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57135
|
||||
#, fuzzy
|
||||
msgid "Online users"
|
||||
msgstr "En ligne"
|
||||
msgstr "Utilisateurs en ligne"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57139
|
||||
#: dist/converse-no-dependencies.js:57291
|
||||
@ -1384,30 +1327,25 @@ msgstr "Protégé par mot de passe"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57145
|
||||
#: dist/converse-no-dependencies.js:57297
|
||||
#, fuzzy
|
||||
msgid "This groupchat requires a password before entry"
|
||||
msgstr "Ce salon nécessite un mot de passe pour y accéder"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57151
|
||||
#, fuzzy
|
||||
msgid "No password required"
|
||||
msgstr "Pas de mot de passe"
|
||||
msgstr "Pas de mot de passe nécessaire"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57153
|
||||
#: dist/converse-no-dependencies.js:57305
|
||||
#, fuzzy
|
||||
msgid "This groupchat does not require a password upon entry"
|
||||
msgstr "Ce salon ne nécessite pas de mot de passe pour y accéder"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57161
|
||||
#: dist/converse-no-dependencies.js:57313
|
||||
#, fuzzy
|
||||
msgid "This groupchat is not publicly searchable"
|
||||
msgstr "Ce salon ne peut pas être recherché publiquement"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57169
|
||||
#: dist/converse-no-dependencies.js:57321
|
||||
#, fuzzy
|
||||
msgid "This groupchat is publicly searchable"
|
||||
msgstr "Ce salon peut être recherché publiquement"
|
||||
|
||||
@ -1417,13 +1355,11 @@ msgid "Members only"
|
||||
msgstr "Membres uniquement"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57177
|
||||
#, fuzzy
|
||||
msgid "This groupchat is restricted to members only"
|
||||
msgstr "Ce salon est restreint aux membres uniquement"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57185
|
||||
#: dist/converse-no-dependencies.js:57337
|
||||
#, fuzzy
|
||||
msgid "Anyone can join this groupchat"
|
||||
msgstr "N’importe qui peut rejoindre ce salon"
|
||||
|
||||
@ -1434,25 +1370,21 @@ msgstr "Persistant"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57193
|
||||
#: dist/converse-no-dependencies.js:57345
|
||||
#, fuzzy
|
||||
msgid "This groupchat persists even if it's unoccupied"
|
||||
msgstr "Ce salon persiste même s'il est inoccupé"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57201
|
||||
#: dist/converse-no-dependencies.js:57353
|
||||
#, fuzzy
|
||||
msgid "This groupchat will disappear once the last person leaves"
|
||||
msgstr "Ce salon disparaîtra au départ de la dernière personne"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57207
|
||||
#: dist/converse-no-dependencies.js:57363
|
||||
#, fuzzy
|
||||
msgid "Not anonymous"
|
||||
msgstr "Non-anonyme"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57209
|
||||
#: dist/converse-no-dependencies.js:57361
|
||||
#, fuzzy
|
||||
msgid "All other groupchat participants can see your XMPP username"
|
||||
msgstr ""
|
||||
"Tous les autres occupants de ce salon peuvent voir votre nom d’utilisateur "
|
||||
@ -1465,19 +1397,16 @@ msgstr "Seuls les modérateurs peuvent voir votre identifiant XMPP"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57225
|
||||
#: dist/converse-no-dependencies.js:57377
|
||||
#, fuzzy
|
||||
msgid "This groupchat is being moderated"
|
||||
msgstr "Ce salon est modéré"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57231
|
||||
#: dist/converse-no-dependencies.js:57387
|
||||
#, fuzzy
|
||||
msgid "Not moderated"
|
||||
msgstr "Non modéré"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57233
|
||||
#: dist/converse-no-dependencies.js:57385
|
||||
#, fuzzy
|
||||
msgid "This groupchat is not being moderated"
|
||||
msgstr "Ce salon n’est pas modéré"
|
||||
|
||||
@ -1496,9 +1425,8 @@ msgid "No password"
|
||||
msgstr "Pas de mot de passe"
|
||||
|
||||
#: dist/converse-no-dependencies.js:57329
|
||||
#, fuzzy
|
||||
msgid "this groupchat is restricted to members only"
|
||||
msgstr "Ce salon est restreint aux membres uniquement"
|
||||
msgstr "ce salon est restreint aux membres uniquement"
|
||||
|
||||
#: dist/converse-no-dependencies.js:58267
|
||||
msgid "XMPP Username:"
|
||||
@ -1514,7 +1442,7 @@ msgstr "Mot de passe"
|
||||
|
||||
#: dist/converse-no-dependencies.js:58283
|
||||
msgid "This is a trusted device"
|
||||
msgstr ""
|
||||
msgstr "Ceci est un appareil de confiance"
|
||||
|
||||
#: dist/converse-no-dependencies.js:58285
|
||||
msgid ""
|
||||
@ -1523,9 +1451,13 @@ msgid ""
|
||||
"log out. It's important that you explicitly log out, otherwise not all "
|
||||
"cached data might be deleted."
|
||||
msgstr ""
|
||||
"Pour améliorer les performances, nous stockons vos données dans ce "
|
||||
"navigateur. Décochez ce bouton si vous êtes sur un ordinateur public, ou si "
|
||||
"vous voulez que vos données soient supprimées lorsque vous vous "
|
||||
"déconnecterez. Il est important que vous vous déconnectiez explicitement, "
|
||||
"sinon toutes les données stockées ne seront pas forcément supprimées."
|
||||
|
||||
#: dist/converse-no-dependencies.js:58287
|
||||
#, fuzzy
|
||||
msgid "Log in"
|
||||
msgstr "Se connecter"
|
||||
|
||||
@ -1534,19 +1466,16 @@ msgid "Click here to log in anonymously"
|
||||
msgstr "Cliquez ici pour se connecter anonymement"
|
||||
|
||||
#: dist/converse-no-dependencies.js:58376
|
||||
#, fuzzy
|
||||
msgid "This message has been edited"
|
||||
msgstr "Ce salon est modéré"
|
||||
msgstr "Ce message a été édité"
|
||||
|
||||
#: dist/converse-no-dependencies.js:58402
|
||||
#, fuzzy
|
||||
msgid "Edit this message"
|
||||
msgstr "Cacher le message caché"
|
||||
msgstr "Éditer ce message"
|
||||
|
||||
#: dist/converse-no-dependencies.js:58427
|
||||
#, fuzzy
|
||||
msgid "Message versions"
|
||||
msgstr "Archivage des messages"
|
||||
msgstr "Versions du message"
|
||||
|
||||
#: dist/converse-no-dependencies.js:58759
|
||||
msgid "Don't have a chat account?"
|
||||
@ -1594,9 +1523,9 @@ msgid "Download"
|
||||
msgstr "Télécharger"
|
||||
|
||||
#: dist/converse-no-dependencies.js:59996
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "Download \"%1$s\""
|
||||
msgstr "Télécharger : \"%1$s\""
|
||||
msgstr "Télécharger « %1$s »"
|
||||
|
||||
#: dist/converse-no-dependencies.js:60019
|
||||
msgid "Download video file"
|
||||
|
6
package-lock.json
generated
6
package-lock.json
generated
@ -2410,9 +2410,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"bootstrap.native": {
|
||||
"version": "2.0.22",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap.native/-/bootstrap.native-2.0.22.tgz",
|
||||
"integrity": "sha512-eypi4y1eKJoRt8cTwkZCI3QQ7W04rbv4VU1nBjBshqNXkONI7jO6tG3qZTwq9Zd+gDoeaQASyk6V185y+Y7KHQ==",
|
||||
"version": "2.0.23",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap.native/-/bootstrap.native-2.0.23.tgz",
|
||||
"integrity": "sha512-bcbVgqIjRkyiHd6DN8Y18BYjJTKvvnN3Msb7Yh6K5vGGsjRT3gV0IFKR3rcEYgJ5Kvg1egL9exIfN/Hvwn4wNA==",
|
||||
"dev": true
|
||||
},
|
||||
"bourbon": {
|
||||
|
@ -44,7 +44,7 @@
|
||||
"backbone.overview": "1.0.2",
|
||||
"backbone.vdomview": "1.0.1",
|
||||
"bootstrap": "^4.0.0",
|
||||
"bootstrap.native": "^2.0.22",
|
||||
"bootstrap.native": "^2.0.23",
|
||||
"bourbon": "^4.3.2",
|
||||
"bytebuffer": "^3.5.5",
|
||||
"clean-css-cli": "^4.0.10",
|
||||
|
@ -1 +1 @@
|
||||
zc.buildout==2.11.4
|
||||
zc.buildout==2.12.1
|
||||
|
@ -34,24 +34,24 @@
|
||||
});
|
||||
spyOn(_converse.connection, 'getUniqueId').and.callThrough();
|
||||
|
||||
test_utils.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC');
|
||||
let view;
|
||||
test_utils.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC')
|
||||
.then(() => {
|
||||
var jid = 'theplay@conference.shakespeare.lit';
|
||||
var view = _converse.chatboxviews.get(jid);
|
||||
view = _converse.chatboxviews.get(jid);
|
||||
spyOn(view, 'renderBookmarkForm').and.callThrough();
|
||||
spyOn(view, 'closeForm').and.callThrough();
|
||||
|
||||
test_utils.waitUntil(function () {
|
||||
return !_.isNull(view.el.querySelector('.toggle-bookmark'));
|
||||
}, 300).then(function () {
|
||||
var $bookmark = $(view.el).find('.toggle-bookmark');
|
||||
$bookmark[0].click();
|
||||
return test_utils.waitUntil(() => !_.isNull(view.el.querySelector('.toggle-bookmark')));
|
||||
}).then(() => {
|
||||
var bookmark = view.el.querySelector('.toggle-bookmark');
|
||||
bookmark.click();
|
||||
expect(view.renderBookmarkForm).toHaveBeenCalled();
|
||||
|
||||
view.el.querySelector('.button-cancel').click();
|
||||
expect(view.closeForm).toHaveBeenCalled();
|
||||
expect($bookmark.hasClass('on-button'), false);
|
||||
expect(u.hasClass('on-button', bookmark), false);
|
||||
|
||||
$bookmark[0].click();
|
||||
bookmark.click();
|
||||
expect(view.renderBookmarkForm).toHaveBeenCalled();
|
||||
|
||||
/* Client uploads data:
|
||||
@ -93,7 +93,7 @@
|
||||
view.el.querySelector('.btn-primary').click();
|
||||
|
||||
expect(view.model.get('bookmarked')).toBeTruthy();
|
||||
expect($bookmark.hasClass('on-button'), true);
|
||||
expect(u.hasClass('on-button', bookmark), true);
|
||||
|
||||
expect(sent_stanza.toLocaleString()).toBe(
|
||||
"<iq type='set' from='dummy@localhost/resource' xmlns='jabber:client' id='"+IQ_id+"'>"+
|
||||
@ -175,17 +175,16 @@
|
||||
it("displays that it's bookmarked through its bookmark icon", mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {}, function (done, _converse) {
|
||||
|
||||
let view;
|
||||
test_utils.waitUntilDiscoConfirmed(
|
||||
_converse, _converse.bare_jid,
|
||||
[{'category': 'pubsub', 'type': 'pep'}],
|
||||
['http://jabber.org/protocol/pubsub#publish-options']
|
||||
).then(function () {
|
||||
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy');
|
||||
var view = _converse.chatboxviews.get('lounge@localhost');
|
||||
|
||||
test_utils.waitUntil(function () {
|
||||
return !_.isNull(view.el.querySelector('.toggle-bookmark'));
|
||||
}, 300).then(function () {
|
||||
).then(() => test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy'))
|
||||
.then(() => {
|
||||
view = _converse.chatboxviews.get('lounge@localhost');
|
||||
return test_utils.waitUntil(() => !_.isNull(view.el.querySelector('.toggle-bookmark')))
|
||||
}).then(function () {
|
||||
var bookmark_icon = view.el.querySelector('.toggle-bookmark');
|
||||
expect(_.includes(bookmark_icon.classList, 'button-on')).toBeFalsy();
|
||||
view.model.set('bookmarked', true);
|
||||
@ -194,27 +193,25 @@
|
||||
expect(_.includes(bookmark_icon.classList, 'button-on')).toBeFalsy();
|
||||
done();
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
it("can be unbookmarked", mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {}, function (done, _converse) {
|
||||
|
||||
let sent_stanza, IQ_id, view, sendIQ;
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(
|
||||
_converse, _converse.bare_jid,
|
||||
[{'category': 'pubsub', 'type': 'pep'}],
|
||||
['http://jabber.org/protocol/pubsub#publish-options']
|
||||
).then(function () {
|
||||
var sent_stanza, IQ_id;
|
||||
var sendIQ = _converse.connection.sendIQ;
|
||||
|
||||
test_utils.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC');
|
||||
).then(() => {
|
||||
sendIQ = _converse.connection.sendIQ;
|
||||
return test_utils.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC');
|
||||
}).then(() => {
|
||||
var jid = 'theplay@conference.shakespeare.lit';
|
||||
var view = _converse.chatboxviews.get(jid);
|
||||
|
||||
test_utils.waitUntil(function () {
|
||||
return !_.isNull(view.el.querySelector('.toggle-bookmark'));
|
||||
}, 300).then(function () {
|
||||
view = _converse.chatboxviews.get(jid);
|
||||
return test_utils.waitUntil(() => !_.isNull(view.el.querySelector('.toggle-bookmark')));
|
||||
}).then(function () {
|
||||
spyOn(view, 'toggleBookmark').and.callThrough();
|
||||
spyOn(_converse.bookmarks, 'sendBookmarkStanza').and.callThrough();
|
||||
view.delegateEvents();
|
||||
@ -227,17 +224,17 @@
|
||||
});
|
||||
expect(_converse.bookmarks.length).toBe(1);
|
||||
expect(view.model.get('bookmarked')).toBeTruthy();
|
||||
var $bookmark_icon = $(view.el.querySelector('.toggle-bookmark'));
|
||||
expect($bookmark_icon.hasClass('button-on')).toBeTruthy();
|
||||
var bookmark_icon = view.el.querySelector('.toggle-bookmark');
|
||||
expect(u.hasClass('button-on', bookmark_icon)).toBeTruthy();
|
||||
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
|
||||
sent_stanza = iq;
|
||||
IQ_id = sendIQ.bind(this)(iq, callback, errback);
|
||||
});
|
||||
spyOn(_converse.connection, 'getUniqueId').and.callThrough();
|
||||
$bookmark_icon[0].click();
|
||||
bookmark_icon.click();
|
||||
expect(view.toggleBookmark).toHaveBeenCalled();
|
||||
expect($bookmark_icon.hasClass('button-on')).toBeFalsy();
|
||||
expect(u.hasClass('button-on', bookmark_icon)).toBeFalsy();
|
||||
expect(_converse.bookmarks.length).toBe(0);
|
||||
|
||||
// Check that an IQ stanza is sent out, containing no
|
||||
@ -269,7 +266,6 @@
|
||||
);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
@ -587,9 +583,8 @@
|
||||
'name': 'The Play',
|
||||
'nick': ''
|
||||
});
|
||||
test_utils.waitUntil(function () {
|
||||
return $('#chatrooms .bookmarks.rooms-list .room-item:visible').length;
|
||||
}, 300).then(function () {
|
||||
test_utils.waitUntil(() => $('#chatrooms .bookmarks.rooms-list .room-item:visible').length
|
||||
).then(function () {
|
||||
expect($('#chatrooms .bookmarks.rooms-list').hasClass('collapsed')).toBeFalsy();
|
||||
expect($('#chatrooms .bookmarks.rooms-list .room-item:visible').length).toBe(1);
|
||||
expect(_converse.bookmarksview.list_model.get('toggle-state')).toBe(_converse.OPENED);
|
||||
@ -614,6 +609,7 @@
|
||||
{ hide_open_bookmarks: true },
|
||||
function (done, _converse) {
|
||||
|
||||
const jid = 'room@conference.example.org';
|
||||
test_utils.waitUntilDiscoConfirmed(
|
||||
_converse, _converse.bare_jid,
|
||||
[{'category': 'pubsub', 'type': 'pep'}],
|
||||
@ -627,14 +623,12 @@
|
||||
_converse.emit('bookmarksInitialized');
|
||||
|
||||
// Check that it's there
|
||||
var jid = 'room@conference.example.org';
|
||||
_converse.bookmarks.create({
|
||||
'jid': jid,
|
||||
'autojoin': false,
|
||||
'name': 'The Play',
|
||||
'nick': ' Othello'
|
||||
});
|
||||
|
||||
expect(_converse.bookmarks.length).toBe(1);
|
||||
var room_els = _converse.bookmarksview.el.querySelectorAll(".open-room");
|
||||
expect(room_els.length).toBe(1);
|
||||
@ -642,9 +636,11 @@
|
||||
// Check that it disappears once the room is opened
|
||||
var bookmark = _converse.bookmarksview.el.querySelector(".open-room");
|
||||
bookmark.click();
|
||||
return test_utils.waitUntil(() => _converse.chatboxviews.get(jid));
|
||||
}).then(() => {
|
||||
expect(u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom"))).toBeTruthy();
|
||||
// Check that it reappears once the room is closed
|
||||
var view = _converse.chatboxviews.get(jid);
|
||||
const view = _converse.chatboxviews.get(jid);
|
||||
view.close();
|
||||
expect(u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom"))).toBeFalsy();
|
||||
done();
|
||||
|
693
spec/chatbox.js
693
spec/chatbox.js
File diff suppressed because it is too large
Load Diff
269
spec/chatroom.js
269
spec/chatroom.js
@ -1,15 +1,16 @@
|
||||
(function (root, factory) {
|
||||
define(["jquery", "jasmine", "mock", "test-utils" ], factory);
|
||||
} (this, function ($, jasmine, mock, test_utils) {
|
||||
var _ = converse.env._;
|
||||
var $pres = converse.env.$pres;
|
||||
var $iq = converse.env.$iq;
|
||||
var $msg = converse.env.$msg;
|
||||
var Strophe = converse.env.Strophe;
|
||||
var Promise = converse.env.Promise;
|
||||
var moment = converse.env.moment;
|
||||
var sizzle = converse.env.sizzle;
|
||||
var u = converse.env.utils;
|
||||
const _ = converse.env._,
|
||||
$pres = converse.env.$pres,
|
||||
$iq = converse.env.$iq,
|
||||
$msg = converse.env.$msg,
|
||||
Strophe = converse.env.Strophe,
|
||||
Promise = converse.env.Promise,
|
||||
moment = converse.env.moment,
|
||||
sizzle = converse.env.sizzle,
|
||||
Backbone = converse.env.Backbone,
|
||||
u = converse.env.utils;
|
||||
|
||||
return describe("ChatRooms", function () {
|
||||
describe("The \"rooms\" API", function () {
|
||||
@ -107,7 +108,7 @@
|
||||
|
||||
it("has a method 'open' which opens (optionally configures) and returns a wrapped chat box",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
// Mock 'getRoomFeatures', otherwise the room won't be
|
||||
@ -119,22 +120,24 @@
|
||||
return deferred.promise();
|
||||
});
|
||||
|
||||
const sent_IQ_els = [];
|
||||
let jid = 'lounge@localhost';
|
||||
let chatroomview, sent_IQ, IQ_id;
|
||||
test_utils.openControlBox();
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
test_utils.waitUntil(function () {
|
||||
return $(_converse.rosterview.el).find('.roster-group .group-toggle').length;
|
||||
}, 300).then(function () {
|
||||
var jid = 'lounge@localhost';
|
||||
var room = _converse.api.rooms.open(jid);
|
||||
test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group .group-toggle').length)
|
||||
.then(() => _converse.api.rooms.open(jid))
|
||||
.then((room) => {
|
||||
// Test on groupchat that's not yet open
|
||||
expect(room instanceof Object).toBeTruthy();
|
||||
var chatroomview = _converse.chatboxviews.get(jid);
|
||||
expect(room instanceof Backbone.Model).toBeTruthy();
|
||||
chatroomview = _converse.chatboxviews.get(jid);
|
||||
expect(chatroomview.is_chatroom).toBeTruthy();
|
||||
expect(u.isVisible(chatroomview.el)).toBeTruthy();
|
||||
|
||||
// Test again, now that the room exists.
|
||||
room = _converse.api.rooms.open(jid);
|
||||
expect(room instanceof Object).toBeTruthy();
|
||||
return _converse.api.rooms.open(jid);
|
||||
}).then((room) => {
|
||||
expect(room instanceof Backbone.Model).toBeTruthy();
|
||||
chatroomview = _converse.chatboxviews.get(jid);
|
||||
expect(chatroomview.is_chatroom).toBeTruthy();
|
||||
expect(u.isVisible(chatroomview.el)).toBeTruthy();
|
||||
@ -142,26 +145,28 @@
|
||||
|
||||
// Test with mixed case in JID
|
||||
jid = 'Leisure@localhost';
|
||||
room = _converse.api.rooms.open(jid);
|
||||
expect(room instanceof Object).toBeTruthy();
|
||||
return _converse.api.rooms.open(jid);
|
||||
}).then((room) => {
|
||||
expect(room instanceof Backbone.Model).toBeTruthy();
|
||||
chatroomview = _converse.chatboxviews.get(jid.toLowerCase());
|
||||
expect(u.isVisible(chatroomview.el)).toBeTruthy();
|
||||
|
||||
jid = 'leisure@localhost';
|
||||
room = _converse.api.rooms.open(jid);
|
||||
expect(room instanceof Object).toBeTruthy();
|
||||
return _converse.api.rooms.open(jid);
|
||||
}).then((room) => {
|
||||
expect(room instanceof Backbone.Model).toBeTruthy();
|
||||
chatroomview = _converse.chatboxviews.get(jid.toLowerCase());
|
||||
expect(u.isVisible(chatroomview.el)).toBeTruthy();
|
||||
|
||||
jid = 'leiSure@localhost';
|
||||
room = _converse.api.rooms.open(jid);
|
||||
expect(room instanceof Object).toBeTruthy();
|
||||
return _converse.api.rooms.open(jid);
|
||||
}).then((room) => {
|
||||
expect(room instanceof Backbone.Model).toBeTruthy();
|
||||
chatroomview = _converse.chatboxviews.get(jid.toLowerCase());
|
||||
expect(u.isVisible(chatroomview.el)).toBeTruthy();
|
||||
chatroomview.close();
|
||||
|
||||
_converse.muc_instant_rooms = false;
|
||||
var sent_IQ, IQ_id, sent_IQ_els = [];
|
||||
var sendIQ = _converse.connection.sendIQ;
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
|
||||
sent_IQ = iq;
|
||||
@ -169,7 +174,7 @@
|
||||
IQ_id = sendIQ.bind(this)(iq, callback, errback);
|
||||
});
|
||||
// Test with configuration
|
||||
_converse.api.rooms.open('room@conference.example.org', {
|
||||
return _converse.api.rooms.open('room@conference.example.org', {
|
||||
'nick': 'some1',
|
||||
'auto_configure': true,
|
||||
'roomconfig': {
|
||||
@ -181,6 +186,7 @@
|
||||
'whois': 'anyone'
|
||||
}
|
||||
});
|
||||
}).then((room) => {
|
||||
chatroomview = _converse.chatboxviews.get('room@conference.example.org');
|
||||
|
||||
// We pretend this is a new room, so no disco info is returned.
|
||||
@ -252,11 +258,8 @@
|
||||
|
||||
spyOn(chatroomview.model, 'sendConfiguration').and.callThrough();
|
||||
_converse.connection._dataRecv(test_utils.createRequest(node.firstElementChild));
|
||||
|
||||
|
||||
return test_utils.waitUntil(function () {
|
||||
return chatroomview.model.sendConfiguration.calls.count() === 1;
|
||||
}, 300).then(function () {
|
||||
return test_utils.waitUntil(() => chatroomview.model.sendConfiguration.calls.count() === 1);
|
||||
}).then(() => {
|
||||
var sent_stanza = sent_IQ_els.pop();
|
||||
while (sent_stanza.getAttribute('type') !== 'set') {
|
||||
sent_stanza = sent_IQ_els.pop();
|
||||
@ -271,7 +274,6 @@
|
||||
expect(sizzle('field[var="muc#roomconfig_historylength"] value', sent_stanza).pop().textContent).toBe('20');
|
||||
done();
|
||||
});
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
@ -279,12 +281,12 @@
|
||||
|
||||
it("will be created when muc_instant_rooms is set to true",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
var IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
var sent_IQ, IQ_id;
|
||||
var sendIQ = _converse.connection.sendIQ;
|
||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
const sendIQ = _converse.connection.sendIQ;
|
||||
let sent_IQ, IQ_id, view;
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
|
||||
if (iq.nodeTree.getAttribute('to') === 'lounge@localhost') {
|
||||
sent_IQ = iq;
|
||||
@ -293,8 +295,8 @@
|
||||
sendIQ.bind(this)(iq, callback, errback);
|
||||
}
|
||||
});
|
||||
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy');
|
||||
|
||||
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy')
|
||||
.then(() => {
|
||||
// We pretend this is a new room, so no disco info is returned.
|
||||
//
|
||||
/* <iq from="jordie.langen@chat.example.org/converse.js-11659299" to="myroom@conference.chat.example.org" type="get">
|
||||
@ -315,7 +317,7 @@
|
||||
.c('item-not-found', {'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas"});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
|
||||
|
||||
var view = _converse.chatboxviews.get('lounge@localhost');
|
||||
view = _converse.chatboxviews.get('lounge@localhost');
|
||||
spyOn(view, 'join').and.callThrough();
|
||||
spyOn(view, 'submitNickname').and.callThrough();
|
||||
|
||||
@ -326,11 +328,8 @@
|
||||
* node="x-roomuser-item"/>
|
||||
* </iq>
|
||||
*/
|
||||
test_utils.waitUntil(function () {
|
||||
return _.filter(IQ_stanzas, function (iq) {
|
||||
return iq.nodeTree.querySelector('query[node="x-roomuser-item"]');
|
||||
}).length > 0;
|
||||
}, 300).then(function () {
|
||||
return test_utils.waitUntil(() => _.filter(IQ_stanzas, (iq) => iq.nodeTree.querySelector('query[node="x-roomuser-item"]')).length);
|
||||
}).then(() => {
|
||||
const iq = _.filter(IQ_stanzas, function (iq) {
|
||||
return iq.nodeTree.querySelector(`query[node="x-roomuser-item"]`);
|
||||
}).pop();
|
||||
@ -411,10 +410,11 @@
|
||||
|
||||
it("shows join/leave messages when users enter or exit a groupchat",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.openChatRoom(_converse, "coven", 'chat.shakespeare.lit', 'some1');
|
||||
test_utils.openChatRoom(_converse, "coven", 'chat.shakespeare.lit', 'some1')
|
||||
.then(() => {
|
||||
var view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
|
||||
var $chat_content = $(view.el).find('.chat-content');
|
||||
|
||||
@ -604,6 +604,7 @@
|
||||
expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(5);
|
||||
expect($chat_content.find('div.chat-info:last').html()).toBe("nomorenicks has entered the groupchat");
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("shows a new day indicator if a join/leave message is received on a new day",
|
||||
@ -774,19 +775,19 @@
|
||||
|
||||
it("shows its description in the chat heading",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
var sent_IQ, IQ_id;
|
||||
var sendIQ = _converse.connection.sendIQ;
|
||||
let sent_IQ, IQ_id, view;
|
||||
const sendIQ = _converse.connection.sendIQ;
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
|
||||
sent_IQ = iq;
|
||||
IQ_id = sendIQ.bind(this)(iq, callback, errback);
|
||||
});
|
||||
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
|
||||
var view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
|
||||
|
||||
var features_stanza = $iq({
|
||||
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'})
|
||||
.then(() => {
|
||||
view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
|
||||
const features_stanza = $iq({
|
||||
from: 'coven@chat.shakespeare.lit',
|
||||
'id': IQ_id,
|
||||
'to': 'dummy@localhost/desktop',
|
||||
@ -814,32 +815,9 @@
|
||||
.c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of participants'})
|
||||
.c('value').t(0);
|
||||
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
|
||||
test_utils.waitUntil(() => _.get(view.el.querySelector('.chatroom-description'), 'textContent'))
|
||||
.then(function () {
|
||||
expect($(view.el.querySelector('.chatroom-description')).text()).toBe('This is the description');
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("will specially mark messages in which you are mentioned",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy').then(function () {
|
||||
var view = _converse.chatboxviews.get('lounge@localhost');
|
||||
if (!$(view.el).find('.chat-area').length) { view.renderChatArea(); }
|
||||
var message = 'dummy: Your attention is required';
|
||||
var nick = mock.chatroom_names[0],
|
||||
msg = $msg({
|
||||
from: 'lounge@localhost/'+nick,
|
||||
id: (new Date()).getTime(),
|
||||
to: 'dummy@localhost',
|
||||
type: 'groupchat'
|
||||
}).c('body').t(message).tree();
|
||||
view.model.onMessage(msg);
|
||||
expect($(view.el).find('.chat-msg').hasClass('mentioned')).toBeTruthy();
|
||||
return test_utils.waitUntil(() => _.get(view.el.querySelector('.chatroom-description'), 'textContent'))
|
||||
}).then(function () {
|
||||
expect(view.el.querySelector('.chatroom-description').textContent).toBe('This is the description');
|
||||
done();
|
||||
});
|
||||
}));
|
||||
@ -886,7 +864,7 @@
|
||||
|
||||
it("can be configured if you're its owner",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
var view;
|
||||
@ -897,7 +875,8 @@
|
||||
IQ_id = sendIQ.bind(this)(iq, callback, errback);
|
||||
});
|
||||
|
||||
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
|
||||
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'})
|
||||
.then(() => {
|
||||
view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
|
||||
|
||||
spyOn(view.model, 'saveAffiliationAndRole').and.callThrough();
|
||||
@ -933,12 +912,9 @@
|
||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
||||
expect(view.model.saveAffiliationAndRole).toHaveBeenCalled();
|
||||
expect($(view.el.querySelector('.toggle-chatbox-button')).is(':visible')).toBeTruthy();
|
||||
|
||||
test_utils.waitUntil(function () {
|
||||
return !_.isNull(view.el.querySelector('.configure-chatroom-button'));
|
||||
}, 300).then(function () {
|
||||
return test_utils.waitUntil(() => !_.isNull(view.el.querySelector('.configure-chatroom-button')))
|
||||
}).then(() => {
|
||||
expect($(view.el.querySelector('.configure-chatroom-button')).is(':visible')).toBeTruthy();
|
||||
|
||||
view.el.querySelector('.configure-chatroom-button').click();
|
||||
|
||||
/* Check that an IQ is sent out, asking for the
|
||||
@ -1074,9 +1050,8 @@
|
||||
.c('value').t('cauldronburn');
|
||||
_converse.connection._dataRecv(test_utils.createRequest(config_stanza));
|
||||
|
||||
test_utils.waitUntil(function () {
|
||||
return $(view.el.querySelector('form.chatroom-form')).length;
|
||||
}, 300).then(function () {
|
||||
return test_utils.waitUntil(() => view.el.querySelectorAll('form.chatroom-form').length)
|
||||
}).then(() => {
|
||||
expect($(view.el.querySelector('form.chatroom-form')).length).toBe(1);
|
||||
expect(view.el.querySelectorAll('form.chatroom-form fieldset').length).toBe(2);
|
||||
var $membersonly = $(view.el.querySelector('input[name="muc#roomconfig_membersonly"]'));
|
||||
@ -1109,7 +1084,6 @@
|
||||
expect($sent_stanza.find('field[var="muc#roomconfig_allowpm"] value').text()).toBe('moderators');
|
||||
expect($sent_stanza.find('field[var="muc#roomconfig_presencebroadcast"] value').text()).toBe('moderator');
|
||||
done();
|
||||
});
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||
}));
|
||||
|
||||
@ -1318,12 +1292,12 @@
|
||||
|
||||
it("will use the user's reserved nickname, if it exists",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
var IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
var sent_IQ, IQ_id;
|
||||
var sendIQ = _converse.connection.sendIQ;
|
||||
let sent_IQ, IQ_id, view;
|
||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
const sendIQ = _converse.connection.sendIQ;
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
|
||||
if (iq.nodeTree.getAttribute('to') === 'lounge@localhost') {
|
||||
sent_IQ = iq;
|
||||
@ -1333,8 +1307,8 @@
|
||||
}
|
||||
});
|
||||
|
||||
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy');
|
||||
|
||||
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy')
|
||||
.then(() => {
|
||||
// We pretend this is a new room, so no disco info is returned.
|
||||
var features_stanza = $iq({
|
||||
from: 'lounge@localhost',
|
||||
@ -1345,7 +1319,7 @@
|
||||
.c('item-not-found', {'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas"});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
|
||||
|
||||
var view = _converse.chatboxviews.get('lounge@localhost');
|
||||
view = _converse.chatboxviews.get('lounge@localhost');
|
||||
spyOn(view, 'join').and.callThrough();
|
||||
|
||||
/* <iq from='hag66@shakespeare.lit/pda'
|
||||
@ -1356,12 +1330,8 @@
|
||||
* node='x-roomuser-item'/>
|
||||
* </iq>
|
||||
*/
|
||||
|
||||
test_utils.waitUntil(function () {
|
||||
return _.filter(IQ_stanzas, function (iq) {
|
||||
return iq.nodeTree.querySelector('query[node="x-roomuser-item"]');
|
||||
}).length > 0;
|
||||
}, 300).then(function () {
|
||||
return test_utils.waitUntil(() => _.filter(IQ_stanzas, (iq) => iq.nodeTree.querySelector('query[node="x-roomuser-item"]')).length)
|
||||
}).then(() => {
|
||||
const iq = _.filter(IQ_stanzas, function (iq) {
|
||||
return iq.nodeTree.querySelector(`query[node="x-roomuser-item"]`);
|
||||
}).pop();
|
||||
@ -1421,20 +1391,23 @@
|
||||
|
||||
it("allows the user to invite their roster contacts to enter the groupchat",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy');
|
||||
test_utils.createContacts(_converse, 'current'); // We need roster contacts, so that we have someone to invite
|
||||
// Since we don't actually fetch roster contacts, we need to
|
||||
// cheat here and emit the event.
|
||||
_converse.emit('rosterContactsFetched');
|
||||
|
||||
let view;
|
||||
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy')
|
||||
.then(() => {
|
||||
|
||||
spyOn(_converse, 'emit');
|
||||
spyOn(window, 'prompt').and.callFake(function () {
|
||||
return "Please join!";
|
||||
});
|
||||
var view = _converse.chatboxviews.get('lounge@localhost');
|
||||
view = _converse.chatboxviews.get('lounge@localhost');
|
||||
|
||||
// XXX: cheating a lttle bit, normally this'll be set after
|
||||
// receiving the features for the groupchat.
|
||||
@ -1444,9 +1417,8 @@
|
||||
var $input;
|
||||
$(view.el).find('.chat-area').remove();
|
||||
|
||||
test_utils.waitUntil(function () {
|
||||
return $(view.el).find('input.invited-contact').length;
|
||||
}, 300).then(function () {
|
||||
return test_utils.waitUntil(() => view.el.querySelectorAll('input.invited-contact').length)
|
||||
}).then(function () {
|
||||
var $input = $(view.el).find('input.invited-contact');
|
||||
expect($input.attr('placeholder')).toBe('Invite');
|
||||
$input.val("Felix");
|
||||
@ -1782,7 +1754,7 @@
|
||||
|
||||
it("queries for the groupchat information before attempting to join the user",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
var sent_IQ, IQ_id;
|
||||
@ -1792,15 +1764,16 @@
|
||||
IQ_id = sendIQ.bind(this)(iq, callback, errback);
|
||||
});
|
||||
|
||||
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
|
||||
|
||||
let view;
|
||||
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'})
|
||||
.then(() => {
|
||||
// Check that the groupchat queried for the feautures.
|
||||
expect(sent_IQ.toLocaleString()).toBe(
|
||||
"<iq from='dummy@localhost/resource' to='coven@chat.shakespeare.lit' type='get' xmlns='jabber:client' id='"+IQ_id+"'>"+
|
||||
"<query xmlns='http://jabber.org/protocol/disco#info'/>"+
|
||||
"</iq>");
|
||||
|
||||
var view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
|
||||
view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
|
||||
spyOn(view.model, 'parseRoomFeatures').and.callThrough();
|
||||
/* <iq from='coven@chat.shakespeare.lit'
|
||||
* id='ik3vs715'
|
||||
@ -1821,7 +1794,7 @@
|
||||
* </query>
|
||||
* </iq>
|
||||
*/
|
||||
var features_stanza = $iq({
|
||||
const features_stanza = $iq({
|
||||
from: 'coven@chat.shakespeare.lit',
|
||||
'id': IQ_id,
|
||||
'to': 'dummy@localhost/desktop',
|
||||
@ -1841,8 +1814,8 @@
|
||||
.c('feature', {'var': 'muc_unmoderated'}).up()
|
||||
.c('feature', {'var': 'muc_nonanonymous'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
|
||||
test_utils.waitUntil(() => view.model.parseRoomFeatures.calls.count(), 300)
|
||||
.then(() => {
|
||||
return test_utils.waitUntil(() => view.model.parseRoomFeatures.calls.count(), 300)
|
||||
}).then(() => {
|
||||
expect(view.model.get('features_fetched')).toBeTruthy();
|
||||
expect(view.model.get('passwordprotected')).toBe(true);
|
||||
expect(view.model.get('hidden')).toBe(true);
|
||||
@ -2014,10 +1987,11 @@
|
||||
|
||||
it("can be saved to, and retrieved from, browserStorage",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy');
|
||||
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy')
|
||||
.then(() => {
|
||||
// We instantiate a new ChatBoxes collection, which by default
|
||||
// will be empty.
|
||||
test_utils.openControlBox();
|
||||
@ -2042,15 +2016,17 @@
|
||||
}
|
||||
_converse.rosterview.render();
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("can be minimized by clicking a DOM element with class 'toggle-chatbox-button'",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy');
|
||||
var view = _converse.chatboxviews.get('lounge@localhost'),
|
||||
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy')
|
||||
.then(() => {
|
||||
const view = _converse.chatboxviews.get('lounge@localhost'),
|
||||
trimmed_chatboxes = _converse.minimized_chats;
|
||||
|
||||
spyOn(view, 'minimize').and.callThrough();
|
||||
@ -2071,15 +2047,18 @@
|
||||
expect(view.model.get('minimized')).toBeFalsy();
|
||||
expect(_converse.emit.calls.count(), 3);
|
||||
done();
|
||||
|
||||
});
|
||||
}));
|
||||
|
||||
it("can be closed again by clicking a DOM element with class 'close-chatbox-button'",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy');
|
||||
var view = _converse.chatboxviews.get('lounge@localhost');
|
||||
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy')
|
||||
.then(() => {
|
||||
const view = _converse.chatboxviews.get('lounge@localhost');
|
||||
spyOn(view, 'close').and.callThrough();
|
||||
spyOn(_converse, 'emit');
|
||||
spyOn(view.model, 'leave');
|
||||
@ -2089,6 +2068,7 @@
|
||||
expect(view.model.leave).toHaveBeenCalled();
|
||||
expect(_converse.emit).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object));
|
||||
done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
@ -2953,20 +2933,20 @@
|
||||
|
||||
it("will first be added to the member list if the groupchat is members only",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
var sent_IQs = [], IQ_ids = [];
|
||||
var invitee_jid, sent_stanza, sent_id;
|
||||
let invitee_jid, sent_stanza, sent_id, view;
|
||||
var sendIQ = _converse.connection.sendIQ;
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
|
||||
sent_IQs.push(iq);
|
||||
IQ_ids.push(sendIQ.bind(this)(iq, callback, errback));
|
||||
});
|
||||
|
||||
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'dummy'});
|
||||
|
||||
var view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
|
||||
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'dummy'})
|
||||
.then(() => {
|
||||
view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
|
||||
spyOn(view.model, 'parseRoomFeatures').and.callThrough();
|
||||
|
||||
// State that the chat is members-only via the features IQ
|
||||
@ -2988,8 +2968,8 @@
|
||||
.c('feature', {'var': 'muc_membersonly'}).up();
|
||||
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
|
||||
|
||||
test_utils.waitUntil(() => view.model.parseRoomFeatures.calls.count(), 300)
|
||||
.then(() => {
|
||||
return test_utils.waitUntil(() => view.model.parseRoomFeatures.calls.count(), 300);
|
||||
}).then(() => {
|
||||
expect(view.model.get('membersonly')).toBeTruthy();
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
@ -3174,10 +3154,12 @@
|
||||
|
||||
it("contains a link to a modal through which a new chatroom can be created",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.openControlBox();
|
||||
_converse.emit('rosterContactsFetched');
|
||||
|
||||
var roomspanel = _converse.chatboxviews.get('controlbox').roomspanel;
|
||||
roomspanel.el.querySelector('.show-add-muc-modal').click();
|
||||
test_utils.closeControlBox(_converse);
|
||||
@ -3193,6 +3175,8 @@
|
||||
|
||||
modal.el.querySelector('input[name="chatroom"]').value = 'lounce@muc.localhost';
|
||||
modal.el.querySelector('form input[type="submit"]').click();
|
||||
return test_utils.waitUntil(() => _converse.chatboxes.length);
|
||||
}).then(() => {
|
||||
expect($('.chatroom:visible').length).toBe(1); // There should now be an open chatroom
|
||||
done();
|
||||
}).catch(_.partial(console.error, _));
|
||||
@ -3200,10 +3184,9 @@
|
||||
|
||||
it("contains a link to a modal which can list groupchats publically available on the server",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
|
||||
var sendIQ = _converse.connection.sendIQ;
|
||||
var sent_stanza, IQ_id;
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
|
||||
@ -3216,9 +3199,8 @@
|
||||
roomspanel.el.querySelector('.show-list-muc-modal').click();
|
||||
test_utils.closeControlBox(_converse);
|
||||
const modal = roomspanel.list_rooms_modal;
|
||||
test_utils.waitUntil(function () {
|
||||
return u.isVisible(modal.el);
|
||||
}, 1000).then(function () {
|
||||
test_utils.waitUntil(() => u.isVisible(modal.el), 1000)
|
||||
.then(() => {
|
||||
spyOn(_converse.ChatRoom.prototype, 'getRoomFeatures').and.callFake(function () {
|
||||
var deferred = new $.Deferred();
|
||||
deferred.resolve();
|
||||
@ -3231,7 +3213,8 @@
|
||||
|
||||
const input = modal.el.querySelector('input[name="server"]').value = 'chat.shakespear.lit';
|
||||
modal.el.querySelector('input[type="submit"]').click();
|
||||
|
||||
return test_utils.waitUntil(() => _converse.chatboxes.length);
|
||||
}).then(() => {
|
||||
expect(sent_stanza.toLocaleString()).toBe(
|
||||
"<iq to='chat.shakespear.lit' from='dummy@localhost/resource' type='get' xmlns='jabber:client' id='"+IQ_id+"'>"+
|
||||
"<query xmlns='http://jabber.org/protocol/disco#items'/>"+
|
||||
@ -3260,6 +3243,8 @@
|
||||
expect(rooms[4].textContent.trim()).toBe("Macbeth's Castle");
|
||||
|
||||
rooms[4].querySelector('.open-room').click();
|
||||
return test_utils.waitUntil(() => _converse.chatboxes.length > 1);
|
||||
}).then(() => {
|
||||
expect($('.chatroom:visible').length).toBe(1); // There should now be an open chatroom
|
||||
var view = _converse.chatboxviews.get('inverness@chat.shakespeare.lit');
|
||||
expect(view.el.querySelector('.chat-head-chatroom').textContent.trim()).toBe("Macbeth's Castle");
|
||||
@ -3509,10 +3494,11 @@
|
||||
describe("A paused notification", function () {
|
||||
it("will be shown if received",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.openChatRoom(_converse, "coven", 'chat.shakespeare.lit', 'some1');
|
||||
test_utils.openChatRoom(_converse, "coven", 'chat.shakespeare.lit', 'some1')
|
||||
.then(() => {
|
||||
var room_jid = 'coven@chat.shakespeare.lit';
|
||||
var view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
|
||||
var $chat_content = $(view.el).find('.chat-content');
|
||||
@ -3645,6 +3631,7 @@
|
||||
expect(notifications[0].textContent).toEqual('nomorenicks is typing');
|
||||
expect(notifications[1].textContent).toEqual('newguy has stopped typing');
|
||||
done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
@ -66,16 +66,18 @@
|
||||
|
||||
it("shows the number of unread mentions received",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'all').openControlBox();
|
||||
_converse.emit('rosterContactsFetched');
|
||||
|
||||
var contacts_panel = _converse.chatboxviews.get('controlbox').contactspanel;
|
||||
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
|
||||
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, sender_jid);
|
||||
var chatview = _converse.chatboxviews.get(sender_jid);
|
||||
return test_utils.waitUntil(() => _converse.chatboxes.length).then(() => {
|
||||
|
||||
const chatview = _converse.chatboxviews.get(sender_jid);
|
||||
chatview.model.set({'minimized': true});
|
||||
|
||||
expect(_.isNull(_converse.chatboxviews.el.querySelector('.restore-chat .message-count'))).toBeTruthy();
|
||||
@ -107,6 +109,7 @@
|
||||
expect(_.isNull(_converse.chatboxviews.el.querySelector('.restore-chat .message-count'))).toBeTruthy();
|
||||
expect(_.isNull(_converse.rosterview.el.querySelector('.msgs-indicator'))).toBeTruthy();
|
||||
done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
(function (root, factory) {
|
||||
define([
|
||||
"jquery",
|
||||
"jasmine",
|
||||
"mock",
|
||||
"test-utils"], factory);
|
||||
} (this, function ($, jasmine, mock, test_utils) {
|
||||
var b64_sha1 = converse.env.b64_sha1;
|
||||
var _ = converse.env._;
|
||||
} (this, function (jasmine, mock, test_utils) {
|
||||
const b64_sha1 = converse.env.b64_sha1,
|
||||
_ = converse.env._,
|
||||
u = converse.env.utils;
|
||||
|
||||
describe("Converse", function() {
|
||||
|
||||
@ -274,59 +274,72 @@
|
||||
|
||||
describe("The \"chats\" API", function() {
|
||||
|
||||
it("has a method 'get' which returns the chatbox model", mock.initConverseWithPromises(
|
||||
null, ['rosterInitialized'], {}, function (done, _converse) {
|
||||
it("has a method 'get' which returns the promise that resolves to a chat model", mock.initConverseWithPromises(
|
||||
null, ['rosterInitialized', 'chatBoxesInitialized'], {}, function (done, _converse) {
|
||||
test_utils.openControlBox();
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
test_utils.createContacts(_converse, 'current', 2);
|
||||
_converse.emit('rosterContactsFetched');
|
||||
|
||||
// Test on chat that doesn't exist.
|
||||
expect(_converse.api.chats.get('non-existing@jabber.org')).toBeFalsy();
|
||||
var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
const jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
const jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
|
||||
// Test on chat that's not open
|
||||
var box = _converse.api.chats.get(jid);
|
||||
let box = _converse.api.chats.get(jid);
|
||||
expect(typeof box === 'undefined').toBeTruthy();
|
||||
var chatboxview = _converse.chatboxviews.get(jid);
|
||||
// Test for single JID
|
||||
expect(_converse.chatboxes.length).toBe(1);
|
||||
|
||||
// Test for one JID
|
||||
test_utils.openChatBoxFor(_converse, jid);
|
||||
test_utils.waitUntil(() => _converse.chatboxes.length == 1).then(() => {
|
||||
box = _converse.api.chats.get(jid);
|
||||
expect(box instanceof Object).toBeTruthy();
|
||||
expect(box.get('box_id')).toBe(b64_sha1(jid));
|
||||
chatboxview = _converse.chatboxviews.get(jid);
|
||||
expect($(chatboxview.el).is(':visible')).toBeTruthy();
|
||||
|
||||
const chatboxview = _converse.chatboxviews.get(jid);
|
||||
expect(u.isVisible(chatboxview.el)).toBeTruthy();
|
||||
// Test for multiple JIDs
|
||||
var jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, jid2);
|
||||
var list = _converse.api.chats.get([jid, jid2]);
|
||||
return test_utils.waitUntil(() => _converse.chatboxes.length == 2);
|
||||
}).then(() => {
|
||||
const list = _converse.api.chats.get([jid, jid2]);
|
||||
expect(_.isArray(list)).toBeTruthy();
|
||||
expect(list[0].get('box_id')).toBe(b64_sha1(jid));
|
||||
expect(list[1].get('box_id')).toBe(b64_sha1(jid2));
|
||||
done();
|
||||
}).catch(_.partial(console.error, _));
|
||||
}));
|
||||
|
||||
it("has a method 'open' which opens and returns the chatbox model", mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {}, function (done, _converse) {
|
||||
it("has a method 'open' which opens and returns a promise that resolves to a chat model", mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched', 'chatBoxesInitialized'], {}, function (done, _converse) {
|
||||
|
||||
test_utils.openControlBox();
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
var chatboxview;
|
||||
test_utils.createContacts(_converse, 'current', 2);
|
||||
_converse.emit('rosterContactsFetched');
|
||||
|
||||
const jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
const jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
// Test on chat that doesn't exist.
|
||||
expect(_converse.api.chats.get('non-existing@jabber.org')).toBeFalsy();
|
||||
var box = _converse.api.chats.open(jid);
|
||||
|
||||
return _converse.api.chats.open(jid).then((box) => {
|
||||
expect(box instanceof Object).toBeTruthy();
|
||||
expect(box.get('box_id')).toBe(b64_sha1(jid));
|
||||
expect(
|
||||
_.keys(box),
|
||||
['close', 'focus', 'get', 'is_chatroom', 'maximize', 'minimize', 'open', 'set']
|
||||
['close', 'endOTR', 'focus', 'get', 'initiateOTR', 'is_chatroom', 'maximize', 'minimize', 'open', 'set']
|
||||
);
|
||||
chatboxview = _converse.chatboxviews.get(jid);
|
||||
expect($(chatboxview.el).is(':visible')).toBeTruthy();
|
||||
const chatboxview = _converse.chatboxviews.get(jid);
|
||||
expect(u.isVisible(chatboxview.el)).toBeTruthy();
|
||||
// Test for multiple JIDs
|
||||
var jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
var list = _converse.api.chats.open([jid, jid2]);
|
||||
return _converse.api.chats.open([jid, jid2]);
|
||||
}).then((list) => {
|
||||
expect(_.isArray(list)).toBeTruthy();
|
||||
expect(list[0].get('box_id')).toBe(b64_sha1(jid));
|
||||
expect(list[1].get('box_id')).toBe(b64_sha1(jid2));
|
||||
done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
|
@ -225,25 +225,28 @@
|
||||
[{'category': 'server', 'type':'IM'}],
|
||||
['http://jabber.org/protocol/disco#items'], [], 'info').then(function () {
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.localhost'], 'items').then(function () {
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, 'upload.localhost', [], [Strophe.NS.HTTPUPLOAD], []).then(function () {
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
var view = _converse.chatboxviews.get(contact_jid);
|
||||
test_utils.waitUntil(function () {
|
||||
return view.el.querySelector('.upload-file');
|
||||
}, 150).then(function () {
|
||||
let contact_jid, view;
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.localhost'], 'items')
|
||||
.then(() => test_utils.waitUntilDiscoConfirmed(_converse, 'upload.localhost', [], [Strophe.NS.HTTPUPLOAD], []))
|
||||
.then(() => {
|
||||
test_utils.createContacts(_converse, 'current', 3);
|
||||
_converse.emit('rosterContactsFetched');
|
||||
|
||||
contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
return test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
}).then(() => {
|
||||
view = _converse.chatboxviews.get(contact_jid);
|
||||
test_utils.waitUntil(() => view.el.querySelector('.upload-file'));
|
||||
}).then(() => {
|
||||
expect(view.el.querySelector('.chat-toolbar .upload-file')).not.toBe(null);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
it("appears in MUC chats", mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(
|
||||
@ -251,19 +254,15 @@
|
||||
[{'category': 'server', 'type':'IM'}],
|
||||
['http://jabber.org/protocol/disco#items'], [], 'info').then(function () {
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.localhost'], 'items').then(function () {
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, 'upload.localhost', [], [Strophe.NS.HTTPUPLOAD], []).then(function () {
|
||||
test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy').then(function () {
|
||||
var view = _converse.chatboxviews.get('lounge@localhost');
|
||||
test_utils.waitUntil(function () {
|
||||
return view.el.querySelector('.upload-file');
|
||||
}).then(function () {
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.localhost'], 'items')
|
||||
.then(() => test_utils.waitUntilDiscoConfirmed(_converse, 'upload.localhost', [], [Strophe.NS.HTTPUPLOAD], []))
|
||||
.then(() => test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy'))
|
||||
.then(() => test_utils.waitUntil(() => _converse.chatboxviews.get('lounge@localhost').el.querySelector('.upload-file')))
|
||||
.then(() => {
|
||||
const view = _converse.chatboxviews.get('lounge@localhost');
|
||||
expect(view.el.querySelector('.chat-toolbar .upload-file')).not.toBe(null);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||
});
|
||||
}));
|
||||
|
||||
@ -277,12 +276,16 @@
|
||||
|
||||
var send_backup = XMLHttpRequest.prototype.send;
|
||||
var IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
let contact_jid;
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items').then(function () {
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []).then(function () {
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items')
|
||||
.then(() => test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []))
|
||||
.then(() => {
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
_converse.emit('rosterContactsFetched');
|
||||
contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
return test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
}).then(() => {
|
||||
var view = _converse.chatboxviews.get(contact_jid);
|
||||
var file = {
|
||||
'type': 'image/jpeg',
|
||||
@ -365,17 +368,16 @@
|
||||
}).then(function () {
|
||||
// Check that the image renders
|
||||
expect(view.el.querySelector('.chat-msg .chat-msg__media').innerHTML.trim()).toEqual(
|
||||
'<!-- src/templates/image.html -->\n'+
|
||||
'<a href="http://localhost:8000/logo/conversejs-filled.svg" target="_blank" rel="noopener">'+
|
||||
'<img class="chat-image img-thumbnail" src="http://localhost:8000/logo/conversejs-filled.svg">'+
|
||||
'</a>');
|
||||
`<!-- src/templates/image.html -->\n`+
|
||||
`<a href="${window.location.origin}/logo/conversejs-filled.svg" target="_blank" rel="noopener">`+
|
||||
`<img class="chat-image img-thumbnail" src="${window.location.origin}/logo/conversejs-filled.svg">`+
|
||||
`</a>`);
|
||||
XMLHttpRequest.prototype.send = send_backup;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
it("is uploaded and sent out from a groupchat", mock.initConverseWithAsync(function (done, _converse) {
|
||||
@ -473,9 +475,10 @@
|
||||
}).then(function () {
|
||||
// Check that the image renders
|
||||
expect(view.el.querySelector('.chat-msg .chat-msg__media').innerHTML.trim()).toEqual(
|
||||
'<!-- src/templates/image.html -->\n'+
|
||||
'<a href="http://localhost:8000/logo/conversejs-filled.svg" target="_blank" rel="noopener">'+
|
||||
'<img class="chat-image img-thumbnail" src="http://localhost:8000/logo/conversejs-filled.svg"></a>')
|
||||
`<!-- src/templates/image.html -->\n`+
|
||||
`<a href="${window.location.origin}/logo/conversejs-filled.svg" target="_blank" rel="noopener">`+
|
||||
`<img class="chat-image img-thumbnail" src="${window.location.origin}/logo/conversejs-filled.svg">`+
|
||||
`</a>`);
|
||||
XMLHttpRequest.prototype.send = send_backup;
|
||||
done();
|
||||
});
|
||||
@ -486,18 +489,16 @@
|
||||
});
|
||||
}));
|
||||
|
||||
it("shows and error message if the file is too large", mock.initConverseWithAsync(function (done, _converse) {
|
||||
var IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
var IQ_ids = _converse.connection.IQ_ids;
|
||||
var send_backup = XMLHttpRequest.prototype.send;
|
||||
it("shows an error message if the file is too large", mock.initConverseWithAsync(function (done, _converse) {
|
||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
const IQ_ids = _converse.connection.IQ_ids;
|
||||
const send_backup = XMLHttpRequest.prototype.send;
|
||||
let view, contact_jid;
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []).then(function () {
|
||||
test_utils.waitUntil(function () {
|
||||
return _.filter(IQ_stanzas, function (iq) {
|
||||
return iq.nodeTree.querySelector(
|
||||
'iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
|
||||
}).length > 0;
|
||||
}, 300).then(function () {
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], [])
|
||||
.then(() => test_utils.waitUntil(() => _.filter(
|
||||
IQ_stanzas, (iq) => iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]')).length
|
||||
)).then(() => {
|
||||
var stanza = _.find(IQ_stanzas, function (iq) {
|
||||
return iq.nodeTree.querySelector(
|
||||
'iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
|
||||
@ -518,8 +519,8 @@
|
||||
.c('feature', {
|
||||
'var': 'http://jabber.org/protocol/disco#items'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
_converse.api.disco.entities.get().then(function(entities) {
|
||||
return _converse.api.disco.entities.get();
|
||||
}).then(function (entities) {
|
||||
expect(entities.length).toBe(2);
|
||||
expect(_.includes(entities.pluck('jid'), 'localhost')).toBe(true);
|
||||
expect(_.includes(entities.pluck('jid'), 'dummy@localhost')).toBe(true);
|
||||
@ -534,7 +535,6 @@
|
||||
return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]');
|
||||
}).length > 0;
|
||||
}, 300);
|
||||
});
|
||||
}).then(function () {
|
||||
var stanza = _.find(IQ_stanzas, function (iq) {
|
||||
return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]');
|
||||
@ -549,6 +549,7 @@
|
||||
.c('item', {
|
||||
'jid': 'upload.localhost',
|
||||
'name': 'HTTP File Upload'});
|
||||
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
_converse.api.disco.entities.get().then(function (entities) {
|
||||
@ -583,15 +584,18 @@
|
||||
.c('field', {'var':'max-file-size'})
|
||||
.c('value').t('5242880');
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
_converse.api.disco.entities.get().then(function (entities) {
|
||||
return _converse.api.disco.entities.get();
|
||||
}).then(function (entities) {
|
||||
expect(entities.get('localhost').items.get('upload.localhost').identities.where({'category': 'store'}).length).toBe(1);
|
||||
_converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain).then(
|
||||
function (result) {
|
||||
return _converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain);
|
||||
}).then(function (result) {
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
var view = _converse.chatboxviews.get(contact_jid);
|
||||
_converse.emit('rosterContactsFetched');
|
||||
|
||||
contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
return test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
}).then(() => {
|
||||
view = _converse.chatboxviews.get(contact_jid);
|
||||
var file = {
|
||||
'type': 'image/jpeg',
|
||||
'size': '5242881',
|
||||
@ -599,27 +603,23 @@
|
||||
'name': "my-juliet.jpg"
|
||||
};
|
||||
view.model.sendFiles([file]);
|
||||
return test_utils.waitUntil(function () {
|
||||
return view.el.querySelectorAll('.message').length;
|
||||
return test_utils.waitUntil(() => view.el.querySelectorAll('.message').length)
|
||||
}).then(function () {
|
||||
const messages = view.el.querySelectorAll('.message.chat-error');
|
||||
expect(messages.length).toBe(1);
|
||||
expect(messages[0].textContent).toBe(
|
||||
'The size of your file, my-juliet.jpg, exceeds the maximum allowed by your server, which is 5 MB.');
|
||||
done();
|
||||
});
|
||||
}
|
||||
);
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||
})
|
||||
});
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL))
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("While a file is being uploaded", function () {
|
||||
|
||||
it("shows a progress bar", mock.initConverseWithAsync(function (done, _converse) {
|
||||
it("shows a progress bar", mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, function (done, _converse) {
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(
|
||||
_converse, _converse.domain,
|
||||
[{'category': 'server', 'type':'IM'}],
|
||||
@ -627,26 +627,28 @@
|
||||
|
||||
var send_backup = XMLHttpRequest.prototype.send;
|
||||
var IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
let view, contact_jid;
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items').then(function () {
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []).then(function () {
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.montague.tld'], 'items')
|
||||
.then(() => test_utils.waitUntilDiscoConfirmed(_converse, 'upload.montague.tld', [], [Strophe.NS.HTTPUPLOAD], []))
|
||||
.then(() => {
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
var view = _converse.chatboxviews.get(contact_jid);
|
||||
var file = {
|
||||
_converse.emit('rosterContactsFetched');
|
||||
|
||||
contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
return test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
}).then(() => {
|
||||
view = _converse.chatboxviews.get(contact_jid);
|
||||
const file = {
|
||||
'type': 'image/jpeg',
|
||||
'size': '23456' ,
|
||||
'lastModifiedDate': "",
|
||||
'name': "my-juliet.jpg"
|
||||
};
|
||||
view.model.sendFiles([file]);
|
||||
return test_utils.waitUntil(function () {
|
||||
return _.filter(IQ_stanzas, function (iq) {
|
||||
return iq.nodeTree.querySelector('iq[to="upload.montague.tld"] request');
|
||||
}).length > 0;
|
||||
return test_utils.waitUntil(() => _.filter(IQ_stanzas, (iq) => iq.nodeTree.querySelector('iq[to="upload.montague.tld"] request')).length)
|
||||
}).then(function () {
|
||||
var iq = IQ_stanzas.pop();
|
||||
const iq = IQ_stanzas.pop();
|
||||
expect(iq.toLocaleString()).toBe(
|
||||
"<iq from='dummy@localhost/resource' "+
|
||||
"to='upload.montague.tld' "+
|
||||
@ -659,10 +661,9 @@
|
||||
"content-type='image/jpeg'/>"+
|
||||
"</iq>");
|
||||
|
||||
var base_url = document.URL.split(window.location.pathname)[0];
|
||||
var message = base_url+"/logo/conversejs-filled.svg";
|
||||
|
||||
var stanza = Strophe.xmlHtmlNode(
|
||||
const base_url = document.URL.split(window.location.pathname)[0];
|
||||
const message = base_url+"/logo/conversejs-filled.svg";
|
||||
const stanza = Strophe.xmlHtmlNode(
|
||||
"<iq from='upload.montague.tld'"+
|
||||
" id='"+iq.nodeTree.getAttribute('id')+"'"+
|
||||
" to='dummy@localhost/resource'"+
|
||||
@ -675,7 +676,6 @@
|
||||
" <get url='"+message+"' />"+
|
||||
"</slot>"+
|
||||
"</iq>").firstElementChild;
|
||||
|
||||
spyOn(XMLHttpRequest.prototype, 'send').and.callFake(function () {
|
||||
const message = view.model.messages.at(0);
|
||||
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0');
|
||||
@ -693,11 +693,8 @@
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
304
spec/messages.js
304
spec/messages.js
@ -21,14 +21,15 @@
|
||||
|
||||
it("can be sent as a correction by clicking the pencil icon",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current', 1);
|
||||
_converse.emit('rosterContactsFetched');
|
||||
test_utils.openControlBox();
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
|
||||
test_utils.openChatBoxFor(_converse, contact_jid)
|
||||
.then(() => {
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
|
||||
@ -115,19 +116,21 @@
|
||||
);
|
||||
expect(view.el.querySelectorAll('.chat-msg .chat-msg__action').length).toBe(1);
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
|
||||
it("can be sent as a correction by using the up arrow",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current', 1);
|
||||
_converse.emit('rosterContactsFetched');
|
||||
test_utils.openControlBox();
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
|
||||
test_utils.openChatBoxFor(_converse, contact_jid)
|
||||
.then(() => {
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
expect(textarea.value).toBe('');
|
||||
@ -262,6 +265,7 @@
|
||||
expect(view.model.messages.at(1).get('correcting')).toBeFalsy();
|
||||
expect(view.model.messages.at(2).get('correcting')).toBeFalsy();
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
|
||||
@ -321,15 +325,16 @@
|
||||
|
||||
it("can be replaced with a correction",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current', 1);
|
||||
_converse.emit('rosterContactsFetched');
|
||||
test_utils.openControlBox();
|
||||
const message = 'This is a received message';
|
||||
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, sender_jid);
|
||||
|
||||
test_utils.openChatBoxFor(_converse, sender_jid)
|
||||
.then(() => {
|
||||
const msg_id = u.getUniqueId();
|
||||
_converse.chatboxes.onMessage($msg({
|
||||
'from': sender_jid,
|
||||
@ -381,6 +386,7 @@
|
||||
expect(older_msgs[1].textContent).toBe('But soft, what light through yonder chimney breaks?');
|
||||
done();
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
describe("when a chatbox is opened for someone who is not in the roster", function () {
|
||||
@ -500,10 +506,11 @@
|
||||
|
||||
it("will have the error message displayed after itself",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
test_utils.openControlBox();
|
||||
|
||||
// TODO: what could still be done for error
|
||||
@ -524,7 +531,8 @@
|
||||
var sender_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
var fullname = _converse.xmppstatus.get('fullname');
|
||||
fullname = _.isEmpty(fullname)? _converse.bare_jid: fullname;
|
||||
_converse.api.chats.open(sender_jid);
|
||||
_converse.api.chats.open(sender_jid)
|
||||
.then(() => {
|
||||
var msg_text = 'This message will not be sent, due to an error';
|
||||
var view = _converse.chatboxviews.get(sender_jid);
|
||||
var message = view.model.messages.create({
|
||||
@ -621,25 +629,28 @@
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
expect($chat_content.find('.chat-error').length).toEqual(3);
|
||||
done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
it("will cause the chat area to be scrolled down only if it was at the bottom originally",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
test_utils.openControlBox();
|
||||
|
||||
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, sender_jid);
|
||||
|
||||
var chatboxview = _converse.chatboxviews.get(sender_jid);
|
||||
let chatboxview;
|
||||
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
const message = 'This message is received while the chat area is scrolled up';
|
||||
test_utils.openChatBoxFor(_converse, sender_jid)
|
||||
.then(() => {
|
||||
chatboxview = _converse.chatboxviews.get(sender_jid);
|
||||
spyOn(chatboxview, 'onScrolledDown').and.callThrough();
|
||||
|
||||
// Create enough messages so that there's a scrollbar.
|
||||
var message = 'This message is received while the chat area is scrolled up';
|
||||
for (var i=0; i<20; i++) {
|
||||
_converse.chatboxes.onMessage($msg({
|
||||
from: sender_jid,
|
||||
@ -649,18 +660,12 @@
|
||||
}).c('body').t('Message: '+i).up()
|
||||
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
|
||||
}
|
||||
return test_utils.waitUntil(function () {
|
||||
return chatboxview.content.scrollTop;
|
||||
}, 1000).then(function () {
|
||||
return test_utils.waitUntil(function () {
|
||||
return !chatboxview.model.get('auto_scrolled');
|
||||
}, 500);
|
||||
}).then(function () {
|
||||
return test_utils.waitUntil(() => chatboxview.content.scrollTop, 1000)
|
||||
.then(() => test_utils.waitUntil(() => !chatboxview.model.get('auto_scrolled'), 500))
|
||||
}).then(() => {
|
||||
chatboxview.content.scrollTop = 0;
|
||||
return test_utils.waitUntil(function () {
|
||||
return chatboxview.model.get('scrolled');
|
||||
}, 900);
|
||||
}).then(function () {
|
||||
return test_utils.waitUntil(() => chatboxview.model.get('scrolled'), 900);
|
||||
}).then(() => {
|
||||
_converse.chatboxes.onMessage($msg({
|
||||
from: sender_jid,
|
||||
to: _converse.connection.jid,
|
||||
@ -670,21 +675,17 @@
|
||||
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
|
||||
|
||||
// Now check that the message appears inside the chatbox in the DOM
|
||||
var $chat_content = $(chatboxview.el).find('.chat-content');
|
||||
var msg_txt = $chat_content.find('.chat-msg:last').find('.chat-msg__text').text();
|
||||
const $chat_content = $(chatboxview.el).find('.chat-content');
|
||||
const msg_txt = $chat_content.find('.chat-msg:last').find('.chat-msg__text').text();
|
||||
expect(msg_txt).toEqual(message);
|
||||
return test_utils.waitUntil(function () {
|
||||
return u.isVisible(chatboxview.el.querySelector('.new-msgs-indicator'));
|
||||
}, 500);
|
||||
}).then(function () {
|
||||
return test_utils.waitUntil(() => u.isVisible(chatboxview.el.querySelector('.new-msgs-indicator')), 900);
|
||||
}).then(() => {
|
||||
expect(chatboxview.model.get('scrolled')).toBe(true);
|
||||
expect(chatboxview.content.scrollTop).toBe(0);
|
||||
expect(u.isVisible(chatboxview.el.querySelector('.new-msgs-indicator'))).toBeTruthy();
|
||||
// Scroll down again
|
||||
chatboxview.content.scrollTop = chatboxview.content.scrollHeight;
|
||||
return test_utils.waitUntil(function () {
|
||||
return !u.isVisible(chatboxview.el.querySelector('.new-msgs-indicator'));
|
||||
}, 700);
|
||||
return test_utils.waitUntil(() => !u.isVisible(chatboxview.el.querySelector('.new-msgs-indicator')), 900);
|
||||
}).then(done);
|
||||
}));
|
||||
|
||||
@ -1109,23 +1110,22 @@
|
||||
|
||||
it("received for a minimized chat box will increment a counter on its header",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
if (_converse.view_mode === 'fullscreen') {
|
||||
return done();
|
||||
}
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
const contact_name = mock.cur_names[0];
|
||||
const contact_jid = contact_name.replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openControlBox();
|
||||
test_utils.waitUntil(function () {
|
||||
return $(_converse.rosterview.el).find('.roster-group').length;
|
||||
}, 300)
|
||||
.then(function () {
|
||||
var contact_name = mock.cur_names[0];
|
||||
var contact_jid = contact_name.replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
|
||||
spyOn(_converse, 'emit').and.callThrough();
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
|
||||
test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length)
|
||||
.then(() => test_utils.openChatBoxFor(_converse, contact_jid))
|
||||
.then(() => {
|
||||
var chatview = _converse.chatboxviews.get(contact_jid);
|
||||
expect(u.isVisible(chatview.el)).toBeTruthy();
|
||||
expect(chatview.model.get('minimized')).toBeFalsy();
|
||||
@ -1171,19 +1171,18 @@
|
||||
|
||||
it("will indicate when it has a time difference of more than a day between it and its predecessor",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
test_utils.openControlBox();
|
||||
test_utils.waitUntil(function () {
|
||||
return $(_converse.rosterview.el).find('.roster-group').length;
|
||||
}, 300)
|
||||
.then(function () {
|
||||
spyOn(_converse, 'emit');
|
||||
var contact_name = mock.cur_names[1];
|
||||
var contact_jid = contact_name.replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
const contact_name = mock.cur_names[1];
|
||||
const contact_jid = contact_name.replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length)
|
||||
.then(() => test_utils.openChatBoxFor(_converse, contact_jid))
|
||||
.then(() => {
|
||||
test_utils.clearChatBoxMessages(_converse, contact_jid);
|
||||
var one_day_ago = moment();
|
||||
one_day_ago.subtract('days', 1);
|
||||
@ -1270,18 +1269,20 @@
|
||||
|
||||
it("can be sent from a chatbox, and will appear inside it",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
test_utils.openControlBox();
|
||||
|
||||
spyOn(_converse, 'emit');
|
||||
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid)
|
||||
.then(() => {
|
||||
expect(_converse.emit).toHaveBeenCalledWith('chatBoxFocused', jasmine.any(Object));
|
||||
var view = _converse.chatboxviews.get(contact_jid);
|
||||
var message = 'This message is sent from this chatbox';
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const message = 'This message is sent from this chatbox';
|
||||
spyOn(view.model, 'sendMessage').and.callThrough();
|
||||
test_utils.sendMessage(view, message);
|
||||
expect(view.model.sendMessage).toHaveBeenCalled();
|
||||
@ -1289,61 +1290,70 @@
|
||||
expect(_converse.emit.calls.mostRecent().args, ['messageSend', message]);
|
||||
expect($(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text').text()).toEqual(message);
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("is sanitized to prevent Javascript injection attacks",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
test_utils.openControlBox();
|
||||
|
||||
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
var view = _converse.chatboxviews.get(contact_jid);
|
||||
var message = '<p>This message contains <em>some</em> <b>markup</b></p>';
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid)
|
||||
.then(() => {
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const message = '<p>This message contains <em>some</em> <b>markup</b></p>';
|
||||
spyOn(view.model, 'sendMessage').and.callThrough();
|
||||
test_utils.sendMessage(view, message);
|
||||
expect(view.model.sendMessage).toHaveBeenCalled();
|
||||
var msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text');
|
||||
const msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text');
|
||||
expect(msg.text()).toEqual(message);
|
||||
expect(msg.html()).toEqual('<p>This message contains <em>some</em> <b>markup</b></p>');
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("can contain hyperlinks, which will be clickable",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
test_utils.openControlBox();
|
||||
|
||||
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
var view = _converse.chatboxviews.get(contact_jid);
|
||||
var message = 'This message contains a hyperlink: www.opkode.com';
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid)
|
||||
.then(() => {
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const message = 'This message contains a hyperlink: www.opkode.com';
|
||||
spyOn(view.model, 'sendMessage').and.callThrough();
|
||||
test_utils.sendMessage(view, message);
|
||||
expect(view.model.sendMessage).toHaveBeenCalled();
|
||||
var msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text');
|
||||
const msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg__text');
|
||||
expect(msg.text()).toEqual(message);
|
||||
expect(msg.html()).toEqual('This message contains a hyperlink: <a target="_blank" rel="noopener" href="http://www.opkode.com">www.opkode.com</a>');
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("will have properly escaped URLs",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
test_utils.openControlBox();
|
||||
|
||||
var message, msg;
|
||||
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
let message, msg;
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid)
|
||||
.then(() => {
|
||||
var view = _converse.chatboxviews.get(contact_jid);
|
||||
spyOn(view.model, 'sendMessage').and.callThrough();
|
||||
message = "http://www.opkode.com/'onmouseover='alert(1)'whatever";
|
||||
@ -1376,10 +1386,14 @@
|
||||
expect(msg.text()).toEqual(message);
|
||||
expect(msg.html()).toEqual('<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Ender%27s_Game">'+message+'</a>');
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("will render newlines", mock.initConverseWithPromises(null, ['rosterGroupsFetched'], {}, function (done, _converse) {
|
||||
it("will render newlines",
|
||||
mock.initConverseWithPromises(null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
|
||||
@ -1417,19 +1431,22 @@
|
||||
|
||||
it("will render images from their URLs",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current', 1);
|
||||
_converse.emit('rosterContactsFetched');
|
||||
const base_url = document.URL.split(window.location.pathname)[0];
|
||||
let message = base_url+"/logo/conversejs-filled.svg";
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
let view;
|
||||
test_utils.openChatBoxFor(_converse, contact_jid)
|
||||
.then(() => {
|
||||
view = _converse.chatboxviews.get(contact_jid);
|
||||
spyOn(view.model, 'sendMessage').and.callThrough();
|
||||
test_utils.sendMessage(view, message);
|
||||
|
||||
test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-image').length, 1000).then(() => {
|
||||
return test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-image').length, 1000)
|
||||
}).then(() => {
|
||||
expect(view.model.sendMessage).toHaveBeenCalled();
|
||||
const msg = $(view.el).find('.chat-content .chat-msg').last().find('.chat-msg__text');
|
||||
expect(msg.html().trim()).toEqual(
|
||||
@ -1462,29 +1479,32 @@
|
||||
|
||||
it("will render the message time as configured",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'],
|
||||
{}, function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
|
||||
_converse.time_format = 'hh:mm';
|
||||
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
var view = _converse.chatboxviews.get(contact_jid);
|
||||
var message = 'This message is sent from this chatbox';
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid)
|
||||
.then(() => {
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const message = 'This message is sent from this chatbox';
|
||||
test_utils.sendMessage(view, message);
|
||||
|
||||
var chatbox = _converse.chatboxes.get(contact_jid);
|
||||
const chatbox = _converse.chatboxes.get(contact_jid);
|
||||
expect(chatbox.messages.models.length, 1);
|
||||
var msg_object = chatbox.messages.models[0];
|
||||
const msg_object = chatbox.messages.models[0];
|
||||
|
||||
var msg_author = view.el.querySelector('.chat-content .chat-msg:last-child .chat-msg__author');
|
||||
const msg_author = view.el.querySelector('.chat-content .chat-msg:last-child .chat-msg__author');
|
||||
expect(msg_author.textContent.trim()).toBe('Max Mustermann');
|
||||
|
||||
var msg_time = view.el.querySelector('.chat-content .chat-msg:last-child .chat-msg__time');
|
||||
var time = moment(msg_object.get('time')).format(_converse.time_format);
|
||||
const msg_time = view.el.querySelector('.chat-content .chat-msg:last-child .chat-msg__time');
|
||||
const time = moment(msg_object.get('time')).format(_converse.time_format);
|
||||
expect(msg_time.textContent).toBe(time);
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("will be correctly identified and rendered as a followup message",
|
||||
@ -1655,17 +1675,20 @@
|
||||
}));
|
||||
|
||||
|
||||
describe("which contains a OOB URL", function () {
|
||||
describe("which contains an OOB URL", function () {
|
||||
|
||||
it("will render audio from oob mp3 URLs",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current', 1);
|
||||
_converse.emit('rosterContactsFetched');
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
let view;
|
||||
test_utils.openChatBoxFor(_converse, contact_jid)
|
||||
.then(() => {
|
||||
view = _converse.chatboxviews.get(contact_jid);
|
||||
spyOn(view.model, 'sendMessage').and.callThrough();
|
||||
|
||||
const stanza = Strophe.xmlHtmlNode(
|
||||
@ -1674,10 +1697,11 @@
|
||||
" to='dummy@localhost/resource'>"+
|
||||
" <body>Have you heard this funny audio?</body>"+
|
||||
" <x xmlns='jabber:x:oob'><url>http://localhost/audio.mp3</url></x>"+
|
||||
"</message>").firstChild;
|
||||
"</message>").firstChild
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg audio').length, 1000).then(function () {
|
||||
return test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg audio').length, 1000);
|
||||
}).then(() => {
|
||||
let msg = view.el.querySelector('.chat-msg .chat-msg__text');
|
||||
expect(msg.outerHTML).toEqual('<div class="chat-msg__text">Have you heard this funny audio?</div>');
|
||||
let media = view.el.querySelector('.chat-msg .chat-msg__media');
|
||||
@ -1709,12 +1733,14 @@
|
||||
|
||||
it("will render video from oob mp4 URLs",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
test_utils.openChatBoxFor(_converse, contact_jid)
|
||||
.then(() => {
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
spyOn(view.model, 'sendMessage').and.callThrough();
|
||||
|
||||
@ -1755,17 +1781,21 @@
|
||||
'<a target="_blank" rel="noopener" href="http://localhost/video.mp4">Download video file</a>');
|
||||
done();
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
it("will render download links for files from oob URLs",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current', 1);
|
||||
_converse.emit('rosterContactsFetched');
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
let view;
|
||||
test_utils.openChatBoxFor(_converse, contact_jid)
|
||||
.then(() => {
|
||||
view = _converse.chatboxviews.get(contact_jid);
|
||||
spyOn(view.model, 'sendMessage').and.callThrough();
|
||||
|
||||
const stanza = Strophe.xmlHtmlNode(
|
||||
@ -1777,7 +1807,8 @@
|
||||
"</message>").firstChild;
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg a').length, 1000).then(function () {
|
||||
test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg a').length, 1000);
|
||||
}).then(function () {
|
||||
const msg = view.el.querySelector('.chat-msg .chat-msg__text');
|
||||
expect(msg.outerHTML).toEqual('<div class="chat-msg__text">Have you downloaded this funny file?</div>');
|
||||
const media = view.el.querySelector('.chat-msg .chat-msg__media');
|
||||
@ -1790,13 +1821,16 @@
|
||||
|
||||
it("will render images from oob URLs",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
let view;
|
||||
test_utils.openChatBoxFor(_converse, contact_jid)
|
||||
.then(() => {
|
||||
view = _converse.chatboxviews.get(contact_jid);
|
||||
spyOn(view.model, 'sendMessage').and.callThrough();
|
||||
const base_url = document.URL.split(window.location.pathname)[0];
|
||||
const url = base_url+"/logo/conversejs-filled.svg";
|
||||
@ -1809,16 +1843,16 @@
|
||||
" <x xmlns='jabber:x:oob'><url>"+url+"</url></x>"+
|
||||
"</message>").firstChild;
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg img').length, 2000).then(function () {
|
||||
return test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg img').length, 2000);
|
||||
}).then(function () {
|
||||
const msg = view.el.querySelector('.chat-msg .chat-msg__text');
|
||||
expect(msg.outerHTML).toEqual('<div class="chat-msg__text">Have you seen this funny image?</div>');
|
||||
const media = view.el.querySelector('.chat-msg .chat-msg__media');
|
||||
expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "")).toEqual(
|
||||
'<!-- src/templates/image.html -->'+
|
||||
'<a href="http://localhost:8000/logo/conversejs-filled.svg" target="_blank" rel="noopener">'+
|
||||
'<img class="chat-image img-thumbnail" src="http://localhost:8000/logo/conversejs-filled.svg">'+
|
||||
'</a>');
|
||||
`<!-- src/templates/image.html -->`+
|
||||
`<a href="${window.location.origin}/logo/conversejs-filled.svg" target="_blank" rel="noopener">`+
|
||||
`<img class="chat-image img-thumbnail" src="${window.location.origin}/logo/conversejs-filled.svg">`+
|
||||
`</a>`);
|
||||
done();
|
||||
}).catch(_.partial(console.error, _));
|
||||
}));
|
||||
@ -1828,6 +1862,50 @@
|
||||
|
||||
describe("A Groupchat Message", function () {
|
||||
|
||||
it("is specially marked when you are mentioned in it",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy').then(function () {
|
||||
const view = _converse.chatboxviews.get('lounge@localhost');
|
||||
if (!$(view.el).find('.chat-area').length) { view.renderChatArea(); }
|
||||
const message = 'dummy: Your attention is required';
|
||||
const nick = mock.chatroom_names[0],
|
||||
msg = $msg({
|
||||
from: 'lounge@localhost/'+nick,
|
||||
id: (new Date()).getTime(),
|
||||
to: 'dummy@localhost',
|
||||
type: 'groupchat'
|
||||
}).c('body').t(message).tree();
|
||||
view.model.onMessage(msg);
|
||||
expect($(view.el).find('.chat-msg').hasClass('mentioned')).toBeTruthy();
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
|
||||
it("keeps track whether you are the sender or not",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy').then(function () {
|
||||
const view = _converse.chatboxviews.get('lounge@localhost');
|
||||
const msg = $msg({
|
||||
from: 'lounge@localhost/dummy',
|
||||
id: (new Date()).getTime(),
|
||||
to: 'dummy@localhost',
|
||||
type: 'groupchat'
|
||||
}).c('body').t('I wrote this message!').tree();
|
||||
view.model.onMessage(msg);
|
||||
expect(view.model.messages.last().get('sender')).toBe('me');
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("can be replaced with a correction",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
|
@ -1,8 +1,9 @@
|
||||
(function (root, factory) {
|
||||
define(["jquery", "jasmine", "mock", "test-utils"], factory);
|
||||
} (this, function ($, jasmine, mock, test_utils) {
|
||||
var _ = converse.env._;
|
||||
var $msg = converse.env.$msg;
|
||||
const _ = converse.env._;
|
||||
const $msg = converse.env.$msg;
|
||||
const u = converse.env.utils;
|
||||
|
||||
describe("The Minimized Chats Widget", function () {
|
||||
|
||||
@ -12,13 +13,16 @@
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
|
||||
test_utils.openControlBox();
|
||||
_converse.minimized_chats.toggleview.model.browserStorage._clear();
|
||||
_converse.minimized_chats.initToggle();
|
||||
|
||||
var contact_jid, chatview;
|
||||
contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
let contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
let chatview;
|
||||
test_utils.openChatBoxFor(_converse, contact_jid)
|
||||
.then(() => {
|
||||
chatview = _converse.chatboxviews.get(contact_jid);
|
||||
expect(chatview.model.get('minimized')).toBeFalsy();
|
||||
expect($(_converse.minimized_chats.el).is(':visible')).toBeFalsy();
|
||||
@ -29,7 +33,8 @@
|
||||
expect(_converse.minimized_chats.keys()[0]).toBe(contact_jid);
|
||||
|
||||
contact_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
return test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
}).then(() => {
|
||||
chatview = _converse.chatboxviews.get(contact_jid);
|
||||
expect(chatview.model.get('minimized')).toBeFalsy();
|
||||
chatview.el.querySelector('.toggle-chatbox-button').click();
|
||||
@ -38,6 +43,7 @@
|
||||
expect(_converse.minimized_chats.keys().length).toBe(2);
|
||||
expect(_.includes(_converse.minimized_chats.keys(), contact_jid)).toBeTruthy();
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("can be toggled to hide or show minimized chats",
|
||||
@ -46,25 +52,26 @@
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
|
||||
test_utils.openControlBox();
|
||||
_converse.minimized_chats.toggleview.model.browserStorage._clear();
|
||||
_converse.minimized_chats.initToggle();
|
||||
|
||||
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
var chatview = _converse.chatboxviews.get(contact_jid);
|
||||
expect($(_converse.minimized_chats.el).is(':visible')).toBeFalsy();
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid)
|
||||
.then(() => {
|
||||
const chatview = _converse.chatboxviews.get(contact_jid);
|
||||
expect(u.isVisible(_converse.minimized_chats.el)).toBeFalsy();
|
||||
chatview.model.set({'minimized': true});
|
||||
expect($(_converse.minimized_chats.el).is(':visible')).toBeTruthy();
|
||||
expect(u.isVisible(_converse.minimized_chats.el)).toBeTruthy();
|
||||
expect(_converse.minimized_chats.keys().length).toBe(1);
|
||||
expect(_converse.minimized_chats.keys()[0]).toBe(contact_jid);
|
||||
expect($(_converse.minimized_chats.el.querySelector('.minimized-chats-flyout')).is(':visible')).toBeTruthy();
|
||||
expect(u.isVisible(_converse.minimized_chats.el.querySelector('.minimized-chats-flyout'))).toBeTruthy();
|
||||
expect(_converse.minimized_chats.toggleview.model.get('collapsed')).toBeFalsy();
|
||||
_converse.minimized_chats.el.querySelector('#toggle-minimized-chats').click();
|
||||
|
||||
return test_utils.waitUntil(function () {
|
||||
return $(_converse.minimized_chats.el.querySelector('.minimized-chats-flyout')).is(':visible');
|
||||
}, 500).then(function () {
|
||||
return test_utils.waitUntil(() => u.isVisible(_converse.minimized_chats.el.querySelector('.minimized-chats-flyout')));
|
||||
}).then(() => {
|
||||
expect(_converse.minimized_chats.toggleview.model.get('collapsed')).toBeTruthy();
|
||||
done();
|
||||
});
|
||||
@ -72,20 +79,28 @@
|
||||
|
||||
it("shows the number messages received to minimized chats",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
|
||||
test_utils.openControlBox();
|
||||
_converse.minimized_chats.toggleview.model.browserStorage._clear();
|
||||
_converse.minimized_chats.initToggle();
|
||||
|
||||
var i, contact_jid, chatview, msg;
|
||||
_converse.minimized_chats.toggleview.model.set({'collapsed': true});
|
||||
expect($(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count')).is(':visible')).toBeFalsy();
|
||||
|
||||
const unread_el = _converse.minimized_chats.toggleview.el.querySelector('.unread-message-count');
|
||||
expect(_.isNull(unread_el)).toBe(true);
|
||||
|
||||
for (i=0; i<3; i++) {
|
||||
contact_jid = mock.cur_names[i].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
}
|
||||
return test_utils.waitUntil(() => _converse.chatboxes.length == 4).then(() => {
|
||||
for (i=0; i<3; i++) {
|
||||
chatview = _converse.chatboxviews.get(contact_jid);
|
||||
chatview.model.set({'minimized': true});
|
||||
msg = $msg({
|
||||
@ -136,6 +151,7 @@
|
||||
}).c('inactive', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
|
||||
expect($(_converse.minimized_chats.toggleview.el.querySelector('.unread-message-count')).text()).toBe((i).toString());
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("shows the number messages received to minimized groupchats",
|
||||
|
@ -12,25 +12,26 @@
|
||||
describe("A list of open rooms", function () {
|
||||
|
||||
it("is shown in the \"Rooms\" panel", mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'],
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'],
|
||||
{ allow_bookmarks: false // Makes testing easier, otherwise we
|
||||
// have to mock stanza traffic.
|
||||
},
|
||||
function (done, _converse) {
|
||||
test_utils.openControlBox();
|
||||
var controlbox = _converse.chatboxviews.get('controlbox');
|
||||
|
||||
var list = controlbox.el.querySelector('div.rooms-list-container');
|
||||
const controlbox = _converse.chatboxviews.get('controlbox');
|
||||
let list = controlbox.el.querySelector('div.rooms-list-container');
|
||||
expect(_.includes(list.classList, 'hidden')).toBeTruthy();
|
||||
|
||||
test_utils.openChatRoom(_converse, 'room', 'conference.shakespeare.lit', 'JC');
|
||||
let room_els;
|
||||
|
||||
test_utils.openChatRoom(_converse, 'room', 'conference.shakespeare.lit', 'JC')
|
||||
.then(() => {
|
||||
expect(_.isUndefined(_converse.rooms_list_view)).toBeFalsy();
|
||||
var room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
||||
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
||||
expect(room_els.length).toBe(1);
|
||||
expect(room_els[0].innerText).toBe('room@conference.shakespeare.lit');
|
||||
|
||||
test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy');
|
||||
return test_utils.openChatRoom(_converse, 'lounge', 'localhost', 'dummy');
|
||||
}).then(() => {
|
||||
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
||||
expect(room_els.length).toBe(2);
|
||||
|
||||
@ -50,6 +51,7 @@
|
||||
list = controlbox.el.querySelector('div.rooms-list-container');
|
||||
expect(_.includes(list.classList, 'hidden')).toBeTruthy();
|
||||
done();
|
||||
});
|
||||
}
|
||||
));
|
||||
});
|
||||
@ -57,26 +59,26 @@
|
||||
describe("A groupchat shown in the groupchats list", function () {
|
||||
|
||||
it("is highlighted if its currently open", mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'],
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'],
|
||||
{ whitelisted_plugins: ['converse-roomslist'],
|
||||
allow_bookmarks: false // Makes testing easier, otherwise we
|
||||
// have to mock stanza traffic.
|
||||
}, function (done, _converse) {
|
||||
|
||||
spyOn(_converse, 'isSingleton').and.callFake(function () {
|
||||
return true;
|
||||
});
|
||||
spyOn(_converse, 'isSingleton').and.callFake(() => true);
|
||||
|
||||
let room_els, item;
|
||||
test_utils.openControlBox();
|
||||
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
|
||||
let room_els = _converse.rooms_list_view.el.querySelectorAll(".available-chatroom");
|
||||
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'})
|
||||
.then(() => {
|
||||
room_els = _converse.rooms_list_view.el.querySelectorAll(".available-chatroom");
|
||||
expect(room_els.length).toBe(1);
|
||||
|
||||
let item = room_els[0];
|
||||
item = room_els[0];
|
||||
expect(u.hasClass('open', item)).toBe(true);
|
||||
expect(item.textContent.trim()).toBe('coven@chat.shakespeare.lit');
|
||||
|
||||
_converse.api.rooms.open('balcony@chat.shakespeare.lit', {'nick': 'some1'});
|
||||
return _converse.api.rooms.open('balcony@chat.shakespeare.lit', {'nick': 'some1'});
|
||||
}).then(() => {
|
||||
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
||||
expect(room_els.length).toBe(2);
|
||||
|
||||
@ -85,18 +87,21 @@
|
||||
item = room_els[0];
|
||||
expect(item.textContent.trim()).toBe('balcony@chat.shakespeare.lit');
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("has an info icon which opens a details modal when clicked", mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'],
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'],
|
||||
{ whitelisted_plugins: ['converse-roomslist'],
|
||||
allow_bookmarks: false // Makes testing easier, otherwise we
|
||||
// have to mock stanza traffic.
|
||||
}, function (done, _converse) {
|
||||
|
||||
let view;
|
||||
test_utils.openControlBox();
|
||||
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
|
||||
const view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
|
||||
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'})
|
||||
.then(() => {
|
||||
view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
|
||||
const last_stanza = _.last(_converse.connection.IQ_stanzas).nodeTree;
|
||||
const IQ_id = last_stanza.getAttribute('id');
|
||||
const features_stanza = $iq({
|
||||
@ -127,9 +132,8 @@
|
||||
.c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of occupants'})
|
||||
.c('value').t(0);
|
||||
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
|
||||
|
||||
test_utils.waitUntil(() => view.model.get('connection_status') === converse.ROOMSTATUS.CONNECTING)
|
||||
.then(function () {
|
||||
return test_utils.waitUntil(() => view.model.get('connection_status') === converse.ROOMSTATUS.CONNECTING)
|
||||
}).then(function () {
|
||||
var presence = $pres({
|
||||
to: _converse.connection.jid,
|
||||
from: 'coven@chat.shakespeare.lit/some1',
|
||||
@ -201,12 +205,10 @@
|
||||
},
|
||||
function (done, _converse) {
|
||||
|
||||
spyOn(window, 'confirm').and.callFake(function () {
|
||||
return true;
|
||||
});
|
||||
spyOn(window, 'confirm').and.callFake(() => true);
|
||||
expect(_converse.chatboxes.length).toBe(1);
|
||||
test_utils.openChatRoom(
|
||||
_converse, 'lounge', 'conference.shakespeare.lit', 'JC');
|
||||
test_utils.openChatRoom(_converse, 'lounge', 'conference.shakespeare.lit', 'JC')
|
||||
.then(() => {
|
||||
expect(_converse.chatboxes.length).toBe(2);
|
||||
var room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
||||
expect(room_els.length).toBe(1);
|
||||
@ -218,6 +220,7 @@
|
||||
expect(room_els.length).toBe(0);
|
||||
expect(_converse.chatboxes.length).toBe(1);
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("shows unread messages directed at the user", mock.initConverseWithAsync(
|
||||
|
@ -92,12 +92,14 @@
|
||||
|
||||
it("can be sent without a hint",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
test_utils.createContacts(_converse, 'current', 1);
|
||||
_converse.emit('rosterContactsFetched');
|
||||
|
||||
test_utils.openControlBox();
|
||||
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
|
||||
// XXX: We need to send a presence from the contact, so that we
|
||||
// have a resource, that resource is then queried to see
|
||||
@ -108,9 +110,9 @@
|
||||
'to': 'dummy@localhost'
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]).then(function () {
|
||||
test_utils.openChatBoxFor(_converse, contact_jid)
|
||||
.then(() => test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]))
|
||||
.then(() => {
|
||||
var view = _converse.chatboxviews.get(contact_jid);
|
||||
spyOn(view, 'onMessageSubmitted').and.callThrough();
|
||||
spyOn(_converse.connection, 'send');
|
||||
@ -167,10 +169,12 @@
|
||||
|
||||
it("can be sent with a hint",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
test_utils.createContacts(_converse, 'current', 1);
|
||||
_converse.emit('rosterContactsFetched');
|
||||
|
||||
test_utils.openControlBox();
|
||||
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
|
||||
@ -183,9 +187,9 @@
|
||||
'to': 'dummy@localhost'
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]).then(function () {
|
||||
test_utils.openChatBoxFor(_converse, contact_jid)
|
||||
.then(() => test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]))
|
||||
.then(() => {
|
||||
var view = _converse.chatboxviews.get(contact_jid);
|
||||
var spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
|
||||
spoiler_toggle.click();
|
||||
|
@ -16,22 +16,23 @@
|
||||
|
||||
it("can be used to remove a contact",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
|
||||
let view, show_modal_button, modal;
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const show_modal_button = view.el.querySelector('.show-user-details-modal');
|
||||
return test_utils.waitUntil(() => _converse.chatboxes.length).then(() => {
|
||||
view = _converse.chatboxviews.get(contact_jid);
|
||||
show_modal_button = view.el.querySelector('.show-user-details-modal');
|
||||
expect(u.isVisible(show_modal_button)).toBeTruthy();
|
||||
show_modal_button.click();
|
||||
const modal = view.user_details_modal;
|
||||
test_utils.waitUntil(() => u.isVisible(modal.el), 1000)
|
||||
.then(function () {
|
||||
modal = view.user_details_modal;
|
||||
return test_utils.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||
}).then(function () {
|
||||
spyOn(window, 'confirm').and.returnValue(true);
|
||||
spyOn(view.model.contact, 'removeFromRoster').and.callFake(function (callback) {
|
||||
callback();
|
||||
@ -57,16 +58,17 @@
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
|
||||
let view, modal;
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
test_utils.openChatBoxFor(_converse, contact_jid)
|
||||
.then(() => {
|
||||
view = _converse.chatboxviews.get(contact_jid);
|
||||
const show_modal_button = view.el.querySelector('.show-user-details-modal');
|
||||
expect(u.isVisible(show_modal_button)).toBeTruthy();
|
||||
show_modal_button.click();
|
||||
const modal = view.user_details_modal;
|
||||
test_utils.waitUntil(() => u.isVisible(modal.el), 2000)
|
||||
.then(function () {
|
||||
modal = view.user_details_modal;
|
||||
return test_utils.waitUntil(() => u.isVisible(modal.el), 2000);
|
||||
}).then(function () {
|
||||
spyOn(window, 'confirm').and.returnValue(true);
|
||||
spyOn(view.model.contact, 'removeFromRoster').and.callFake(function (callback, errback) {
|
||||
errback();
|
||||
|
@ -69,12 +69,7 @@
|
||||
Strophe.LogLevel.WARN
|
||||
);
|
||||
}
|
||||
Promise.all([
|
||||
_converse.api.waitUntil('rosterContactsFetched'),
|
||||
_converse.api.waitUntil('chatBoxesFetched')
|
||||
]).then(() => {
|
||||
_converse.api.chats.open(jid);
|
||||
});
|
||||
}
|
||||
_converse.router.route('converse/chat?jid=:jid', openChat);
|
||||
|
||||
@ -485,7 +480,7 @@
|
||||
if (attrs.type === 'groupchat') {
|
||||
attrs.from = stanza.getAttribute('from');
|
||||
attrs.nick = Strophe.unescapeNode(Strophe.getResourceFromJid(attrs.from));
|
||||
if (attrs.from === this.get('nick')) {
|
||||
if (Strophe.getResourceFromJid(attrs.from) === this.get('nick')) {
|
||||
attrs.sender = 'me';
|
||||
} else {
|
||||
attrs.sender = 'them';
|
||||
@ -876,6 +871,11 @@
|
||||
|
||||
/************************ BEGIN API ************************/
|
||||
_.extend(_converse.api, {
|
||||
/**
|
||||
* The "chats" grouping (used for one-on-one chats)
|
||||
*
|
||||
* @namespace
|
||||
*/
|
||||
'chats': {
|
||||
'create' (jids, attrs) {
|
||||
if (_.isUndefined(jids)) {
|
||||
@ -885,7 +885,6 @@
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_.isString(jids)) {
|
||||
if (attrs && !_.get(attrs, 'fullname')) {
|
||||
attrs.fullname = _.get(_converse.api.contacts.get(jids), 'attributes.fullname');
|
||||
@ -902,17 +901,80 @@
|
||||
return _converse.chatboxes.getChatBox(jid, attrs, true).trigger('show');
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Opens a new one-on-one chat.
|
||||
*
|
||||
* @function
|
||||
*
|
||||
* @param {String|string[]} name - e.g. 'buddy@example.com' or ['buddy1@example.com', 'buddy2@example.com']
|
||||
* @returns {Promise} Promise which resolves with the Backbone.Model representing the chat.
|
||||
*
|
||||
* @example
|
||||
* // To open a single chat, provide the JID of the contact you're chatting with in that chat:
|
||||
* converse.plugins.add('myplugin', {
|
||||
* initialize: function() {
|
||||
* var _converse = this._converse;
|
||||
* // Note, buddy@example.org must be in your contacts roster!
|
||||
* _converse.api.chats.open('buddy@example.com').then((chat) => {
|
||||
* // Now you can do something with the chat model
|
||||
* });
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* @example
|
||||
* // To open an array of chats, provide an array of JIDs:
|
||||
* converse.plugins.add('myplugin', {
|
||||
* initialize: function () {
|
||||
* var _converse = this._converse;
|
||||
* // Note, these users must first be in your contacts roster!
|
||||
* _converse.api.chats.open(['buddy1@example.com', 'buddy2@example.com']).then((chats) => {
|
||||
* // Now you can do something with the chat models
|
||||
* });
|
||||
* }
|
||||
* });
|
||||
*
|
||||
*/
|
||||
'open' (jids, attrs) {
|
||||
return new Promise((resolve, reject) => {
|
||||
Promise.all([
|
||||
_converse.api.waitUntil('rosterContactsFetched'),
|
||||
_converse.api.waitUntil('chatBoxesFetched')
|
||||
]).then(() => {
|
||||
if (_.isUndefined(jids)) {
|
||||
_converse.log("chats.open: You need to provide at least one JID", Strophe.LogLevel.ERROR);
|
||||
return null;
|
||||
const err_msg = "chats.open: You need to provide at least one JID";
|
||||
_converse.log(err_msg, Strophe.LogLevel.ERROR);
|
||||
reject(new Error(err_msg));
|
||||
} else if (_.isString(jids)) {
|
||||
const chatbox = _converse.api.chats.create(jids, attrs);
|
||||
chatbox.trigger('show');
|
||||
return chatbox;
|
||||
resolve(_converse.api.chats.create(jids, attrs).trigger('show'));
|
||||
} else {
|
||||
resolve(_.map(jids, (jid) => _converse.api.chats.create(jid, attrs).trigger('show')));
|
||||
}
|
||||
return _.map(jids, (jid) => _converse.api.chats.create(jid, attrs).trigger('show'));
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a chat model. The chat should already be open.
|
||||
*
|
||||
* @function
|
||||
*
|
||||
* @param {String|string[]} name - e.g. 'buddy@example.com' or ['buddy1@example.com', 'buddy2@example.com']
|
||||
* @returns {Backbone.Model}
|
||||
*
|
||||
* @example
|
||||
* // To return a single chat, provide the JID of the contact you're chatting with in that chat:
|
||||
* const model = _converse.api.chats.get('buddy@example.com');
|
||||
*
|
||||
* @example
|
||||
* // To return an array of chats, provide an array of JIDs:
|
||||
* const models = _converse.api.chats.get(['buddy1@example.com', 'buddy2@example.com']);
|
||||
*
|
||||
* @example
|
||||
* // To return all open chats, call the method without any parameters::
|
||||
* const models = _converse.api.chats.get();
|
||||
*
|
||||
*/
|
||||
'get' (jids) {
|
||||
if (_.isUndefined(jids)) {
|
||||
const result = [];
|
||||
|
@ -888,6 +888,9 @@
|
||||
const textarea = this.el.querySelector('.chat-textarea'),
|
||||
message = textarea.value;
|
||||
|
||||
if (!message.replace(/\s/g, '').length) {
|
||||
return;
|
||||
}
|
||||
let spoiler_hint;
|
||||
if (this.model.get('composing_spoiler')) {
|
||||
const hint_el = this.el.querySelector('form.sendXMPPMessage input.spoiler-hint');
|
||||
@ -901,10 +904,8 @@
|
||||
event.initEvent('input', true, true);
|
||||
textarea.dispatchEvent(event);
|
||||
|
||||
if (message !== '') {
|
||||
this.onMessageSubmitted(message, spoiler_hint);
|
||||
_converse.emit('messageSend', message);
|
||||
}
|
||||
this.setChatState(_converse.ACTIVE);
|
||||
},
|
||||
|
||||
|
@ -99,6 +99,11 @@
|
||||
'converse-vcard'
|
||||
];
|
||||
|
||||
// Setting wait to 59 instead of 60 to avoid timing conflicts with the
|
||||
// webserver, which is often also set to 60 and might therefore sometimes
|
||||
// return a 504 error page instead of passing through to the BOSH proxy.
|
||||
const BOSH_WAIT = 59;
|
||||
|
||||
// Make converse pluggable
|
||||
pluggable.enable(_converse, '_converse', 'pluggable');
|
||||
|
||||
@ -1026,7 +1031,7 @@
|
||||
if (!this.connection.reconnecting) {
|
||||
this.connection.reset();
|
||||
}
|
||||
this.connection.connect(this.jid.toLowerCase(), null, this.onConnectStatusChanged);
|
||||
this.connection.connect(this.jid.toLowerCase(), null, this.onConnectStatusChanged, BOSH_WAIT);
|
||||
} else if (this.authentication === _converse.LOGIN) {
|
||||
const password = _.isNil(credentials) ? (_converse.connection.pass || this.password) : credentials.password;
|
||||
if (!password) {
|
||||
@ -1047,7 +1052,7 @@
|
||||
if (!this.connection.reconnecting) {
|
||||
this.connection.reset();
|
||||
}
|
||||
this.connection.connect(this.jid, password, this.onConnectStatusChanged);
|
||||
this.connection.connect(this.jid, password, this.onConnectStatusChanged, BOSH_WAIT);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -296,6 +296,7 @@
|
||||
if (from !== null) {
|
||||
iqresult.attrs({'to': from});
|
||||
}
|
||||
iqresult.c('query', attrs);
|
||||
_.each(plugin._identities, (identity) => {
|
||||
const attrs = {
|
||||
'category': identity.category,
|
||||
|
@ -30,11 +30,10 @@
|
||||
if (!_.isArray(_converse.auto_join_rooms) && !_.isArray(_converse.auto_join_private_chats)) {
|
||||
throw new Error("converse-embedded: auto_join_rooms must be an Array");
|
||||
}
|
||||
if (_converse.auto_join_rooms.length !== 1 && _converse.auto_join_private_chats.length !== 1) {
|
||||
if (_converse.auto_join_rooms.length > 1 && _converse.auto_join_private_chats.length > 1) {
|
||||
throw new Error("converse-embedded: It doesn't make "+
|
||||
"sense to have the auto_join_rooms setting to zero or "+
|
||||
"more then one, since only one chat room can be open "+
|
||||
"at any time.");
|
||||
"sense to have the auto_join_rooms setting more then one, "+
|
||||
"since only one chat room can be open at any time.");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -550,16 +550,7 @@
|
||||
|
||||
this.model.occupants.on('add', this.showJoinNotification, this);
|
||||
this.model.occupants.on('remove', this.showLeaveNotification, this);
|
||||
this.model.occupants.on('change:show', (occupant) => {
|
||||
if (!occupant.isMember() || _.includes(occupant.get('states'), '303')) {
|
||||
return;
|
||||
}
|
||||
if (occupant.get('show') === 'offline') {
|
||||
this.showLeaveNotification(occupant);
|
||||
} else if (occupant.get('show') === 'online') {
|
||||
this.showJoinNotification(occupant);
|
||||
}
|
||||
});
|
||||
this.model.occupants.on('change:show', this.showJoinOrLeaveNotification, this);
|
||||
|
||||
this.createEmojiPicker();
|
||||
this.createOccupantsView();
|
||||
@ -570,8 +561,7 @@
|
||||
const handler = () => {
|
||||
if (!u.isPersistableModel(this.model)) {
|
||||
// Happens during tests, nothing to do if this
|
||||
// is a hanging chatbox (i.e. not in the
|
||||
// collection anymore).
|
||||
// is a hanging chatbox (i.e. not in the collection anymore).
|
||||
return;
|
||||
}
|
||||
this.populateAndJoin();
|
||||
@ -1383,6 +1373,17 @@
|
||||
}
|
||||
},
|
||||
|
||||
showJoinOrLeaveNotification (occupant) {
|
||||
if (!occupant.isMember() || _.includes(occupant.get('states'), '303')) {
|
||||
return;
|
||||
}
|
||||
if (occupant.get('show') === 'offline') {
|
||||
this.showLeaveNotification(occupant);
|
||||
} else if (occupant.get('show') === 'online') {
|
||||
this.showJoinNotification(occupant);
|
||||
}
|
||||
},
|
||||
|
||||
showJoinNotification (occupant) {
|
||||
if (this.model.get('connection_status') !== converse.ROOMSTATUS.ENTERED) {
|
||||
return;
|
||||
@ -1429,11 +1430,11 @@
|
||||
showLeaveNotification (occupant) {
|
||||
const nick = occupant.get('nick'),
|
||||
stat = occupant.get('status'),
|
||||
last_el = this.content.lastElementChild,
|
||||
last_msg_date = last_el.getAttribute('data-isodate');
|
||||
last_el = this.content.lastElementChild;
|
||||
|
||||
if (_.includes(_.get(last_el, 'classList', []), 'chat-info') &&
|
||||
moment(last_msg_date).isSame(new Date(), "day") &&
|
||||
if (last_el &&
|
||||
_.includes(_.get(last_el, 'classList', []), 'chat-info') &&
|
||||
moment(last_el.getAttribute('data-isodate')).isSame(new Date(), "day") &&
|
||||
_.get(last_el, 'dataset', {}).join === `"${nick}"`) {
|
||||
|
||||
let message;
|
||||
@ -1462,7 +1463,8 @@
|
||||
'extra_classes': 'chat-event',
|
||||
'data': `data-leave="${nick}"`
|
||||
}
|
||||
if (_.includes(_.get(last_el, 'classList', []), 'chat-info') &&
|
||||
if (last_el &&
|
||||
_.includes(_.get(last_el, 'classList', []), 'chat-info') &&
|
||||
_.get(last_el, 'dataset', {}).leavejoin === `"${nick}"`) {
|
||||
|
||||
last_el.outerHTML = tpl_info(data);
|
||||
|
@ -1254,14 +1254,23 @@
|
||||
}
|
||||
return _.map(jids, _.partial(createChatRoom, _, attrs));
|
||||
},
|
||||
|
||||
'open' (jids, attrs) {
|
||||
return new Promise((resolve, reject) => {
|
||||
_converse.api.waitUntil('chatBoxesFetched').then(() => {
|
||||
if (_.isUndefined(jids)) {
|
||||
throw new TypeError('rooms.open: You need to provide at least one JID');
|
||||
const err_msg = 'rooms.open: You need to provide at least one JID';
|
||||
_converse.log(err_msg, Strophe.LogLevel.ERROR);
|
||||
reject(new TypeError(err_msg));
|
||||
} else if (_.isString(jids)) {
|
||||
return _converse.api.rooms.create(jids, attrs).trigger('show');
|
||||
resolve(_converse.api.rooms.create(jids, attrs).trigger('show'));
|
||||
} else {
|
||||
resolve(_.map(jids, (jid) => _converse.api.rooms.create(jid, attrs).trigger('show')));
|
||||
}
|
||||
return _.map(jids, (jid) => _converse.api.rooms.create(jid, attrs).trigger('show'));
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
'get' (jids, attrs, create) {
|
||||
if (_.isString(attrs)) {
|
||||
attrs = {'nick': attrs};
|
||||
|
@ -148,8 +148,13 @@
|
||||
);
|
||||
xhr.onload = function () {
|
||||
if (xhr.status >= 200 && xhr.status < 400) {
|
||||
jed_instance = new Jed(window.JSON.parse(xhr.responseText));
|
||||
try {
|
||||
const data = window.JSON.parse(xhr.responseText);
|
||||
jed_instance = new Jed(data);
|
||||
resolve();
|
||||
} catch (e) {
|
||||
xhr.onerror(e);
|
||||
}
|
||||
} else {
|
||||
xhr.onerror();
|
||||
}
|
||||
|
@ -98,8 +98,9 @@
|
||||
return views;
|
||||
};
|
||||
|
||||
utils.openChatBoxFor = function (converse, jid) {
|
||||
return converse.roster.get(jid).trigger("open");
|
||||
utils.openChatBoxFor = function (_converse, jid) {
|
||||
_converse.roster.get(jid).trigger("open");
|
||||
return utils.waitUntil(() => _converse.chatboxviews.get(jid));
|
||||
};
|
||||
|
||||
utils.openChatRoomViaModal = function (_converse, jid, nick) {
|
||||
@ -121,14 +122,14 @@
|
||||
};
|
||||
|
||||
utils.openChatRoom = function (_converse, room, server, nick) {
|
||||
_converse.api.rooms.open(`${room}@${server}`);
|
||||
return _converse.api.rooms.open(`${room}@${server}`);
|
||||
};
|
||||
|
||||
utils.openAndEnterChatRoom = function (_converse, room, server, nick) {
|
||||
let last_stanza;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
_converse.api.rooms.open(`${room}@${server}`);
|
||||
return new Promise((resolve, reject) => {
|
||||
return _converse.api.rooms.open(`${room}@${server}`).then(() => {
|
||||
const view = _converse.chatboxviews.get((room+'@'+server).toLowerCase());
|
||||
// We pretend this is a new room, so no disco info is returned.
|
||||
let last_stanza = _.last(_converse.connection.IQ_stanzas).nodeTree;
|
||||
@ -178,7 +179,7 @@
|
||||
.c('status').attrs({code:'110'});
|
||||
_converse.connection._dataRecv(utils.createRequest(presence));
|
||||
resolve();
|
||||
|
||||
}).catch(_.partial(console.error, _));
|
||||
}).catch(_.partial(console.error, _));
|
||||
}).catch(_.partial(console.error, _));
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user