diff --git a/CHANGES.md b/CHANGES.md index 11cea1342..af41cd1e9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,6 @@ # Changelog -## 3.3.4 (Unreleased) +## 3.3.4 (2018-03-05) - Don't show bookmark toggles when PEP bookmarking not supported by the XMPP server. - Emojis are now sent in unicode instead of short names (also in MUCs) diff --git a/COPYRIGHT b/COPYRIGHT index 85eb72a2b..68543da11 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -2,7 +2,7 @@ * * An XMPP chat client that runs in the browser. * - * Version: 3.3.3 + * Version: 3.3.4 * * Copyright: JC Brand 2012-2017 * Except for 3rd party dependencies. diff --git a/Makefile b/Makefile index 8e908f4a3..a5f1db023 100644 --- a/Makefile +++ b/Makefile @@ -71,7 +71,7 @@ serve_bg: dev ######################################################################## ## Translation machinery -GETTEXT = xgettext --language="JavaScript" --keyword=__ --keyword=___ --from-code=UTF-8 --output=locale/converse.pot dist/converse-no-dependencies.js --package-name=Converse.js --copyright-holder="Jan-Carel Brand" --package-version=3.3.3 -c +GETTEXT = xgettext --language="JavaScript" --keyword=__ --keyword=___ --from-code=UTF-8 --output=locale/converse.pot dist/converse-no-dependencies.js --package-name=Converse.js --copyright-holder="Jan-Carel Brand" --package-version=3.3.4 -c .PHONY: pot pot: dist/converse-no-dependencies.js diff --git a/dist/converse-muc-embedded.js b/dist/converse-muc-embedded.js index 844cf3ef6..85bee0da9 100644 --- a/dist/converse-muc-embedded.js +++ b/dist/converse-muc-embedded.js @@ -2,7 +2,7 @@ * * An XMPP chat client that runs in the browser. * - * Version: 3.3.3 + * Version: 3.3.4 */ /* jshint ignore:start */ @@ -22063,6 +22063,17 @@ define('lodash.fp',['lodash', 'lodash.converter'], function (_, lodashConverter) return fp; }); +function CustomEvent ( event, params ) { + params = params || { bubbles: false, cancelable: false, detail: undefined }; + var evt = document.createEvent( 'CustomEvent' ); + evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail ); + return evt; +} +if ( typeof window.CustomEvent !== "function" ) { + CustomEvent.prototype = window.Event.prototype; + window.CustomEvent = CustomEvent; +} + if (!String.prototype.includes) { String.prototype.includes = function(search, start) { 'use strict'; @@ -27679,6 +27690,97 @@ return af; }))); +//! moment.js locale configuration +//! locale : Bulgarian [bg] +//! author : Krasen Borisov : https://github.com/kraz + +;(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' + && typeof require === 'function' ? factory(require('../moment')) : + typeof define === 'function' && define.amd ? define('moment/locale/bg',['../moment'], factory) : + factory(global.moment) +}(this, (function (moment) { 'use strict'; + + +var bg = moment.defineLocale('bg', { + months : 'януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември'.split('_'), + monthsShort : 'янр_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек'.split('_'), + weekdays : 'неделя_понеделник_вторник_сряда_четвъртък_петък_събота'.split('_'), + weekdaysShort : 'нед_пон_вто_сря_чет_пет_съб'.split('_'), + weekdaysMin : 'нд_пн_вт_ср_чт_пт_сб'.split('_'), + longDateFormat : { + LT : 'H:mm', + LTS : 'H:mm:ss', + L : 'D.MM.YYYY', + LL : 'D MMMM YYYY', + LLL : 'D MMMM YYYY H:mm', + LLLL : 'dddd, D MMMM YYYY H:mm' + }, + calendar : { + sameDay : '[Днес в] LT', + nextDay : '[Утре в] LT', + nextWeek : 'dddd [в] LT', + lastDay : '[Вчера в] LT', + lastWeek : function () { + switch (this.day()) { + case 0: + case 3: + case 6: + return '[В изминалата] dddd [в] LT'; + case 1: + case 2: + case 4: + case 5: + return '[В изминалия] dddd [в] LT'; + } + }, + sameElse : 'L' + }, + relativeTime : { + future : 'след %s', + past : 'преди %s', + s : 'няколко секунди', + m : 'минута', + mm : '%d минути', + h : 'час', + hh : '%d часа', + d : 'ден', + dd : '%d дни', + M : 'месец', + MM : '%d месеца', + y : 'година', + yy : '%d години' + }, + dayOfMonthOrdinalParse: /\d{1,2}-(ев|ен|ти|ви|ри|ми)/, + ordinal : function (number) { + var lastDigit = number % 10, + last2Digits = number % 100; + if (number === 0) { + return number + '-ев'; + } else if (last2Digits === 0) { + return number + '-ен'; + } else if (last2Digits > 10 && last2Digits < 20) { + return number + '-ти'; + } else if (lastDigit === 1) { + return number + '-ви'; + } else if (lastDigit === 2) { + return number + '-ри'; + } else if (lastDigit === 7 || lastDigit === 8) { + return number + '-ми'; + } else { + return number + '-ти'; + } + }, + week : { + dow : 1, // Monday is the first day of the week. + doy : 7 // The week that contains Jan 1st is the first week of the year. + } +}); + +return bg; + +}))); + //! moment.js locale configuration //! locale : Catalan [ca] //! author : Juan G. Hurtado : https://github.com/juanghurtado @@ -28968,6 +29070,97 @@ return ru; }))); +//! moment.js locale configuration +//! locale : Turkish [tr] +//! authors : Erhan Gundogan : https://github.com/erhangundogan, +//! Burak Yiğit Kaya: https://github.com/BYK + +;(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' + && typeof require === 'function' ? factory(require('../moment')) : + typeof define === 'function' && define.amd ? define('moment/locale/tr',['../moment'], factory) : + factory(global.moment) +}(this, (function (moment) { 'use strict'; + + +var suffixes = { + 1: '\'inci', + 5: '\'inci', + 8: '\'inci', + 70: '\'inci', + 80: '\'inci', + 2: '\'nci', + 7: '\'nci', + 20: '\'nci', + 50: '\'nci', + 3: '\'üncü', + 4: '\'üncü', + 100: '\'üncü', + 6: '\'ncı', + 9: '\'uncu', + 10: '\'uncu', + 30: '\'uncu', + 60: '\'ıncı', + 90: '\'ıncı' +}; + +var tr = moment.defineLocale('tr', { + months : 'Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık'.split('_'), + monthsShort : 'Oca_Şub_Mar_Nis_May_Haz_Tem_Ağu_Eyl_Eki_Kas_Ara'.split('_'), + weekdays : 'Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi'.split('_'), + weekdaysShort : 'Paz_Pts_Sal_Çar_Per_Cum_Cts'.split('_'), + weekdaysMin : 'Pz_Pt_Sa_Ça_Pe_Cu_Ct'.split('_'), + longDateFormat : { + LT : 'HH:mm', + LTS : 'HH:mm:ss', + L : 'DD.MM.YYYY', + LL : 'D MMMM YYYY', + LLL : 'D MMMM YYYY HH:mm', + LLLL : 'dddd, D MMMM YYYY HH:mm' + }, + calendar : { + sameDay : '[bugün saat] LT', + nextDay : '[yarın saat] LT', + nextWeek : '[haftaya] dddd [saat] LT', + lastDay : '[dün] LT', + lastWeek : '[geçen hafta] dddd [saat] LT', + sameElse : 'L' + }, + relativeTime : { + future : '%s sonra', + past : '%s önce', + s : 'birkaç saniye', + m : 'bir dakika', + mm : '%d dakika', + h : 'bir saat', + hh : '%d saat', + d : 'bir gün', + dd : '%d gün', + M : 'bir ay', + MM : '%d ay', + y : 'bir yıl', + yy : '%d yıl' + }, + dayOfMonthOrdinalParse: /\d{1,2}'(inci|nci|üncü|ncı|uncu|ıncı)/, + ordinal : function (number) { + if (number === 0) { // special case for zero + return number + '\'ıncı'; + } + var a = number % 10, + b = number % 100 - a, + c = number >= 100 ? 100 : null; + return number + (suffixes[a] || suffixes[b] || suffixes[c]); + }, + week : { + dow : 1, // Monday is the first day of the week. + doy : 7 // The week that contains Jan 1st is the first week of the year. + } +}); + +return tr; + +}))); + //! moment.js locale configuration //! locale : Ukrainian [uk] //! author : zemlanin : https://github.com/zemlanin @@ -29348,7 +29541,7 @@ return zhTw; /*global define */ (function (root, factory) { - define('i18n',["es6-promise", "jed", "lodash.noconflict", "moment", 'moment/locale/af', 'moment/locale/ca', 'moment/locale/de', 'moment/locale/es', 'moment/locale/fr', 'moment/locale/he', 'moment/locale/hu', 'moment/locale/id', 'moment/locale/it', 'moment/locale/ja', 'moment/locale/nb', 'moment/locale/nl', 'moment/locale/pl', 'moment/locale/pt-br', 'moment/locale/ru', 'moment/locale/uk', 'moment/locale/zh-cn', 'moment/locale/zh-tw'], factory); + define('i18n',["es6-promise", "jed", "lodash.noconflict", "moment", 'moment/locale/af', 'moment/locale/bg', 'moment/locale/ca', 'moment/locale/de', 'moment/locale/es', 'moment/locale/fr', 'moment/locale/he', 'moment/locale/hu', 'moment/locale/id', 'moment/locale/it', 'moment/locale/ja', 'moment/locale/nb', 'moment/locale/nl', 'moment/locale/pl', 'moment/locale/pt-br', 'moment/locale/ru', 'moment/locale/tr', 'moment/locale/uk', 'moment/locale/zh-cn', 'moment/locale/zh-tw'], factory); })(this, function (Promise, Jed, _, moment) { 'use strict'; @@ -36494,6 +36687,42 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat return promise; }; + u.interpolate = function (string, o) { + return string.replace(/{{{([^{}]*)}}}/g, function (a, b) { + var r = o[b]; + return typeof r === 'string' || typeof r === 'number' ? r : a; + }); + }; + + u.onMultipleEvents = function () { + var events = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + var callback = arguments.length > 1 ? arguments[1] : undefined; + + /* Call the callback once all the events have been triggered + * + * Parameters: + * (Array) events: An array of objects, with keys `object` and + * `event`, representing the event name and the object it's + * triggered upon. + * (Function) callback: The function to call once all events have + * been triggered. + */ + var triggered = []; + + function handler(result) { + triggered.push(result); + + if (events.length === triggered.length) { + callback(triggered); + triggered = []; + } + } + + _.each(events, function (map) { + return map.object.on(map.event, handler); + }); + }; + u.safeSave = function (model, attributes) { if (u.isPersistableModel(model)) { model.save(attributes); @@ -36503,7 +36732,11 @@ function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterat }; u.isVisible = function (el) { - // XXX: Taken from jQuery's "visible" implementation + if (u.hasClass('hidden', el)) { + return false; + } // XXX: Taken from jQuery's "visible" implementation + + return el.offsetWidth > 0 || el.offsetHeight > 0 || el.getClientRects().length > 0; }; @@ -39196,7 +39429,7 @@ return Backbone.BrowserStorage; /*global Backbone, define, window, JSON */ (function (root, factory) { define('converse-core',["sizzle", "es6-promise", "lodash.noconflict", "lodash.fp", "polyfill", "i18n", "utils", "moment", "strophe", "pluggable", "backbone.noconflict", "backbone.nativeview", "backbone.browserStorage"], factory); -})(this, function (sizzle, Promise, _, f, polyfill, i18n, utils, moment, Strophe, pluggable, Backbone) { +})(this, function (sizzle, Promise, _, f, polyfill, i18n, u, moment, Strophe, pluggable, Backbone) { /* Cannot use this due to Safari bug. * See https://github.com/jcbrand/converse.js/issues/196 */ @@ -39368,7 +39601,7 @@ return Backbone.BrowserStorage; /* Private function, used to add a new promise to the ones already * available via the `waitUntil` api method. */ - _converse.promises[promise] = utils.getResolveablePromise(); + _converse.promises[promise] = u.getResolveablePromise(); } _converse.emit = function (name) { @@ -39390,7 +39623,7 @@ return Backbone.BrowserStorage; var _this = this; settings = !_.isUndefined(settings) ? settings : {}; - var init_promise = utils.getResolveablePromise(); + var init_promise = u.getResolveablePromise(); _.each(PROMISES, addPromise); @@ -39474,7 +39707,7 @@ return Backbone.BrowserStorage; jid: undefined, keepalive: true, locales_url: 'locale/{{{locale}}}/LC_MESSAGES/converse.json', - locales: ['af', 'ca', 'de', 'es', 'en', 'fr', 'he', 'hu', 'id', 'it', 'ja', 'nb', 'nl', 'pl', 'pt_BR', 'ru', 'uk', 'zh_CN', 'zh_TW'], + locales: ['af', 'bg', 'ca', 'de', 'es', 'en', 'fr', 'he', 'hu', 'id', 'it', 'ja', 'nb', 'nl', 'pl', 'pt_BR', 'ru', 'tr', 'uk', 'zh_CN', 'zh_TW'], message_carbons: true, message_storage: 'session', password: undefined, @@ -39821,7 +40054,7 @@ return Backbone.BrowserStorage; this.initStatus = function () { return new Promise(function (resolve, reject) { - var promise = new utils.getResolveablePromise(); + var promise = new u.getResolveablePromise(); _this.xmppstatus = new _this.XMPPStatus(); var id = b64_sha1("converse.xmppstatus-".concat(_converse.bare_jid)); _this.xmppstatus.id = id; // Appears to be necessary for backbone.browserStorage @@ -39866,7 +40099,10 @@ return Backbone.BrowserStorage; _converse.connection.disconnect(); } else { _converse._tearDown(); - } + } // Recreate all the promises + + + _.each(_.keys(_converse.promises), addPromise); _converse.emit('logout'); }; @@ -40117,9 +40353,9 @@ return Backbone.BrowserStorage; initialize: function initialize(attributes) { var _this3 = this; - var jid = attributes.jid; - var bare_jid = Strophe.getBareJidFromJid(jid).toLowerCase(); - var resource = Strophe.getResourceFromJid(jid); + var jid = attributes.jid, + bare_jid = Strophe.getBareJidFromJid(jid).toLowerCase(), + resource = Strophe.getResourceFromJid(jid); attributes.jid = bare_jid; this.set(_.assignIn({ 'fullname': bare_jid, @@ -40392,7 +40628,7 @@ return Backbone.BrowserStorage; return true; }, isSelf: function isSelf(jid) { - return utils.isSameBareJID(jid, _converse.connection.jid); + return u.isSameBareJID(jid, _converse.connection.jid); }, addAndSubscribe: function addAndSubscribe(jid, name, groups, message, attributes) { /* Add a roster contact and then once we have confirmation from @@ -40796,7 +41032,7 @@ return Backbone.BrowserStorage; constructPresence: function constructPresence(type, status_message) { var presence; type = _.isString(type) ? type : this.get('status') || _converse.default_state; - status_message = _.isString(status_message) ? status_message : undefined; // Most of these presence types are actually not explicitly sent, + status_message = _.isString(status_message) ? status_message : this.get('status_message'); // Most of these presence types are actually not explicitly sent, // but I add all of them here for reference and future proofing. if (type === 'unavailable' || type === 'probe' || type === 'error' || type === 'unsubscribe' || type === 'unsubscribed' || type === 'subscribe' || type === 'subscribed') { @@ -41165,7 +41401,7 @@ return Backbone.BrowserStorage; } else if (_.isUndefined(i18n)) { finishInitialization(); } else { - i18n.fetchTranslations(_converse.locale, _converse.locales, _.template(_converse.locales_url)({ + i18n.fetchTranslations(_converse.locale, _converse.locales, u.interpolate(_converse.locales_url, { 'locale': _converse.locale })).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL)).then(finishInitialization).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL)); } @@ -41233,9 +41469,9 @@ return Backbone.BrowserStorage; }, 'settings': { 'update': function update(settings) { - utils.merge(_converse.default_settings, settings); - utils.merge(_converse, settings); - utils.applyUserSettings(_converse, settings, _converse.user_settings); + u.merge(_converse.default_settings, settings); + u.merge(_converse, settings); + u.applyUserSettings(_converse, settings, _converse.user_settings); }, 'get': function get(key) { if (_.includes(_.keys(_converse.default_settings), key)) { @@ -41359,10 +41595,10 @@ return Backbone.BrowserStorage; 'b64_sha1': b64_sha1, 'moment': moment, 'sizzle': sizzle, - 'utils': utils + 'utils': u } }; - window.dispatchEvent(new Event('converse-loaded')); + window.dispatchEvent(new CustomEvent('converse-loaded')); return window.converse; }); //# sourceMappingURL=converse-core.js.map; @@ -41527,7 +41763,8 @@ return Backbone.BrowserStorage; return Backbone.Overview; }); -//# sourceMappingURL=backbone.overview.js.map; +//# sourceMappingURL=backbone.overview.js.map +; // Converse.js (A browser based XMPP chat client) // http://conversejs.org // @@ -41617,6 +41854,7 @@ return Backbone.BrowserStorage; _converse.ChatBox = Backbone.Model.extend({ defaults: { 'type': 'chatbox', + 'show_avatar': true, 'bookmarked': false, 'chat_state': undefined, 'num_unread': 0, @@ -44470,9 +44708,9 @@ __e(o.avatar_height) + 'px" width="' + __e(o.avatar_width) + 'px"\n src="data:' + -__e(o.image_type) + +__e(o.image_type || o._converse.DEFAULT_IMAGE_TYPE) + ';base64,' + -__e(o.image) + +__e(o.image || o._converse.DEFAULT_IMAGE) + '"/>\n '; } ; __p += '\n
\n '; @@ -44938,6 +45176,7 @@ return __p }, render: function render() { this.el.innerHTML = tpl_chatbox_head(_.extend(this.model.toJSON(), { + '_converse': _converse, 'avatar_width': _converse.chatview_avatar_width, 'avatar_height': _converse.chatview_avatar_height, 'info_close': __('Close this chat box') @@ -46266,7 +46505,7 @@ Strophe.addConnectionPlugin('disco', this.waitUntilFeaturesDiscovered = utils.getResolveablePromise(); this.features = new Backbone.Collection(); this.features.browserStorage = new Backbone.BrowserStorage[_converse.storage](b64_sha1("converse.features-".concat(this.get('jid')))); - this.features.on('add', this.onFeatureAdded); + this.features.on('add', this.onFeatureAdded, this); this.identities = new Backbone.Collection(); this.identities.browserStorage = new Backbone.BrowserStorage[_converse.storage](b64_sha1("converse.identities-".concat(this.get('jid')))); this.fetchFeatures(); @@ -46323,6 +46562,8 @@ Strophe.addConnectionPlugin('disco', }); }, onFeatureAdded: function onFeatureAdded(feature) { + feature.entity = this; + _converse.emit('serviceDiscovered', feature); }, fetchFeatures: function fetchFeatures() { @@ -47531,7 +47772,7 @@ __p += '\n