// Converse.js (A browser based XMPP chat client) // http://conversejs.org // // This is the utilities module. // // Copyright (c) 2012-2017, Jan-Carel Brand // Licensed under the Mozilla Public License (MPLv2) // /*global define, escape, Jed */ (function (root, factory) { define(["converse-core", "utils/core"], factory); }(this, function (converse, u) { "use strict"; const { Strophe, sizzle, _ } = converse.env; u.computeAffiliationsDelta = function computeAffiliationsDelta (exclude_existing, remove_absentees, new_list, old_list) { /* Given two lists of objects with 'jid', 'affiliation' and * 'reason' properties, return a new list containing * those objects that are new, changed or removed * (depending on the 'remove_absentees' boolean). * * The affiliations for new and changed members stay the * same, for removed members, the affiliation is set to 'none'. * * The 'reason' property is not taken into account when * comparing whether affiliations have been changed. * * Parameters: * (Boolean) exclude_existing: Indicates whether JIDs from * the new list which are also in the old list * (regardless of affiliation) should be excluded * from the delta. One reason to do this * would be when you want to add a JID only if it * doesn't have *any* existing affiliation at all. * (Boolean) remove_absentees: Indicates whether JIDs * from the old list which are not in the new list * should be considered removed and therefore be * included in the delta with affiliation set * to 'none'. * (Array) new_list: Array containing the new affiliations * (Array) old_list: Array containing the old affiliations */ const new_jids = _.map(new_list, 'jid'); const old_jids = _.map(old_list, 'jid'); // Get the new affiliations let delta = _.map( _.difference(new_jids, old_jids), (jid) => new_list[_.indexOf(new_jids, jid)] ); if (!exclude_existing) { // Get the changed affiliations delta = delta.concat(_.filter(new_list, function (item) { const idx = _.indexOf(old_jids, item.jid); if (idx >= 0) { return item.affiliation !== old_list[idx].affiliation; } return false; })); } if (remove_absentees) { // Get the removed affiliations delta = delta.concat( _.map( _.difference(old_jids, new_jids), (jid) => ({'jid': jid, 'affiliation': 'none'}) ) ); } return delta; }; u.parseMemberListIQ = function parseMemberListIQ (iq) { /* Given an IQ stanza with a member list, create an array of member objects. */ return _.map( sizzle(`query[xmlns="${Strophe.NS.MUC_ADMIN}"] item`, iq), (item) => { const data = { 'affiliation': item.getAttribute('affiliation'), } const jid = item.getAttribute('jid'); if (u.isValidJID(jid)) { data['jid'] = jid; } else { // XXX: Prosody sends nick for the jid attribute value // Perhaps for anonymous room? data['nick'] = jid; } const nick = item.getAttribute('nick'); if (nick) { data['nick'] = nick; } const role = item.getAttribute('role'); if (role) { data['role'] = nick; } return data; } ); }; u.marshallAffiliationIQs = function marshallAffiliationIQs () { /* Marshall a list of IQ stanzas into a map of JIDs and * affiliations. * * Parameters: * Any amount of XMLElement objects, representing the IQ * stanzas. */ return _.flatMap(arguments[0], u.parseMemberListIQ); } }));