From 081f075aa9f3b97137fbd87b8548a1ec3535a41b Mon Sep 17 00:00:00 2001 From: JC Brand Date: Thu, 26 Jan 2017 14:49:02 +0000 Subject: [PATCH] Add eslint with lodash checking and apply its suggestions --- .eslintrc.json | 264 +++++++++++++++++++++++++++++++++++ Makefile | 29 ++-- package.json | 5 +- spec/chatbox.js | 10 +- spec/chatroom.js | 8 +- spec/controlbox.js | 8 +- spec/converse.js | 10 +- spec/headline.js | 2 +- spec/mam.js | 2 +- spec/minchats.js | 2 +- spec/transcripts.js | 7 +- spec/utils.js | 4 +- src/converse-api.js | 37 ++--- src/converse-bookmarks.js | 6 +- src/converse-chatview.js | 42 +++--- src/converse-controlbox.js | 14 +- src/converse-core.js | 62 ++++---- src/converse-dragresize.js | 8 +- src/converse-headline.js | 4 +- src/converse-mam.js | 10 +- src/converse-minimize.js | 6 +- src/converse-muc.js | 132 ++++++++++-------- src/converse-notification.js | 12 +- src/converse-otr.js | 31 ++-- src/converse-ping.js | 8 +- src/converse-register.js | 8 +- src/converse-rosterview.js | 17 +-- src/converse.js | 1 + src/jquery-private.js | 1 + src/jquery.eventemitter.js | 25 ---- src/locales.js | 1 + src/utils.js | 12 +- 32 files changed, 531 insertions(+), 257 deletions(-) create mode 100644 .eslintrc.json delete mode 100644 src/jquery.eventemitter.js diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 000000000..dc38ad0ca --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,264 @@ +{ + "env": { + "browser": true, + "jasmine": true + }, + "plugins": ["lodash"], + "extends": ["eslint:recommended", "plugin:lodash/canonical"], + "globals": { + "window": true, + "sinon": true, + "define": true + }, + "rules": { + "lodash/prefer-lodash-method": [2, { + "ignoreMethods": ["find", "endsWith", "startsWith", "filter", "map"] + }], + "lodash/prefer-startswith": "off", + "lodash/prefer-constant": "off", + "lodash/prefer-noop": "off", + "lodash/prefer-lodash-typecheck": "off", + "lodash/preferred-alias": "off", + "accessor-pairs": "error", + "array-bracket-spacing": "off", + "array-callback-return": "error", + "arrow-body-style": "error", + "arrow-parens": "error", + "arrow-spacing": "error", + "block-scoped-var": "off", + "block-spacing": "off", + "brace-style": "off", + "callback-return": "off", + "camelcase": "off", + "capitalized-comments": "off", + "class-methods-use-this": "error", + "comma-dangle": "off", + "comma-spacing": "off", + "comma-style": "off", + "complexity": "off", + "computed-property-spacing": [ + "error", + "never" + ], + "consistent-return": "off", + "consistent-this": "off", + "curly": "off", + "default-case": "off", + "dot-location": [ + "error", + "property" + ], + "dot-notation": [ + "error", + { + "allowKeywords": false + } + ], + "eol-last": "error", + "eqeqeq": "off", + "func-call-spacing": "off", + "no-spaced-func": "off", + "func-name-matching": "error", + "func-names": "off", + "func-style": "off", + "generator-star-spacing": "error", + "global-require": "off", + "guard-for-in": "error", + "handle-callback-err": "error", + "id-blacklist": "error", + "id-length": "off", + "id-match": "error", + "indent": "off", + "init-declarations": "off", + "jsx-quotes": "error", + "key-spacing": "off", + "keyword-spacing": "off", + "line-comment-position": "off", + "linebreak-style": [ + "error", + "unix" + ], + "lines-around-comment": "off", + "lines-around-directive": "off", + "max-depth": "error", + "max-len": "off", + "max-lines": "off", + "max-nested-callbacks": "error", + "max-params": "off", + "max-statements": "off", + "max-statements-per-line": "off", + "multiline-ternary": "off", + "new-parens": "error", + "newline-after-var": "off", + "newline-before-return": "off", + "newline-per-chained-call": "off", + "no-alert": "off", + "no-array-constructor": "error", + "no-await-in-loop": "error", + "no-bitwise": "off", + "no-caller": "error", + "no-console": "off", + "no-catch-shadow": "error", + "no-cond-assign": [ + "error", + "except-parens" + ], + "no-confusing-arrow": "error", + "no-continue": "off", + "no-div-regex": "error", + "no-duplicate-imports": "error", + "no-else-return": "off", + "no-empty-function": "off", + "no-eq-null": "error", + "no-eval": "error", + "no-extend-native": "off", + "no-extra-bind": "off", + "no-extra-label": "error", + "no-extra-parens": "off", + "no-floating-decimal": "error", + "no-implicit-globals": "off", + "no-implied-eval": "error", + "no-inline-comments": "off", + "no-inner-declarations": [ + "error", + "functions" + ], + "no-invalid-this": "off", + "no-iterator": "error", + "no-label-var": "error", + "no-labels": "error", + "no-lone-blocks": "error", + "no-lonely-if": "off", + "no-loop-func": "error", + "no-magic-numbers": "off", + "no-mixed-operators": "off", + "no-mixed-requires": "error", + "no-multi-assign": "off", + "no-multi-spaces": "off", + "no-multi-str": "error", + "no-multiple-empty-lines": "error", + "no-native-reassign": "error", + "no-negated-condition": "off", + "no-negated-in-lhs": "error", + "no-nested-ternary": "off", + "no-new": "error", + "no-new-func": "error", + "no-new-object": "error", + "no-new-require": "error", + "no-new-wrappers": "error", + "no-octal-escape": "error", + "no-param-reassign": "off", + "no-path-concat": "error", + "no-plusplus": "off", + "no-process-env": "error", + "no-process-exit": "error", + "no-proto": "error", + "no-prototype-builtins": "error", + "no-restricted-globals": "error", + "no-restricted-imports": "error", + "no-restricted-modules": "error", + "no-restricted-properties": "error", + "no-restricted-syntax": "error", + "no-return-assign": "error", + "no-return-await": "error", + "no-script-url": "error", + "no-self-compare": "error", + "no-sequences": "error", + "no-shadow": "off", + "no-shadow-restricted-names": "error", + "no-sync": "error", + "no-tabs": "error", + "no-template-curly-in-string": "error", + "no-ternary": "off", + "no-throw-literal": "error", + "no-trailing-spaces": "off", + "no-undef-init": "error", + "no-undefined": "off", + "no-underscore-dangle": "off", + "no-unmodified-loop-condition": "error", + "no-unneeded-ternary": "off", + "no-unused-vars": "off", + "no-unused-expressions": "off", + "no-use-before-define": "off", + "no-useless-call": "error", + "no-useless-computed-key": "error", + "no-useless-concat": "error", + "no-useless-constructor": "error", + "no-useless-escape": "off", + "no-useless-rename": "error", + "no-useless-return": "off", + "no-var": "off", + "no-void": "error", + "no-warning-comments": "off", + "no-whitespace-before-property": "error", + "no-with": "error", + "object-curly-newline": "off", + "object-curly-spacing": "off", + "object-property-newline": [ + "error", + { + "allowMultiplePropertiesPerLine": true + } + ], + "object-shorthand": "off", + "one-var": "off", + "one-var-declaration-per-line": "off", + "operator-assignment": "off", + "operator-linebreak": [ + "error", + "after" + ], + "padded-blocks": "off", + "prefer-arrow-callback": "off", + "prefer-const": "error", + "prefer-destructuring": [ + "error", + { + "array": false, + "object": false + } + ], + "prefer-numeric-literals": "error", + "prefer-promise-reject-errors": "error", + "prefer-reflect": "off", + "prefer-rest-params": "off", + "prefer-spread": "off", + "prefer-template": "off", + "quote-props": "off", + "quotes": "off", + "radix": [ + "error", + "always" + ], + "require-await": "error", + "require-jsdoc": "off", + "rest-spread-spacing": "error", + "semi": "off", + "semi-spacing": "off", + "sort-imports": "error", + "sort-keys": "off", + "sort-vars": "off", + "space-before-blocks": "off", + "space-before-function-paren": "off", + "space-in-parens": "off", + "space-infix-ops": "off", + "space-unary-ops": "off", + "spaced-comment": "off", + "strict": "off", + "symbol-description": "error", + "template-curly-spacing": "error", + "unicode-bom": [ + "error", + "never" + ], + "valid-jsdoc": "error", + "vars-on-top": "off", + "wrap-iife": [ + "error", + "any" + ], + "wrap-regex": "error", + "yield-star-spacing": "error", + "yoda": "off" + } +} diff --git a/Makefile b/Makefile index ec740201b..4615ab217 100644 --- a/Makefile +++ b/Makefile @@ -3,11 +3,12 @@ BOWER ?= node_modules/.bin/bower BUILDDIR = ./docs BUNDLE ?= ./.bundle/bin/bundle GRUNT ?= ./node_modules/.bin/grunt -HTTPSERVE ?= ./node_modules/.bin/http-server -JSHINT ?= ./node_modules/.bin/jshint +HTTPSERVE ?= ./node_modules/.bin/http-server +JSHINT ?= ./node_modules/.bin/jshint +ESLINT ?= ./node_modules/.bin/eslint PAPER = PHANTOMJS ?= ./node_modules/.bin/phantomjs -RJS ?= ./node_modules/.bin/r.js +RJS ?= ./node_modules/.bin/r.js PO2JSON ?= ./node_modules/.bin/po2json SASS ?= ./.bundle/bin/sass CLEANCSS ?= ./node_modules/.bin/cleancss @@ -16,16 +17,13 @@ SPHINXOPTS = # Internal variables. ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) ./docs/source -SOURCES = $(wildcard *.js) $(wildcard spec/*.js) $(wildcard src/*.js) +SOURCES = $(wildcard *.js) $(wildcard spec/*.js) $(wildcard src/*.js) JSHINTEXCEPTIONS = $(GENERATED) \ - src/otr.js \ - src/crypto.js \ - src/build-mobile.js \ - src/build-no-jquery.js \ - src/build-no-dependencies.js \ - src/build.js \ - src/bigint.js -CHECKSOURCES = $(filter-out $(JSHINTEXCEPTIONS),$(SOURCES)) + src/build-mobile.js \ + src/build-no-jquery.js \ + src/build-no-dependencies.js \ + src/build.js \ +CHECKSOURCES = $(filter-out $(JSHINTEXCEPTIONS),$(SOURCES)) .PHONY: all all: dev dist @@ -189,8 +187,13 @@ build:: stamp-bundler stamp-bower css jshint: stamp-bower $(JSHINT) --config jshintrc $(CHECKSOURCES) +.PHONY: eslint +eslint: stamp-npm + $(ESLINT) src/ + $(ESLINT) spec/ + .PHONY: check -check: stamp-bower jshint +check: stamp-bower jshint eslint $(PHANTOMJS) node_modules/phantom-jasmine/lib/run_jasmine_test.coffee tests.html ######################################################################## diff --git a/package.json b/package.json index 9d6064787..5487221f7 100644 --- a/package.json +++ b/package.json @@ -39,19 +39,22 @@ "bower": "latest", "clean-css": "^3.4.19", "crypto-js": "3.1.2-5", + "eslint": "^3.14.1", + "eslint-plugin-lodash": "^2.3.3", "greenkeeper": "^4.1.0", "grunt": "^1.0.1", "grunt-cli": "^1.1.0", "grunt-json": "^0.2.0", "http-server": "^0.9.0", + "install": "^0.8.4", "jed": "0.5.4", "jquery": "2.2.3", "jquery-easing": "0.0.1", "jquery.browser": ">=0.1.0", "jshint": "^2.9.4", "lodash": "^4.17.4", - "lodash-cli": "^4.17.4", "moment": "~2.13.0", + "npm": "^4.1.1", "otr": "0.2.16", "phantom-jasmine": "0.1.8", "phantomjs": "~1.9.7-1", diff --git a/spec/chatbox.js b/spec/chatbox.js index 4760f0625..0c6b9bb89 100644 --- a/spec/chatbox.js +++ b/spec/chatbox.js @@ -154,8 +154,8 @@ var attrs = ['id', 'box_id', 'visible']; var new_attrs, old_attrs; for (var i=0; i (this.model.get('min_width') || 0)) ? (this.width+diff) : this.model.get('min_width'); @@ -292,9 +292,9 @@ * default_value. If value is close enough to * default_value, then default_value is returned instead. */ - if (typeof value === 'undefined') { + if (_.isUndefined(value)) { return undefined; - } else if (typeof default_value === 'undefined') { + } else if (_.isUndefined(default_value)) { return value; } var resistance = 10; diff --git a/src/converse-headline.js b/src/converse-headline.js index 48403a3e8..46050c3a5 100644 --- a/src/converse-headline.js +++ b/src/converse-headline.js @@ -76,7 +76,7 @@ }, initialize: function () { - if (typeof this.setDimensions !== "undefined") { + if (!_.isUndefined(this.setDimensions)) { // setDimensions is defined for dragresize $(window).on('resize', _.debounce(this.setDimensions.bind(this), 100)); } @@ -103,7 +103,7 @@ ) ) ); - if (typeof this.setWidth !== "undefined") { + if (!_.isUndefined(this.setWidth)) { // setWidth is defined for dragresize $(window).on('resize', _.debounce(this.setWidth.bind(this), 100)); } diff --git a/src/converse-mam.js b/src/converse-mam.js index 341fa6166..572e78a67 100644 --- a/src/converse-mam.js +++ b/src/converse-mam.js @@ -99,7 +99,7 @@ converse.queryForArchivedMessages(options, function (messages) { this.clearSpinner(); if (messages.length) { - _.map(messages, converse.chatboxes.onMessage.bind(converse.chatboxes)); + _.each(messages, converse.chatboxes.onMessage.bind(converse.chatboxes)); } }.bind(this), function () { @@ -163,7 +163,7 @@ * get the next or previous page in the result set. */ var date, messages = []; - if (typeof options === "function") { + if (_.isFunction(options)) { callback = options; errback = callback; } @@ -176,14 +176,14 @@ */ var queryid = converse.connection.getUniqueId(); var attrs = {'type':'set'}; - if (typeof options !== "undefined" && options.groupchat) { + if (!_.isUndefined(options) && options.groupchat) { if (!options['with']) { throw new Error('You need to specify a "with" value containing the chat room JID, when querying groupchat messages.'); } attrs.to = options['with']; } var stanza = $iq(attrs).c('query', {'xmlns':Strophe.NS.MAM, 'queryid':queryid}); - if (typeof options !== "undefined") { + if (!_.isUndefined(options)) { stanza.c('x', {'xmlns':Strophe.NS.XFORM, 'type': 'submit'}) .c('field', {'var':'FORM_TYPE', 'type': 'hidden'}) .c('value').t(Strophe.NS.MAM).up().up(); @@ -209,7 +209,7 @@ } } - if (typeof callback === "function") { + if (_.isFunction(callback)) { converse.connection.addHandler(function (message) { var $msg = $(message), rsm, $fin = $msg.find('fin[xmlns="'+Strophe.NS.MAM+'"]'); diff --git a/src/converse-minimize.js b/src/converse-minimize.js index 67e4ea864..6cf9fbb10 100644 --- a/src/converse-minimize.js +++ b/src/converse-minimize.js @@ -255,7 +255,7 @@ } var oldest_chat, boxes_width, view, $minimized = converse.minimized_chats.$el, - minimized_width = _.contains(this.model.pluck('minimized'), true) ? $minimized.outerWidth(true) : 0, + minimized_width = _.includes(this.model.pluck('minimized'), true) ? $minimized.outerWidth(true) : 0, new_id = newchat ? newchat.model.get('id') : null; boxes_width = _.reduce(this.xget(new_id), function (memo, view) { @@ -283,7 +283,7 @@ exclude_ids.push('controlbox'); var i = 0; var model = this.model.sort().at(i); - while (_.contains(exclude_ids, model.get('id')) || + while (_.includes(exclude_ids, model.get('id')) || model.get('minimized') === true) { i++; model = this.model.at(i); @@ -370,7 +370,7 @@ this.model.messages.off('add',null,this); this.remove(); this.model.maximize(); - }, 200, true) + }, 200, {'leading': true}) }); converse.MinimizedChats = Backbone.Overview.extend({ diff --git a/src/converse-muc.js b/src/converse-muc.js index 40c3582b5..df4ef5cb8 100755 --- a/src/converse-muc.js +++ b/src/converse-muc.js @@ -496,13 +496,15 @@ this.insertIntoTextArea(ev.target.textContent); }, - requestMemberList: function (affiliation) { + requestMemberList: function (chatroom_jid, affiliation) { /* Send an IQ stanza to the server, asking it for the * member-list of this room. * * See: http://xmpp.org/extensions/xep-0045.html#modifymember * * Parameters: + * (String) chatroom_jid: The JID of the chatroom for + * which the member-list is being requested * (String) affiliation: The specific member list to * fetch. 'admin', 'owner' or 'member'. * @@ -512,7 +514,7 @@ */ var deferred = new $.Deferred(); affiliation = affiliation || 'member'; - var iq = $iq({to: this.model.get('jid'), type: "get"}) + var iq = $iq({to: chatroom_jid, type: "get"}) .c("query", {xmlns: Strophe.NS.MUC_ADMIN}) .c("item", {'affiliation': affiliation}); converse.connection.sendIQ(iq, deferred.resolve, deferred.reject); @@ -561,8 +563,8 @@ * (Array) new_list: Array containing the new affiliations * (Array) old_list: Array containing the old affiliations */ - var new_jids = _.pluck(new_list, 'jid'); - var old_jids = _.pluck(old_list, 'jid'); + var new_jids = _.map(new_list, 'jid'); + var old_jids = _.map(old_list, 'jid'); // Get the new affiliations var delta = _.map(_.difference(new_jids, old_jids), function (jid) { @@ -587,6 +589,30 @@ return delta; }, + sendAffiliationIQ: function (chatroom_jid, affiliation, member) { + /* Send an IQ stanza specifying an affiliation change. + * + * Paremeters: + * (String) chatroom_jid: JID of the relevant room + * (String) affiliation: affiliation (could also be stored + * on the member object). + * (Object) member: Map containing the member's jid and + * optionally a reason and affiliation. + */ + var deferred = new $.Deferred(); + var iq = $iq({to: chatroom_jid, type: "set"}) + .c("query", {xmlns: Strophe.NS.MUC_ADMIN}) + .c("item", { + 'affiliation': member.affiliation || affiliation, + 'jid': member.jid + }); + if (!_.isUndefined(member.reason)) { + iq.c("reason", member.reason); + } + converse.connection.sendIQ(iq, deferred.resolve, deferred.reject); + return deferred; + }, + setAffiliation: function (affiliation, members) { /* Send IQ stanzas to the server to set an affiliation for * the provided JIDs. @@ -599,6 +625,7 @@ * Related ticket: https://prosody.im/issues/issue/795 * * Parameters: + * (String) affiliation: The affiliation * (Object) members: A map of jids, affiliations and * optionally reasons. Only those entries with the * same affiliation as being currently set will be @@ -615,21 +642,11 @@ return _.isUndefined(member.affiliation) || member.affiliation === affiliation; }); - var promises = _.map(members, function (member) { - var deferred = new $.Deferred(); - var iq = $iq({to: this.model.get('jid'), type: "set"}) - .c("query", {xmlns: Strophe.NS.MUC_ADMIN}) - .c("item", { - 'affiliation': member.affiliation || affiliation, - 'jid': member.jid - }); - if (!_.isUndefined(member.reason)) { - iq.c("reason", member.reason); - } - converse.connection.sendIQ(iq, deferred.resolve, deferred.reject); - return deferred; - }, this); - return $.when.apply($, promises); + var promises = _.map( + members, + _.partial(this.sendAffiliationIQ, this.model.get('jid'), affiliation) + ); + return $.when.apply($, promises); }, setAffiliations: function (members, onSuccess, onError) { @@ -648,8 +665,8 @@ onSuccess(null); return; } - var affiliations = _.uniq(_.pluck(members, 'affiliation')); - var promises = _.map(affiliations, _.partial(this.setAffiliation, _, members), this); + var affiliations = _.uniq(_.map(members, 'affiliation')); + var promises = _.map(affiliations, _.partial(this.setAffiliation.bind(this), _, members)); $.when.apply($, promises).done(onSuccess).fail(onError); }, @@ -661,24 +678,20 @@ * Any amount of XMLElement objects, representing the IQ * stanzas. */ - return _.flatten(_.map(arguments, this.parseMemberListIQ)); + return _.flatMap(arguments, this.parseMemberListIQ); }, getJidsWithAffiliations: function (affiliations) { /* Returns a map of JIDs that have the affiliations * as provided. */ - if (typeof affiliations === "string") { + if (_.isString(affiliations)) { affiliations = [affiliations]; } - var that = this; var deferred = new $.Deferred(); - var promises = []; - _.each(affiliations, function (affiliation) { - promises.push(that.requestMemberList(affiliation)); - }); + var promises = _.map(affiliations, _.partial(this.requestMemberList, this.model.get('jid'))); $.when.apply($, promises).always( - _.compose(deferred.resolve, this.marshallAffiliationIQs.bind(this)) + _.flow(this.marshallAffiliationIQs.bind(this), deferred.resolve) ); return deferred.promise(); }, @@ -838,7 +851,7 @@ clearChatRoomMessages: function (ev) { /* Remove all messages from the chat room UI. */ - if (typeof ev !== "undefined") { ev.stopPropagation(); } + if (!_.isUndefined(ev)) { ev.stopPropagation(); } var result = confirm(__("Are you sure you want to clear the messages from this room?")); if (result === true) { this.$content.empty(); @@ -995,7 +1008,7 @@ room_no_longer_anon || room_now_semi_anon || room_now_fully_anon) { this.getRoomFeatures(); } - _.compose(this.onChatRoomMessage.bind(this), this.showStatusMessages.bind(this))(stanza); + _.flow(this.showStatusMessages.bind(this), this.onChatRoomMessage.bind(this))(stanza); return true; }, @@ -1354,7 +1367,7 @@ if (_.isUndefined(ev) && this.model.get('auto_configure')) { this.fetchRoomConfiguration().then(that.autoConfigureChatRoom.bind(that)); } else { - if (typeof ev !== 'undefined' && ev.preventDefault) { + if (!_.isUndefined(ev) && ev.preventDefault) { ev.preventDefault(); } this.showSpinner(); @@ -1472,7 +1485,7 @@ */ this.$('.chatroom-body').children().addClass('hidden'); this.$('span.centered.spinner').remove(); - if (typeof message !== "string") { + if (!_.isString(message)) { message = ''; } this.$('.chatroom-body').append( @@ -1583,7 +1596,7 @@ 'messages': _.reject(_.map(statuses, mapper), _.isUndefined), }; // 2. Get disconnection messages based on the elements - var codes = _.map(statuses, function (stat) { return stat.getAttribute('code'); }); + var codes = _.invokeMap(statuses, Element.prototype.getAttribute, 'code'); var disconnection_codes = _.intersection(codes, _.keys(converse.muc.disconnect_messages)); var disconnected = is_self && disconnection_codes.length > 0; if (disconnected) { @@ -1649,10 +1662,12 @@ // Unfortunately this doesn't work (returns empty list) // var elements = stanza.querySelectorAll('x[xmlns="'+Strophe.NS.MUC_USER+'"]'); - var elements = _.chain(stanza.querySelectorAll('x')).filter(function (x) { - return x.getAttribute('xmlns') === Strophe.NS.MUC_USER; - }).value(); - + var elements = _.filter( + stanza.querySelectorAll('x'), + function (x) { + return x.getAttribute('xmlns') === Strophe.NS.MUC_USER; + } + ); var notifications = _.map( elements, _.partial(this.parseXUserElement.bind(this), _, stanza, is_self) @@ -1845,7 +1860,7 @@ function (messages) { that.clearSpinner(); if (messages.length) { - _.map(messages, that.onChatRoomMessage.bind(that)); + _.each(messages, that.onChatRoomMessage.bind(that)); } }, function () { @@ -2027,11 +2042,12 @@ }, { name: 'contacts-dataset', source: function (q, cb) { - var results = []; - _.each(converse.roster.filter(utils.contains(['fullname', 'jid'], q)), function (n) { - results.push({value: n.get('fullname'), jid: n.get('jid')}); - }); - cb(results); + cb(_.map( + converse.roster.filter(utils.contains(['fullname', 'jid'], q)), + function (n) { + return {value: n.get('fullname'), jid: n.get('jid')}; + } + )); }, templates: { suggestion: _.template('

{{value}}

') @@ -2331,7 +2347,7 @@ 'box_id': b64_sha1(room_jid), 'password': $x.attr('password') }); - if (!_.contains( + if (!_.includes( [Strophe.Status.CONNECTING, Strophe.Status.CONNECTED], chatroom.get('connection_status')) ) { @@ -2359,9 +2375,9 @@ * settings). */ _.each(converse.auto_join_rooms, function (room) { - if (typeof room === 'string') { + if (_.isString(room)) { converse_api.rooms.open(room); - } else if (typeof room === 'object') { + } else if (_.isObject(room)) { converse_api.rooms.open(room.jid, room.nick); } else { converse.log('Invalid room criteria specified for "auto_join_rooms"', 'error'); @@ -2388,26 +2404,26 @@ _.extend(converse_api, { 'rooms': { 'close': function (jids) { - if (typeof jids === "undefined") { + if (_.isUndefined(jids)) { converse.chatboxviews.each(function (view) { if (view.is_chatroom && view.model) { view.close(); } }); - } else if (typeof jids === "string") { + } else if (_.isString(jids)) { var view = converse.chatboxviews.get(jids); if (view) { view.close(); } } else { - _.map(jids, function (jid) { + _.each(jids, function (jid) { var view = converse.chatboxviews.get(jid); if (view) { view.close(); } }); } }, 'open': function (jids, attrs) { - if (typeof attrs === "string") { + if (_.isString(attrs)) { attrs = {'nick': attrs}; - } else if (typeof attrs === "undefined") { + } else if (_.isUndefined(attrs)) { attrs = {}; } if (_.isUndefined(attrs.maximize)) { @@ -2416,20 +2432,20 @@ if (!attrs.nick && converse.muc_nickname_from_jid) { attrs.nick = Strophe.getNodeFromJid(converse.bare_jid); } - if (typeof jids === "undefined") { + if (_.isUndefined(jids)) { throw new TypeError('rooms.open: You need to provide at least one JID'); - } else if (typeof jids === "string") { + } else if (_.isString(jids)) { return converse.getWrappedChatRoom(jids, attrs, converse.createChatRoom); } return _.map(jids, _.partial(converse.getWrappedChatRoom, _, attrs, converse.createChatRoom)); }, 'get': function (jids, attrs, create) { - if (typeof attrs === "string") { + if (_.isString(attrs)) { attrs = {'nick': attrs}; - } else if (typeof attrs === "undefined") { + } else if (_.isUndefined(attrs)) { attrs = {}; } - if (typeof jids === "undefined") { + if (_.isUndefined(jids)) { var result = []; converse.chatboxes.each(function (chatbox) { if (chatbox.get('type') === 'chatroom') { @@ -2442,7 +2458,7 @@ if (!attrs.nick) { attrs.nick = Strophe.getNodeFromJid(converse.bare_jid); } - if (typeof jids === "string") { + if (_.isString(jids)) { return converse.getWrappedChatRoom(jids, attrs, fetcher); } return _.map(jids, _.partial(converse.getWrappedChatRoom, _, attrs, fetcher)); diff --git a/src/converse-notification.js b/src/converse-notification.js index fbdc80042..7510905ab 100644 --- a/src/converse-notification.js +++ b/src/converse-notification.js @@ -68,7 +68,7 @@ return false; } var mentioned = (new RegExp("\\b"+room.get('nick')+"\\b")).test($body.text()); - notify_all = notify_all === true || (_.isArray(notify_all) && _.contains(notify_all, room_jid)); + notify_all = notify_all === true || (_.isArray(notify_all) && _.includes(notify_all, room_jid)); if (sender === room.get('nick') || (!notify_all && !mentioned)) { return false; } @@ -102,7 +102,7 @@ // feature, but no browser currently supports it. // https://developer.mozilla.org/en-US/docs/Web/API/notification/sound var audio; - if (converse.play_sounds && typeof Audio !== "undefined") { + if (converse.play_sounds && !_.isUndefined(Audio)) { audio = new Audio(converse.sounds_path+"msg_received.ogg"); if (audio.canPlayType('/audio/ogg')) { audio.play(); @@ -130,7 +130,7 @@ */ var n, title, contact_jid, roster_item, from_jid = $message.attr('from'); - if ($message.attr('type') === 'headline' || from_jid.indexOf('@') === -1) { + if ($message.attr('type') === 'headline' || !_.includes(from_jid, '@')) { // XXX: 2nd check is workaround for Prosody which doesn't // give type "headline" title = __(___("Notification from %1$s"), from_jid); @@ -138,7 +138,7 @@ if ($message.attr('type') === 'groupchat') { title = __(___("%1$s says"), Strophe.getResourceFromJid(from_jid)); } else { - if (typeof converse.roster === 'undefined') { + if (_.isUndefined(converse.roster)) { converse.log("Could not send notification, because roster is undefined", "error"); return; } @@ -159,7 +159,7 @@ /* Creates an HTML5 Notification to inform of a change in a * contact's chat state. */ - if (_.contains(converse.chatstate_notification_blacklist, contact.jid)) { + if (_.includes(converse.chatstate_notification_blacklist, contact.jid)) { // Don't notify if the user is being ignored. return; } @@ -243,7 +243,7 @@ converse.requestPermission = function (evt) { if (converse.supports_html5_notification && - ! _.contains(['denied', 'granted'], Notification.permission)) { + ! _.includes(['denied', 'granted'], Notification.permission)) { // Ask user to enable HTML5 notifications Notification.requestPermission(); } diff --git a/src/converse-otr.js b/src/converse-otr.js index 62f685ade..dc1968374 100644 --- a/src/converse-otr.js +++ b/src/converse-otr.js @@ -30,14 +30,13 @@ // For translations var __ = utils.__.bind(converse); - var HAS_CSPRNG = ((typeof crypto !== 'undefined') && - ((typeof crypto.randomBytes === 'function') || - (typeof crypto.getRandomValues === 'function') + var HAS_CSPRNG = ((!_.isUndefined(crypto)) && + ((_.isFunction(crypto.randomBytes)) || (_.isFunction(crypto.getRandomValues)) )); var HAS_CRYPTO = HAS_CSPRNG && ( - (typeof CryptoJS !== "undefined") && - (typeof otr.OTR !== "undefined") && - (typeof otr.DSA !== "undefined") + (!_.isUndefined(CryptoJS)) && + (!_.isUndefined(otr.OTR)) && + (!_.isUndefined(otr.DSA)) ); var UNENCRYPTED = 0; @@ -105,7 +104,7 @@ * "visible" OTR messages being exchanged. */ return this.__super__.shouldPlayNotification.apply(this, arguments) && - !(utils.isOTRMessage($message[0]) && !_.contains([UNVERIFIED, VERIFIED], this.get('otr_status'))); + !(utils.isOTRMessage($message[0]) && !_.includes([UNVERIFIED, VERIFIED], this.get('otr_status'))); }, createMessage: function ($message, $delay, original_stanza) { @@ -119,7 +118,7 @@ if (text.match(/^\?OTRv23?/)) { this.initiateOTR(text); } else { - if (_.contains([UNVERIFIED, VERIFIED], this.get('otr_status'))) { + if (_.includes([UNVERIFIED, VERIFIED], this.get('otr_status'))) { this.otr.receiveMsg(text); } else { if (text.match(/^\?OTR/)) { @@ -142,11 +141,11 @@ var pass, instance_tag, saved_key, pass_check; if (converse.cache_otr_key) { pass = converse.otr.getSessionPassphrase(); - if (typeof pass !== "undefined") { + if (!_.isUndefined(pass)) { instance_tag = window.sessionStorage[b64_sha1(this.id+'instance_tag')]; saved_key = window.sessionStorage[b64_sha1(this.id+'priv_key')]; pass_check = window.sessionStorage[b64_sha1(this.connection.jid+'pass_check')]; - if (saved_key && instance_tag && typeof pass_check !== 'undefined') { + if (saved_key && instance_tag && !_.isUndefined(pass_check)) { var decrypted = cipher.decrypt(CryptoJS.algo.AES, saved_key, pass); var key = otr.DSA.parsePrivate(decrypted.toString(CryptoJS.enc.Latin1)); if (cipher.decrypt(CryptoJS.algo.AES, pass_check, pass).toString(CryptoJS.enc.Latin1) === 'match') { @@ -285,7 +284,7 @@ this.model.on('showReceivedOTRMessage', function (text) { this.showMessage({'message': text, 'sender': 'them'}); }, this); - if ((_.contains([UNVERIFIED, VERIFIED], this.model.get('otr_status'))) || converse.use_otr_by_default) { + if ((_.includes([UNVERIFIED, VERIFIED], this.model.get('otr_status'))) || converse.use_otr_by_default) { this.model.initiateOTR(); } }, @@ -319,7 +318,7 @@ return this.model.initiateOTR(); } } - if (_.contains([UNVERIFIED, VERIFIED], this.model.get('otr_status'))) { + if (_.includes([UNVERIFIED, VERIFIED], this.model.get('otr_status'))) { // Off-the-record encryption is active this.model.otr.sendMsg(text); this.model.trigger('showSentOTRMessage', text); @@ -372,7 +371,7 @@ }, endOTR: function (ev) { - if (typeof ev !== "undefined") { + if (!_.isUndefined(ev)) { ev.preventDefault(); ev.stopPropagation(); } @@ -485,7 +484,7 @@ }; _.extend(converse.default_settings, settings); _.extend(converse, settings); - _.extend(converse, _.pick(converse.user_settings, Object.keys(settings))); + _.extend(converse, _.pick(converse.user_settings, _.keys(settings))); // Only allow OTR if we have the capability converse.allow_otr = converse.allow_otr && HAS_CRYPTO; @@ -500,7 +499,7 @@ if (converse.authentication === 'prebind') { var key = b64_sha1(converse.connection.jid), pass = window.sessionStorage[key]; - if (typeof pass === 'undefined') { + if (_.isUndefined(pass)) { pass = Math.floor(Math.random()*4294967295).toString(); window.sessionStorage[key] = pass; } @@ -516,7 +515,7 @@ if (converse.cache_otr_key) { var cipher = CryptoJS.lib.PasswordBasedCipher; var pass = this.getSessionPassphrase(); - if (typeof pass !== "undefined") { + if (!_.isUndefined(pass)) { // Encrypt the key and set in sessionStorage. Also store instance tag. window.sessionStorage[b64_sha1(jid+'priv_key')] = cipher.encrypt(CryptoJS.algo.AES, key.packPrivate(), pass).toString(); diff --git a/src/converse-ping.js b/src/converse-ping.js index 199705e3d..9c15d8309 100644 --- a/src/converse-ping.js +++ b/src/converse-ping.js @@ -42,12 +42,12 @@ // // var feature = converse.features.findWhere({'var': Strophe.NS.PING}); converse.lastStanzaDate = new Date(); - if (typeof jid === 'undefined' || jid === null) { + if (_.isNil(jid)) { jid = Strophe.getDomainFromJid(converse.bare_jid); } - if (typeof timeout === 'undefined' ) { timeout = null; } - if (typeof success === 'undefined' ) { success = null; } - if (typeof error === 'undefined' ) { error = null; } + if (_.isUndefined(timeout) ) { timeout = null; } + if (_.isUndefined(success) ) { success = null; } + if (_.isUndefined(error) ) { error = null; } if (converse.connection) { converse.connection.ping.ping(jid, success, error, timeout); return true; diff --git a/src/converse-register.js b/src/converse-register.js index 4f2268b2e..fd21916fa 100644 --- a/src/converse-register.js +++ b/src/converse-register.js @@ -51,7 +51,7 @@ // Add Strophe Statuses var i = 0; - Object.keys(Strophe.Status).forEach(function (key) { + _.each(_.keys(Strophe.Status), function (key) { i = Math.max(i, Strophe.Status[key]); }); Strophe.Status.REGIFAIL = i + 1; @@ -211,7 +211,7 @@ }; _.extend(this, defaults); if (settings) { - _.extend(this, _.pick(settings, Object.keys(defaults))); + _.extend(this, _.pick(settings, _.keys(defaults))); } }, @@ -254,7 +254,7 @@ onRegistering: function (status, error) { var that; converse.log('onRegistering'); - if (_.contains([ + if (_.includes([ Strophe.Status.DISCONNECTED, Strophe.Status.CONNFAIL, Strophe.Status.REGIFAIL, @@ -320,7 +320,7 @@ }.bind(this)); } else { // Show fields - _.each(Object.keys(this.fields), function (key) { + _.each(_.keys(this.fields), function (key) { if (key === "username") { $input = converse.templates.form_username({ domain: ' @'+this.domain, diff --git a/src/converse-rosterview.js b/src/converse-rosterview.js index 9157940af..530af03fd 100644 --- a/src/converse-rosterview.js +++ b/src/converse-rosterview.js @@ -110,8 +110,8 @@ a = a.get('name'); b = b.get('name'); var special_groups = _.keys(HEADER_WEIGHTS); - var a_is_special = _.contains(special_groups, a); - var b_is_special = _.contains(special_groups, b); + var a_is_special = _.includes(special_groups, a); + var b_is_special = _.includes(special_groups, b); if (!a_is_special && !b_is_special ) { return a.toLowerCase() < b.toLowerCase() ? -1 : (a.toLowerCase() > b.toLowerCase() ? 1 : 0); } else if (a_is_special && b_is_special) { @@ -345,7 +345,7 @@ query = query.toLowerCase(); if (type === 'groups') { _.each(this.getAll(), function (view, idx) { - if (view.model.get('name').toLowerCase().indexOf(query.toLowerCase()) === -1) { + if (!_.includes(view.model.get('name').toLowerCase(), query.toLowerCase())) { view.hide(); } else if (view.model.contacts.length > 0) { view.show(); @@ -407,7 +407,7 @@ if (_.has(contact.changed, 'subscription')) { if (contact.changed.subscription === 'from') { this.addContactToGroup(contact, HEADER_PENDING_CONTACTS); - } else if (_.contains(['both', 'to'], contact.get('subscription'))) { + } else if (_.includes(['both', 'to'], contact.get('subscription'))) { this.addExistingContact(contact); } } @@ -550,6 +550,7 @@ }, render: function () { + var that = this; if (!this.mayBeShown()) { this.$el.hide(); return this; @@ -568,10 +569,10 @@ _.each(classes_to_remove, function (cls) { - if (this.el.className.indexOf(cls) !== -1) { - this.$el.removeClass(cls); + if (_.includes(that.el.className, cls)) { + that.$el.removeClass(cls); } - }, this); + }); this.$el.addClass(chat_status).data('status', chat_status); if ((ask === 'subscribe') || (subscription === 'from')) { @@ -861,7 +862,7 @@ }, onContactGroupChange: function (contact) { - var in_this_group = _.contains(contact.get('groups'), this.model.get('name')); + var in_this_group = _.includes(contact.get('groups'), this.model.get('name')); var cid = contact.get('id'); var in_this_overview = !this.get(cid); if (in_this_group && !in_this_overview) { diff --git a/src/converse.js b/src/converse.js index dfbd4b841..084189c88 100755 --- a/src/converse.js +++ b/src/converse.js @@ -3,6 +3,7 @@ * This file is used to tell require.js which components (or plugins) to load * when it generates a build. */ +/*global define */ if (typeof define !== 'undefined') { /* When running tests, define is not defined. */ diff --git a/src/jquery-private.js b/src/jquery-private.js index 6d6060ad0..3af8c7dea 100644 --- a/src/jquery-private.js +++ b/src/jquery-private.js @@ -1,3 +1,4 @@ +/*global define */ define(['jquery'], function (jq) { return jq.noConflict( true ); }); diff --git a/src/jquery.eventemitter.js b/src/jquery.eventemitter.js deleted file mode 100644 index 93a6a75f0..000000000 --- a/src/jquery.eventemitter.js +++ /dev/null @@ -1,25 +0,0 @@ -/*global $ */ -(function (root, factory) { - if (typeof define === 'function' && define.amd) { - define("converse", ["jquery"], function($) { - return factory($); - }); - } else { - factory($); - } -}(this, function ($) { - $.eventEmitter = { - emit: function(evt, data) { - $(this).trigger(evt, data); - }, - once: function(evt, handler) { - $(this).one(evt, handler); - }, - on: function(evt, handler) { - $(this).bind(evt, handler); - }, - off: function(evt, handler) { - $(this).unbind(evt, handler); - } - }; -})); diff --git a/src/locales.js b/src/locales.js index ec5f65ddf..d76ea7461 100755 --- a/src/locales.js +++ b/src/locales.js @@ -6,6 +6,7 @@ * * See also src/moment_locales.js */ +/*global define */ (function (root, factory) { define("locales", ['jed', 'text!af', diff --git a/src/utils.js b/src/utils.js index ba4c4fc7d..9c36f92dd 100755 --- a/src/utils.js +++ b/src/utils.js @@ -1,4 +1,4 @@ -/*global escape, locales, Jed */ +/*global define, escape, locales, Jed */ (function (root, factory) { define([ "jquery", @@ -244,8 +244,8 @@ // check if an @ signal is included, and if not, we assume it's // a headline message. ( $message.attr('type') !== 'error' && - typeof from_jid !== 'undefined' && - from_jid.indexOf('@') === -1 + !_.isUndefined(from_jid) && + !_.includes(from_jid, '@') )) { return true; } @@ -326,11 +326,11 @@ if (typeof attr === 'object') { var value = false; _.forEach(attr, function (a) { - value = value || item.get(a).toLowerCase().indexOf(query.toLowerCase()) !== -1; + value = value || _.includes(item.get(a).toLowerCase(), query.toLowerCase()); }); return value; } else if (typeof attr === 'string') { - return item.get(attr).toLowerCase().indexOf(query.toLowerCase()) !== -1; + return _.includes(item.get(attr).toLowerCase(), query.toLowerCase()); } else { throw new TypeError('contains: wrong attribute type. Must be string or array.'); } @@ -360,7 +360,7 @@ options.push(tpl_select_option({ value: value, label: $($options[j]).attr('label'), - selected: (values.indexOf(value) >= 0), + selected: _.startsWith(values, value), required: $field.find('required').length })); }