From afd8b7e81bbe9dec2ad61adfb1b02ecf5cd76515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kooi?= Date: Mon, 11 Jul 2016 15:04:57 +0200 Subject: [PATCH 1/3] switch to eslint --- .eslintrc | 3 +++ package.json | 11 ++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 .eslintrc diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..7cde01d --- /dev/null +++ b/.eslintrc @@ -0,0 +1,3 @@ +{ + "extends": "airbnb-base" +} diff --git a/package.json b/package.json index 1e78803..4ef8ce0 100644 --- a/package.json +++ b/package.json @@ -3,14 +3,17 @@ "version": "0.15.8", "description": "Highly flexible, modular userscript extension for plug.dj.", "dependencies": { + "backbone": "^1.1.2", "debug": "^2.2.0", "es6-symbol": "^2.0.1", + "jquery": "^2.1.1", "meld": "^1.3.2", "onecolor": "^2.5.0", "plug-modules": "^4.3.3", "regexp-quote": "0.0.0", "semver-compare": "^1.0.0", - "sistyl": "^1.0.0" + "sistyl": "^1.0.0", + "underscore": "^1.6.0" }, "devDependencies": { "babel-plugin-external-helpers": "^6.5.0", @@ -19,6 +22,9 @@ "babel-preset-stage-2": "^6.5.0", "browserify": "^11.0.1", "del": "^1.2.1", + "eslint": "^3.0.1", + "eslint-config-airbnb-base": "^4.0.0", + "eslint-plugin-import": "^1.10.2", "gulp": "^3.9.0", "gulp-babel": "^6.1.2", "gulp-babel-external-helpers": "^2.0.0", @@ -27,7 +33,6 @@ "gulp-rename": "^1.2.2", "gulp-template": "^3.0.0", "gulp-zip": "^3.0.2", - "jscs": "^1.13.1", "merge-stream": "^1.0.0", "mkdirp": "^0.5.1", "requirejs": "^2.1.20", @@ -36,6 +41,6 @@ }, "scripts": { "build": "gulp build", - "test": "jscs src" + "test": "eslint gulpfile.babel.js src/**/*.js test/**/*.js" } } From 54cff00ea5343336d56ca10b1561f29607a37e6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kooi?= Date: Mon, 11 Jul 2016 16:38:48 +0200 Subject: [PATCH 2/3] use airbnb javascript style --- .eslintrc | 14 +- .jscsrc | 31 ---- gulpfile.babel.js | 148 +++++++++--------- package.json | 3 +- src/ExtPlug.js | 146 ++++++++++------- src/Plugin.js | 54 ++++--- src/collections/PluginsCollection.js | 11 +- src/hooks/api-early.js | 16 +- src/hooks/index.js | 2 +- src/hooks/playback.js | 5 +- src/hooks/popout-style.js | 7 +- src/main.js | 31 ++-- src/models/PluginMeta.js | 10 +- src/models/RoomSettings.js | 41 ++--- src/models/Settings.js | 10 +- src/pluginLoader.js | 33 ++-- src/plugins/ChatTypePlugin.js | 36 +++-- src/plugins/CommandsPlugin.js | 24 +-- src/plugins/EmojiDataPlugin.js | 19 +-- src/plugins/GuestPlugin.js | 43 ++--- src/plugins/MoreChatEventsPlugin.js | 23 +-- src/plugins/PlugSettingsPlugin.js | 8 +- src/plugins/SettingsTabPlugin.js | 27 ++-- src/plugins/SocketEventsPlugin.js | 37 +++-- src/plugins/TooltipsPlugin.js | 16 +- src/plugins/UserClassesPlugin.js | 33 ++-- src/plugins/WaitlistEventsPlugin.js | 18 +-- src/styles/badge.js | 7 +- src/styles/inline-chat.js | 25 +-- src/styles/install-plugin-dialog.js | 23 ++- src/styles/settings-pane.js | 50 +++--- src/util/Style.js | 22 +-- src/util/getUserClasses.js | 8 +- src/util/request.js | 49 +++--- src/views/dialogs/InstallPluginDialog.js | 22 +-- src/views/users/settings/CheckboxView.js | 12 +- src/views/users/settings/ColorInputView.js | 18 ++- src/views/users/settings/ControlGroupView.js | 4 +- .../users/settings/DefaultSettingsView.js | 28 ++-- src/views/users/settings/DropdownView.js | 24 ++- src/views/users/settings/InputView.js | 2 +- .../users/settings/PlaylistSelectMenuView.js | 22 ++- .../users/settings/PlaylistSelectView.js | 9 +- src/views/users/settings/PluginsGroupView.js | 12 +- src/views/users/settings/RemoveBoxView.js | 6 +- src/views/users/settings/SettingsView.js | 67 +++----- src/views/users/settings/SliderView.js | 32 ++-- src/views/users/settings/TabMenuView.js | 12 +- .../users/settings/footers/GroupFooterView.js | 3 +- .../settings/footers/ManagingFooterView.js | 3 +- .../settings/footers/PluginsFooterView.js | 3 +- 51 files changed, 668 insertions(+), 641 deletions(-) delete mode 100644 .jscsrc diff --git a/.eslintrc b/.eslintrc index 7cde01d..c5137f7 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,3 +1,15 @@ { - "extends": "airbnb-base" + "extends": "airbnb-base", + "parser": "babel-eslint", + "globals": { + "API": false + }, + "rules": { + "no-param-reassign": ["error", { "props": false }], + "no-underscore-dangle": ["error", { "allow": ["_super"] }], + "import/no-extraneous-dependencies": "off", + "import/no-unresolved": ["error", { + "ignore": ["^plug/", "^lang/Lang$"] + }] + } } diff --git a/.jscsrc b/.jscsrc deleted file mode 100644 index bd15e80..0000000 --- a/.jscsrc +++ /dev/null @@ -1,31 +0,0 @@ -{ - "esnext": true, - - "disallowTrailingWhitespace": true, - "maximumLineLength": 120, - "requireCamelCaseOrUpperCaseIdentifiers": true, - "requireCapitalizedConstructors": true, - "requireCommaBeforeLineBreak": true, - "requireDotNotation": true, - "requireKeywordsOnNewLine": [ "else" ], - "requireLineBreakAfterVariableAssignment": true, - "requireLineFeedAtFileEnd": true, - "requirePaddingNewLinesBeforeExport": true, - "requireSemicolons": true, - "requireSpaceAfterKeywords": true, - "requireSpaceAfterLineComment": true, - "requireSpaceBeforeBlockStatements": true, - "requireSpaceBeforeObjectValues": true, - "requireSpaceBetweenArguments": true, - "requireSpacesInAnonymousFunctionExpression": { - "beforeOpeningRoundBrace": true, - "beforeOpeningCurlyBrace": true - }, - "requireSpacesInConditionalExpression": true, - "requireSpacesInForStatement": true, - "requireSpacesInsideArrayBrackets": "all", - "requireSpacesInsideObjectBrackets": "all", - "validateIndentation": 2, - "validateParameterSeparator": ", ", - "validateQuoteMarks": true -} \ No newline at end of file diff --git a/gulpfile.babel.js b/gulpfile.babel.js index 2ba8964..e4bc1de 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -8,13 +8,13 @@ import fs from 'fs'; import gulp from 'gulp'; import merge from 'merge-stream'; import mkdirp from 'mkdirp'; -import packg from './package.json'; import rename from 'gulp-rename'; import rjs from 'requirejs'; import runseq from 'run-sequence'; import source from 'vinyl-source-stream'; import template from 'gulp-template'; import zip from 'gulp-zip'; +import packg from './package.json'; gulp.task('clean-lib', cb => { del('lib', cb); @@ -24,32 +24,30 @@ gulp.task('clean-build', cb => { del('build', cb); }); -gulp.task('clean', [ 'clean-lib', 'clean-build' ]); +gulp.task('clean', ['clean-lib', 'clean-build']); -gulp.task('babel', () => { - return gulp.src('src/**/*.js') +gulp.task('babel', () => + gulp.src('src/**/*.js') .pipe(babel({ presets: ['extplug'], - plugins: ['external-helpers'] + plugins: ['external-helpers'], })) .pipe(babelHelpers('_babelHelpers.js', 'var')) - .pipe(gulp.dest('lib/')); -}); - -const nodelib = (entry, standalone, name) => { - name = name || `${standalone}.js`; + .pipe(gulp.dest('lib/')) +); - let opts = { - entries: `./node_modules/${entry}` - }; - if (standalone) opts.standalone = standalone; - - return () => { - return browserify(opts) - .bundle() - .pipe(source(name)) - .pipe(gulp.dest('build/_deps/')); +const nodelib = (entry, standalone, name = `${standalone}.js`) => { + const opts = { + entries: `./node_modules/${entry}`, }; + if (standalone) { + opts.standalone = standalone; + } + + return () => browserify(opts) + .bundle() + .pipe(source(name)) + .pipe(gulp.dest('build/_deps/')); }; gulp.task('lib-debug', nodelib('debug/browser.js', 'debug')); @@ -63,18 +61,18 @@ gulp.task('dependencies', [ 'lib-semvercmp', 'lib-sistyl', 'lib-symbol', - 'lib-regexp-quote' + 'lib-regexp-quote', ]); gulp.task('rjs', done => { - let npm = 'node_modules/'; + const npm = 'node_modules/'; packg.builtAt = Date.now(); - let packgString = JSON.stringify(packg, null, 2); + const packgString = JSON.stringify(packg, null, 2); delete packg.builtAt; rjs.optimize({ baseUrl: './', name: 'extplug/main', - include: [ 'extplug/ExtPlug' ], + include: ['extplug/ExtPlug'], paths: { // plug-modules defines, these are defined at runtime // so the r.js optimizer can't find them @@ -83,43 +81,41 @@ gulp.task('rjs', done => { backbone: 'empty:', jquery: 'empty:', underscore: 'empty:', - meld: npm + 'meld/meld', + meld: `${npm}meld/meld`, sistyl: 'build/_deps/sistyl', extplug: 'lib', 'plug-modules': `${npm}plug-modules/plug-modules`, - 'debug': 'build/_deps/debug', - 'onecolor': `${npm}onecolor/one-color-all`, + debug: 'build/_deps/debug', + onecolor: `${npm}onecolor/one-color-all`, 'regexp-quote': 'build/_deps/regexp-quote', - 'semver-compare': 'build/_deps/semvercmp' + 'semver-compare': 'build/_deps/semvercmp', }, rawText: { - 'extplug/package': `define(${packgString})` + 'package.json': `define(${packgString})`, + 'extplug/package': `define(${packgString})`, }, - insertRequire: [ 'extplug/main' ], + insertRequire: ['extplug/main'], optimize: 'none', out(text) { mkdirp('build', e => { if (e) { done(e); - } - else { + } else { fs.writeFile('build/build.rjs.js', text, done); } }); - } + }, }); }); -gulp.task('concat', () => { - return gulp.src([ 'build/_deps/es6-symbol.js' - , 'lib/_babelHelpers.js' - , 'build/build.rjs.js' ]) +gulp.task('concat', () => + gulp.src(['build/_deps/es6-symbol.js', 'lib/_babelHelpers.js', 'build/build.rjs.js']) .pipe(concat('extplug.code.js')) - .pipe(gulp.dest('build/')); -}); + .pipe(gulp.dest('build/')) +); -gulp.task('build', [ 'concat' ], () => { - return gulp.src('src/loader.js.template') +gulp.task('build', ['concat'], () => + gulp.src('src/loader.js.template') .pipe(data((file, cb) => { fs.readFile('build/extplug.code.js', 'utf8', (e, c) => { if (e) cb(e); @@ -128,65 +124,61 @@ gulp.task('build', [ 'concat' ], () => { })) .pipe(template()) .pipe(rename('extplug.js')) - .pipe(gulp.dest('build/')); -}); + .pipe(gulp.dest('build/')) +); -gulp.task('chrome-unpacked', cb => { - return merge( - gulp.src([ 'extensions/chrome/main.js', 'extensions/chrome/manifest.json' ]) - .pipe(template(packg)) - .pipe(gulp.dest('build/chrome/')), +gulp.task('chrome-unpacked', () => merge( + gulp.src(['extensions/chrome/main.js', 'extensions/chrome/manifest.json']) + .pipe(template(packg)) + .pipe(gulp.dest('build/chrome/')), - gulp.src([ 'img/icon*.png' ]) - .pipe(gulp.dest('build/chrome/img/')), + gulp.src(['img/icon*.png']) + .pipe(gulp.dest('build/chrome/img/')), - gulp.src([ 'build/extplug.js' ]) - .pipe(concat('extplug.js')) - .pipe(gulp.dest('build/chrome/')) - ); -}); + gulp.src(['build/extplug.js']) + .pipe(concat('extplug.js')) + .pipe(gulp.dest('build/chrome/')) +)); -gulp.task('chrome-pack', () => { - return gulp.src('build/chrome/*') +gulp.task('chrome-pack', () => + gulp.src('build/chrome/*') .pipe(zip('extplug.chrome.zip')) - .pipe(gulp.dest('build/')); -}); + .pipe(gulp.dest('build/')) +); gulp.task('chrome', cb => { runseq('chrome-unpacked', 'chrome-pack', cb); }); -gulp.task('firefox', () => { - return merge( - gulp.src([ 'extensions/firefox/*' ]) - .pipe(template(packg)) - .pipe(gulp.dest('build/firefox/')), +gulp.task('firefox', () => merge( + gulp.src(['extensions/firefox/*']) + .pipe(template(packg)) + .pipe(gulp.dest('build/firefox/')), - gulp.src([ 'build/extplug.js' ]) - .pipe(gulp.dest('build/firefox/data/')) - ); -}); + gulp.src(['build/extplug.js']) + .pipe(gulp.dest('build/firefox/data/')) +)); -gulp.task('userscript-meta', () => { - return gulp.src([ 'extensions/userscript/extplug.user.js' ]) +gulp.task('userscript-meta', () => + gulp.src(['extensions/userscript/extplug.user.js']) .pipe(template(packg)) .pipe(rename('extplug.meta.user.js')) - .pipe(gulp.dest('build/')); -}); + .pipe(gulp.dest('build/')) +); -gulp.task('userscript', [ 'userscript-meta' ], () => { - return gulp.src([ 'build/extplug.meta.user.js', 'build/extplug.js' ]) +gulp.task('userscript', ['userscript-meta'], () => + gulp.src(['build/extplug.meta.user.js', 'build/extplug.js']) .pipe(concat('extplug.user.js')) - .pipe(gulp.dest('build/')); -}); + .pipe(gulp.dest('build/')) +); gulp.task('default', cb => { runseq( 'clean', - [ 'babel', 'dependencies' ], + ['babel', 'dependencies'], 'rjs', 'build', - [ 'chrome', 'firefox', 'userscript' ], + ['chrome', 'firefox', 'userscript'], cb ); }); diff --git a/package.json b/package.json index 4ef8ce0..33da491 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "underscore": "^1.6.0" }, "devDependencies": { + "babel-eslint": "^6.1.2", "babel-plugin-external-helpers": "^6.5.0", "babel-preset-es2015": "^6.9.0", "babel-preset-extplug": "^1.0.0", @@ -41,6 +42,6 @@ }, "scripts": { "build": "gulp build", - "test": "eslint gulpfile.babel.js src/**/*.js test/**/*.js" + "test": "eslint gulpfile.babel.js src test" } } diff --git a/src/ExtPlug.js b/src/ExtPlug.js index c964f2e..ca58fbb 100644 --- a/src/ExtPlug.js +++ b/src/ExtPlug.js @@ -1,10 +1,10 @@ +import * as _ from 'underscore'; + import Events from 'plug/core/Events'; import ApplicationView from 'plug/views/app/ApplicationView'; import currentUser from 'plug/models/currentUser'; -import settings from './store/settings'; import RoomSettings from './models/RoomSettings'; -import PluginMeta from './models/PluginMeta'; import PluginsCollection from './collections/PluginsCollection'; import Plugin from './Plugin'; import * as pluginLoader from './pluginLoader'; @@ -21,10 +21,7 @@ import SocketEventsPlugin from './plugins/SocketEventsPlugin'; import WaitlistEventsPlugin from './plugins/WaitlistEventsPlugin'; import PlugSettingsPlugin from './plugins/PlugSettingsPlugin'; -import * as _package from './package'; - -import * as _ from 'underscore'; -import semvercmp from 'semver-compare'; +import * as packageMeta from '../package.json'; import hooks from './hooks/index'; @@ -38,9 +35,11 @@ const LS_NAME = 'extPlugins'; // Try to parse as JSON, defaulting to an empty object. function jsonParse(str) { - try { return JSON.parse(str) || {}; } - catch (e) {} - return {}; + try { + return JSON.parse(str) || {}; + } catch (e) { + return {}; + } } /** @@ -55,7 +54,7 @@ function jsonParse(str) { * @return {ApplicationView} The ApplicationView instance of this page. */ function getApplicationView() { - let evts = Events._events['show:room']; + const evts = Events._events['show:room']; // eslint-disable-line no-underscore-dangle // Backbone event handlers have a .ctx property, containing what they will be bound to. // And ApplicationView adds a handler that's bound to itself! let appView; @@ -75,13 +74,19 @@ function getApplicationView() { */ const ExtPlug = Plugin.extend({ name: 'ExtPlug', + settings: { - corsProxy: { type: 'boolean', default: true, label: 'Use CORS proxy' } + corsProxy: { + type: 'boolean', + default: true, + label: 'Use CORS proxy', + }, }, + init() { this._super('extplug', this); - this._core = [ + this.corePlugins = [ new CommandsPlugin('extplug:chat-commands', this), new SettingsTabPlugin('extplug:settings-tab', this), new MoreChatEventsPlugin('extplug:more-chat-events', this), @@ -91,10 +96,17 @@ const ExtPlug = Plugin.extend({ new TooltipsPlugin('extplug:tooltips', this), new SocketEventsPlugin('extplug:socket-events', this), new WaitlistEventsPlugin('extplug:waitlist-events', this), - new PlugSettingsPlugin('extplug:plug-settings', this) + new PlugSettingsPlugin('extplug:plug-settings', this), ]; - this._guest = new GuestPlugin('extplug:guest', this); + this.guestPlugin = new GuestPlugin('extplug:guest', this); + + // Alias for compatibility with old versions. + Object.defineProperty(this, '_plugins', { + get() { + return this.plugins; + }, + }); }, /** @@ -104,20 +116,24 @@ const ExtPlug = Plugin.extend({ */ registerPlugin(id, cb) { pluginLoader.load(id, (e, meta) => { - if (e) return cb && cb(e); - this._plugins.add(meta); - let instance = meta.get('instance'); - let state = this._getPluginSettings(meta.get('id')); + if (e) { + if (cb) cb(e); + return; + } + + this.plugins.add(meta); + const instance = meta.get('instance'); + const state = this.getPluginSettings(meta.get('id')); instance.settings.set(state.settings); instance.settings.on('change', () => { - this._savePluginSettings(meta.get('id')); + this.savePluginSettings(meta.get('id')); }); if (state.enabled) { - _.defer(() => { - meta.enable(); - }); + _.defer(() => meta.enable()); + } + if (cb) { + cb(null); } - if (cb) cb(null); }); return this; }, @@ -126,15 +142,15 @@ const ExtPlug = Plugin.extend({ * Disables and removes an ExtPlug plugin. */ unregisterPlugin(id) { - let plugin = this._plugins.findWhere({ id: id }); + const plugin = this.plugins.findWhere({ id }); if (plugin) { plugin.disable(); - this._plugins.remove(plugin); + this.plugins.remove(plugin); } }, getPlugin(id) { - let meta = this._plugins.get(id); + const meta = this.plugins.get(id); return meta ? meta.get('instance') : null; }, @@ -145,9 +161,12 @@ const ExtPlug = Plugin.extend({ */ install(id, cb) { this.registerPlugin(id, (e) => { - if (e) return cb(e); - let json = jsonParse(localStorage.getItem(LS_NAME)); - json.installed = (json.installed || []).concat([ id ]); + if (e) { + cb(e); + return; + } + const json = jsonParse(localStorage.getItem(LS_NAME)); + json.installed = (json.installed || []).concat([id]); localStorage.setItem(LS_NAME, JSON.stringify(json)); cb(null); }); @@ -158,9 +177,9 @@ const ExtPlug = Plugin.extend({ */ uninstall(id) { this.unregisterPlugin(id); - let json = jsonParse(localStorage.getItem(LS_NAME)); + const json = jsonParse(localStorage.getItem(LS_NAME)); if (json.installed) { - let i = json.installed.indexOf(id); + const i = json.installed.indexOf(id); if (i !== -1) { json.installed.splice(i, 1); localStorage.setItem(LS_NAME, JSON.stringify(json)); @@ -171,20 +190,19 @@ const ExtPlug = Plugin.extend({ /** * Loads installed plugins. */ - _loadInstalled() { - let { installed } = jsonParse(localStorage.getItem(LS_NAME)); + loadInstalledPlugins() { + const { installed } = jsonParse(localStorage.getItem(LS_NAME)); if (_.isArray(installed)) { - let l = installed.length; + const l = installed.length; let i = 0; - let errors = []; + const errors = []; const done = () => { if (errors.length) { errors.forEach(e => { Events.trigger('notify', 'icon-chat-system', `Plugin error: ${e.message}`); }); - } - else if (i > 0) { + } else if (i > 0) { Events.trigger('notify', 'icon-plug-dj', `ExtPlug: loaded ${i} plugins.`); } @@ -212,7 +230,7 @@ const ExtPlug = Plugin.extend({ */ onFirstRun() { localStorage.setItem(LS_NAME, JSON.stringify({ - version: _package.version, + version: packageMeta.version, installed: [ 'autowoot/build/autowoot.js;extplug/autowoot/main', 'chat-notifications/build/chat-notifications.js;' + @@ -222,9 +240,9 @@ const ExtPlug = Plugin.extend({ 'hide-badges/build/hide-badges.js;extplug/hide-badges/main', 'meh-icons/build/meh-icons.js;extplug/meh-icons/main', 'room-styles/build/room-styles.js;extplug/room-styles/main', - 'show-deleted/build/show-deleted.js;extplug/show-deleted/main' + 'show-deleted/build/show-deleted.js;extplug/show-deleted/main', ].map(path => `https://extplug.github.io/${path}`), - plugins: {} + plugins: {}, })); }, @@ -242,9 +260,9 @@ const ExtPlug = Plugin.extend({ /** * Internal map of registered plugins. */ - this._plugins = new PluginsCollection(); - this._plugins.on('change:enabled', (plugin, enabled) => { - this._savePluginSettings(plugin.get('id')); + this.plugins = new PluginsCollection(); + this.plugins.on('change:enabled', plugin => { + this.savePluginSettings(plugin.get('id')); }); if (this.isFirstRun()) this.onFirstRun(); @@ -258,7 +276,7 @@ const ExtPlug = Plugin.extend({ hook.install(); }); - this._core.forEach(plugin => { + this.corePlugins.forEach(plugin => { plugin.enable(); }); @@ -272,13 +290,13 @@ const ExtPlug = Plugin.extend({ // room settings this.roomSettings = new RoomSettings(this); - this._loadInstalled(); - Events.trigger('notify', 'icon-plug-dj', `ExtPlug v${_package.version} loaded`); + this.loadInstalledPlugins(); + Events.trigger('notify', 'icon-plug-dj', `ExtPlug v${packageMeta.version} loaded`); if (currentUser.get('guest')) { - this._guest.enable(); + this.guestPlugin.enable(); currentUser.once('change:guest', () => { - this._guest.disable(); + this.guestPlugin.disable(); }); } @@ -291,17 +309,17 @@ const ExtPlug = Plugin.extend({ * Everything should be unloaded here, so the Plug.DJ page looks like nothing ever happened. */ disable() { - this._plugins.off().forEach(mod => { + this.plugins.off().forEach(mod => { mod.disable(); }); - this._core.forEach(plugin => { + this.corePlugins.forEach(plugin => { plugin.disable(); }); hooks.forEach(hook => { hook.uninstall(); }); - this._guest.disable(); + this.guestPlugin.disable(); // remove room settings handling this.roomSettings.dispose(); @@ -313,20 +331,28 @@ const ExtPlug = Plugin.extend({ * Persists plugin settings to localStorage. * @private */ - _savePluginSettings(id) { - let json = jsonParse(localStorage.getItem(LS_NAME)); - let plugin = this._plugins.findWhere({ id: id }); - let settings = plugin.get('instance').settings; - if (!json.plugins) json.plugins = {}; - json.plugins[id] = { enabled: plugin.get('enabled'), settings: settings }; + savePluginSettings(id) { + const json = jsonParse(localStorage.getItem(LS_NAME)); + const plugin = this.plugins.findWhere({ id }); + const settings = plugin.get('instance').settings; + + if (!json.plugins) { + json.plugins = {}; + } + + json.plugins[id] = { + enabled: plugin.get('enabled'), + settings, + }; + localStorage.setItem(LS_NAME, JSON.stringify(json)); }, /** * Retrieves plugin settings from localStorage. */ - _getPluginSettings(id) { - let settings = jsonParse(localStorage.getItem(LS_NAME)).plugins; + getPluginSettings(id) { + const settings = jsonParse(localStorage.getItem(LS_NAME)).plugins; if (settings && id in settings) { return settings[id]; } @@ -338,7 +364,7 @@ const ExtPlug = Plugin.extend({ */ upgrade() { // Empty - } + }, }); export default ExtPlug; diff --git a/src/Plugin.js b/src/Plugin.js index 5aa8126..43e65f9 100644 --- a/src/Plugin.js +++ b/src/Plugin.js @@ -1,31 +1,34 @@ import jQuery from 'jquery'; -import _ from 'underscore'; +import { each, extend, partial } from 'underscore'; import Backbone from 'backbone'; +import debug from 'debug'; +import quote from 'regexp-quote'; import Class from 'plug/core/Class'; import Settings from './models/Settings'; import Style from './util/Style'; import SettingsView from './views/users/settings/DefaultSettingsView'; -import debug from 'debug'; -import quote from 'regexp-quote'; -const stubHook = function () {}; -const hooks = [ 'enable', 'disable' ]; +const stubHook = () => {}; +const hooks = ['enable', 'disable']; + +const commandsSymbol = Symbol.for('extplug:commands'); +const stylesSymbol = Symbol.for('extplug:styles'); const Plugin = Class.extend({ init(id, ext) { - _.extend(this, Backbone.Events); + extend(this, Backbone.Events); this.id = id; this.ext = ext; this.debug = debug(`extplug:plugin:${id}`); - let settings = new Settings({}, { meta: this.settings }); + const settings = new Settings({}, { meta: this.settings }); if (this.settings) { - _.each(this.settings, (setting, name) => { + each(this.settings, (setting, name) => { settings.set(name, setting.default); }); - this._settings = this.settings; + this._settings = this.settings; // eslint-disable-line no-underscore-dangle } this.settings = settings; @@ -44,7 +47,7 @@ const Plugin = Class.extend({ value: () => { this.trigger(hookName); Plugin.trigger(hookName, this); - } + }, }); } }); @@ -54,7 +57,7 @@ const Plugin = Class.extend({ this.on('disable', this.stopListening); // Styles API - this._styles = []; + this[stylesSymbol] = []; if (this.style) { // declarative `style: {}` API this.on('enable', () => { @@ -66,11 +69,11 @@ const Plugin = Class.extend({ }); // Chat Commands API - this._commands = []; + this[commandsSymbol] = []; if (this.commands) { // declarative `commands: {}` API this.on('enable', () => { - _.each(this.commands, (method, name) => { + each(this.commands, (method, name) => { this.addCommand(name, this[method].bind(this)); }); }); @@ -81,7 +84,7 @@ const Plugin = Class.extend({ }, $(sel) { - this.debug(`Plugin#$ is deprecated. Use require('jquery') instead.`); + this.debug('Plugin#$ is deprecated. Use require(\'jquery\') instead.'); return jQuery(sel || document); }, @@ -96,19 +99,19 @@ const Plugin = Class.extend({ // Styles API createStyle(defaults = {}) { - let style = new Style(defaults); - this._styles.push(style); + const style = new Style(defaults); + this[stylesSymbol].push(style); return style; }, Style(defaults) { - this.debug(`Plugin#Style is deprecated. Use Plugin#createStyle instead.`); + this.debug('Plugin#Style is deprecated. Use Plugin#createStyle instead.'); return this.createStyle(defaults); }, removeStyles() { - if (this._styles) { - this._styles.forEach(style => style.remove()); + if (this[stylesSymbol]) { + this[stylesSymbol].forEach(style => style.remove()); } - this._styles = []; + this[stylesSymbol] = []; }, // Chat Commands API @@ -119,21 +122,20 @@ const Plugin = Class.extend({ cb(text.slice(name.length + 2)); } }; - this._commands.push(fn); + this[commandsSymbol].push(fn); API.on(API.CHAT_COMMAND, fn); }, removeCommands() { - this._commands.forEach(_.partial(API.off, API.CHAT_COMMAND), API); - this._commands = []; + this[commandsSymbol].forEach(partial(API.off, API.CHAT_COMMAND), API); + this[commandsSymbol] = []; }, // Settings API getSettingsView() { return new SettingsView({ model: this.settings }); - } - + }, }); -_.extend(Plugin, Backbone.Events); +extend(Plugin, Backbone.Events); export default Plugin; diff --git a/src/collections/PluginsCollection.js b/src/collections/PluginsCollection.js index 4d2f87c..4eb2957 100644 --- a/src/collections/PluginsCollection.js +++ b/src/collections/PluginsCollection.js @@ -4,10 +4,13 @@ import PluginMeta from '../models/PluginMeta'; const PluginsCollection = Collection.extend({ model: PluginMeta, comparator(a, b) { - return a.get('name') > b.get('name') ? 1 - : a.get('name') < b.get('name') ? -1 - : 0; - } + if (a.get('name') > b.get('name')) { + return 1; + } else if (a.get('name') < b.get('name')) { + return -1; + } + return 0; + }, }); export default PluginsCollection; diff --git a/src/hooks/api-early.js b/src/hooks/api-early.js index 2f98cb8..191bfdb 100644 --- a/src/hooks/api-early.js +++ b/src/hooks/api-early.js @@ -1,12 +1,12 @@ import meld from 'meld'; function intercept(joinpoint) { - let [ eventName, ...params ] = joinpoint.args; + const [eventName, ...params] = joinpoint.args; API.trigger.apply( API, // userLeave → beforeUserLeave - [ 'before' + eventName.charAt(0).toUpperCase() + eventName.slice(1), ...params ] + [`before${eventName.charAt(0).toUpperCase()}${eventName.slice(1)}`, ...params] ); return joinpoint.proceed(); @@ -15,23 +15,23 @@ function intercept(joinpoint) { function nop() { return 'Dummy handler to ensure that plug.dj actually triggers the event'; } // find default plug.dj API event names -let eventKeys = Object.keys(API).filter(key => { - return key.toUpperCase() === key && typeof API[key] === 'string'; -}); +const eventKeys = Object.keys(API).filter(key => + key.toUpperCase() === key && typeof API[key] === 'string' +); let advice; export function install() { advice = meld.around(API, 'dispatch', intercept); eventKeys.forEach(key => { // add the API constants for these, too - API[`BEFORE_${key}`] = 'before' + API[key].charAt(0).toUpperCase() + API[key].slice(1); + API[`BEFORE_${key}`] = `before${API[key].charAt(0).toUpperCase()}${API[key].slice(1)}`; // plug.dj checks if an event is actually attached (through the _events hash) // before dispatching. We might run into situations where there is a BEFORE_ // handler, but not a normal one, and we do need to get the BEFORE_ event to // trigger there. So we just pretend like we have handlers for all the things. API.on(API[key], nop); }); -}; +} export function uninstall() { eventKeys.forEach(key => { @@ -39,4 +39,4 @@ export function uninstall() { API.off(key, nop); }); advice.remove(); -}; +} diff --git a/src/hooks/index.js b/src/hooks/index.js index afa61ce..6114f23 100644 --- a/src/hooks/index.js +++ b/src/hooks/index.js @@ -5,5 +5,5 @@ import * as popoutStyleHook from './popout-style'; export default [ apiEarlyHook, playbackHook, - popoutStyleHook + popoutStyleHook, ]; diff --git a/src/hooks/playback.js b/src/hooks/playback.js index 9fc3c37..20772a1 100644 --- a/src/hooks/playback.js +++ b/src/hooks/playback.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Events from 'plug/core/Events'; function onRefresh() { Events.trigger('playback:refresh'); } @@ -8,10 +9,10 @@ export function install() { $('#playback .refresh.button').on('click', onRefresh); $('#playback .hd.button').on('click', onHd); $('#playback .snooze.button').on('click', onSnooze); -}; +} export function uninstall() { $('#playback .refresh.button').off('click', onRefresh); $('#playback .hd.button').off('click', onHd); $('#playback .snooze.button').off('click', onSnooze); -}; +} diff --git a/src/hooks/popout-style.js b/src/hooks/popout-style.js index 27f23e4..e6be3f1 100644 --- a/src/hooks/popout-style.js +++ b/src/hooks/popout-style.js @@ -1,17 +1,18 @@ import $ from 'jquery'; +import { defer } from 'underscore'; import Events from 'plug/core/Events'; import popoutView from 'plug/views/rooms/popout/PopoutView'; function sync() { - _.defer(() => { + defer(() => { popoutView.$document.find('head').append($('.extplug-style').clone()); }); } export function install() { Events.on('popout:show', sync); -}; +} export function uninstall() { Events.off('popout:show', sync); -}; +} diff --git a/src/main.js b/src/main.js index d662d91..cae18b7 100644 --- a/src/main.js +++ b/src/main.js @@ -1,7 +1,7 @@ import plugModules from 'plug-modules'; function waitFor(cond, fn) { - let i = setInterval(() => { + const i = setInterval(() => { if (cond()) { clearInterval(i); fn(); @@ -9,27 +9,26 @@ function waitFor(cond, fn) { }, 20); } -plugModules.run(); -plugModules.register(); - -require([ 'extplug/ExtPlug' ], function _loaded(ExtPlug) { - waitFor(appViewExists, () => { - let ext = new ExtPlug(); - window.extp = ext; - - ext.enable(); - }); -}); - function appViewExists() { try { // the ApplicationView attaches an event handler on instantiation. const AppView = plugModules.require('plug/views/app/ApplicationView'); const Events = plugModules.require('plug/core/Events'); - let evts = Events._events['show:room']; + const evts = Events._events['show:room']; // eslint-disable-line no-underscore-dangle return evts.some(event => event.ctx instanceof AppView); - } - catch (e) { + } catch (e) { return false; } } + +plugModules.run(); +plugModules.register(); + +window.require(['extplug/ExtPlug'], ExtPlug => { + waitFor(appViewExists, () => { + const ext = new ExtPlug(); + window.extp = ext; + + ext.enable(); + }); +}); diff --git a/src/models/PluginMeta.js b/src/models/PluginMeta.js index dac4bdb..0bd8a93 100644 --- a/src/models/PluginMeta.js +++ b/src/models/PluginMeta.js @@ -1,7 +1,6 @@ import { Model } from 'backbone'; const PluginMeta = Model.extend({ - defaults: { id: '', fullUrl: '', @@ -9,13 +8,13 @@ const PluginMeta = Model.extend({ name: '', description: '', instance: null, - class: null + class: null, }, initialize() { this.get('instance') - .on('enable', () => { this.set('enabled', true); }) - .on('disable', () => { this.set('enabled', false); }); + .on('enable', () => this.set('enabled', true)) + .on('disable', () => this.set('enabled', false)); }, enable() { @@ -28,8 +27,7 @@ const PluginMeta = Model.extend({ if (this.get('enabled')) { this.get('instance').disable(); } - } - + }, }); export default PluginMeta; diff --git a/src/models/RoomSettings.js b/src/models/RoomSettings.js index 8bcf16a..8b0d8ae 100644 --- a/src/models/RoomSettings.js +++ b/src/models/RoomSettings.js @@ -1,17 +1,15 @@ +import { defer } from 'underscore'; +import Backbone from 'backbone'; import currentRoom from 'plug/models/currentRoom'; import util from 'plug/util/util'; -import request from '../util/request'; -import Backbone from 'backbone'; import Events from 'plug/core/Events'; +import { json as getJson } from '../util/request'; const RoomSettings = Backbone.Model.extend({ - - constructor(ext) { + constructor() { Backbone.Model.call(this, {}); - this._loaded = {}; - - this.load = this.load.bind(this); + this.load = this.load.bind(this); this.unload = this.unload.bind(this); this.reload = this.reload.bind(this); @@ -23,16 +21,15 @@ const RoomSettings = Backbone.Model.extend({ }, load(unload = false) { - let description = currentRoom.get('description'), - m = description.match(/(?:^|\n)@(?:p3|rcs)=(.*?)(?:\n|$)/); + const description = currentRoom.get('description'); + const m = description.match(/(?:^|\n)@(?:p3|rcs)=(.*?)(?:\n|$)/); if (m) { - let url = util.h2t(m[1]); - request.json(url).then(settings => { + const url = util.h2t(m[1]); + getJson(url).then(settings => { if (unload) { this.unload(); - } - else { + } else { this.clear(); } this.set(settings); @@ -42,18 +39,15 @@ const RoomSettings = Backbone.Model.extend({ let message = ''; if (e.status === 0) { message += ' Your browser or an extension may be blocking its URL.'; - } - else if (e.status >= 400) { + } else if (e.status >= 400) { message += ' Its URL is not accessible.'; - } - else if (e.status) { - message += ' Status code: ' + e.status; + } else if (e.status) { + message += ` Status code: ${e.status}`; } Events.trigger('notify', 'icon-chat-system', - 'Room Settings could not be loaded for this room.' + message); + `Room Settings could not be loaded for this room.${message}`); }); - } - else if (unload) { + } else if (unload) { this.unload(); } }, @@ -65,7 +59,7 @@ const RoomSettings = Backbone.Model.extend({ reload() { // "joined" is set *after* "description" - _.defer(() => { + defer(() => { if (currentRoom.get('joined')) { this.load(true); } @@ -75,8 +69,7 @@ const RoomSettings = Backbone.Model.extend({ dispose() { this.unload(); currentRoom.off('change:description', this.reload); - } - + }, }); export default RoomSettings; diff --git a/src/models/Settings.js b/src/models/Settings.js index ae95827..cbfab24 100644 --- a/src/models/Settings.js +++ b/src/models/Settings.js @@ -1,15 +1,15 @@ import { Model } from 'backbone'; -const Settings = Model.extend({ +const metaSymbol = Symbol('settings schema'); +const Settings = Model.extend({ initialize(attrs, opts = {}) { - this._meta = opts.meta; + this[metaSymbol] = opts.meta; }, meta() { - return this._meta; - } - + return this[metaSymbol]; + }, }); export default Settings; diff --git a/src/pluginLoader.js b/src/pluginLoader.js index 40f6daa..b942704 100644 --- a/src/pluginLoader.js +++ b/src/pluginLoader.js @@ -1,9 +1,10 @@ -import request from './util/request'; import PluginMeta from './models/PluginMeta'; +const requirejs = window.requirejs; + function parse(name) { - let parts = name.split(';'); - let o = {}; + const parts = name.split(';'); + const o = {}; o.url = parts[0]; if (parts[1]) { o.name = parts[1]; @@ -15,8 +16,8 @@ function parse(name) { return o; } -export function load(url, cb) { - let o = parse(url); +export function load(url, cb) { // eslint-disable-line import/prefer-default-export + const o = parse(url); if (o.name) { // add module name alias to the plugin URL // this way, when we require([ module name ]), the plugin URL @@ -25,20 +26,24 @@ export function load(url, cb) { // and requirejs will figure everything out. // Chopping off the .js extension because require.js adds it // since we're actually requiring a module name and not a path. - requirejs({ paths: { [o.name]: o.url.replace(/\.js$/, '') } }); + requirejs({ + paths: { + [o.name]: o.url.replace(/\.js$/, ''), + }, + }); } - let pluginId = o.name || o.url; - let onLoad = Plugin => { - let instance = new Plugin(pluginId, window.extp); - let meta = new PluginMeta({ + const pluginId = o.name || o.url; + const onLoad = Plugin => { + const instance = new Plugin(pluginId, window.extp); + const meta = new PluginMeta({ id: pluginId, fullUrl: url, name: instance.name, description: instance.description, - instance: instance, - class: Plugin + instance, + class: Plugin, }); cb(null, meta); }; - requirejs([ pluginId ], onLoad, cb); -}; + requirejs([pluginId], onLoad, cb); +} diff --git a/src/plugins/ChatTypePlugin.js b/src/plugins/ChatTypePlugin.js index b1410e9..d99e74a 100644 --- a/src/plugins/ChatTypePlugin.js +++ b/src/plugins/ChatTypePlugin.js @@ -28,31 +28,31 @@ import Plugin from '../Plugin'; const ChatTypePlugin = Plugin.extend({ style: { '.badge-box .emoji-outer': { - 'margin': '7px' + margin: '7px', }, '.inline .badge-box .emoji-outer': { - 'margin': '0 7px' - } + margin: '0 7px', + }, }, enable() { // chatView.onReceived will still be the old method after adding advice // so the event listener should also be swapped out this.replaceEventHandler(() => { - this._chatTypeAdvice = around(ChatView.prototype, 'onReceived', this.onReceived); + this.chatTypeAdvice = around(ChatView.prototype, 'onReceived', this.onReceived); }); }, disable() { // remove custom chat type advice, and restore // the original event listener this.replaceEventHandler(() => { - this._chatTypeAdvice.remove(); + this.chatTypeAdvice.remove(); }); }, // bound to the ChatView instance onReceived(joinpoint) { - let message = joinpoint.args[0]; + const message = joinpoint.args[0]; if (message.type.split(' ').indexOf('custom') !== -1) { // plug.dj has some nice default styling on "update" messages message.type += ' update'; @@ -68,15 +68,15 @@ const ChatTypePlugin = Plugin.extend({ // insert the chat message element joinpoint.proceed(); - let el = this.$chatMessages.children().last(); + const el = this.$chatMessages.children().last(); if (message.classes) { el.addClass(message.classes); } if (message.badge) { - // emoji badge if (/^:(.*?):$/.test(message.badge)) { - let badgeBox = el.find('.badge-box'); - let emojiName = message.badge.slice(1, -1); + // emoji badge + const badgeBox = el.find('.badge-box'); + const emojiName = message.badge.slice(1, -1); if (emoji.map.colons[emojiName]) { badgeBox.find('i').remove(); badgeBox @@ -84,10 +84,9 @@ const ChatTypePlugin = Plugin.extend({ // compatibility class .find('.emoji-outer').addClass('extplug-badji'); } - } - // icon badge - else if (/^icon-(.*?)$/.test(message.badge)) { - let badgeBox = el.find('.badge-box'); + } else if (/^icon-(.*?)$/.test(message.badge)) { + // icon badge + const badgeBox = el.find('.badge-box'); badgeBox.find('i') .removeClass() .addClass('icon').addClass(message.badge); @@ -100,10 +99,13 @@ const ChatTypePlugin = Plugin.extend({ // replace callback without affecting calling order replaceEventHandler(fn) { - let chatView = this.ext.appView.room.chat; + const chatView = this.ext.appView.room.chat; let handler; if (chatView) { - handler = find(Events._events['chat:receive'], e => e.callback === chatView.onReceived); + handler = find( + Events._events['chat:receive'], // eslint-disable-line no-underscore-dangle + e => e.callback === chatView.onReceived + ); } fn(); if (chatView) { @@ -112,7 +114,7 @@ const ChatTypePlugin = Plugin.extend({ } handler.callback = chatView.onReceived; } - } + }, }); export default ChatTypePlugin; diff --git a/src/plugins/CommandsPlugin.js b/src/plugins/CommandsPlugin.js index 9a865a3..0d89ddb 100644 --- a/src/plugins/CommandsPlugin.js +++ b/src/plugins/CommandsPlugin.js @@ -1,15 +1,15 @@ import Plugin from '../Plugin'; -import _package from '../package'; +import packageMeta from '../../package.json'; // version info -const pad = x => x < 10 ? `0${x}` : x; -const ba = new Date(_package.builtAt); -const builtAt = ba.getUTCFullYear() + '-' - + pad(ba.getUTCMonth() + 1) + '-' - + pad(ba.getUTCDate() + 1) + ' ' - + pad(ba.getUTCHours() + 1) + ':' - + pad(ba.getUTCMinutes() + 1) + ':' - + pad(ba.getUTCSeconds() + 1) + ' UTC'; +const pad = x => (x < 10 ? `0${x}` : x); +const ba = new Date(packageMeta.builtAt); +const builtAt = `${ba.getUTCFullYear()}-` + + `${pad(ba.getUTCMonth() + 1)}-` + + `${pad(ba.getUTCDate() + 1)} ` + + `${pad(ba.getUTCHours())}:` + + `${pad(ba.getUTCMinutes())}:` + + `${pad(ba.getUTCSeconds())} UTC`; const CommandsPlugin = Plugin.extend({ name: 'Chat Commands', @@ -18,11 +18,11 @@ const CommandsPlugin = Plugin.extend({ commands: { version: 'showVersion', reloadsettings: 'reloadRoomSettings', - disable: 'disableExtPlug' + disable: 'disableExtPlug', }, showVersion() { - API.chatLog(`${_package.name} v${_package.version} (${builtAt})`); + API.chatLog(`${packageMeta.name} v${packageMeta.version} (${builtAt})`); }, reloadRoomSettings() { @@ -36,7 +36,7 @@ const CommandsPlugin = Plugin.extend({ API.chatLog('Disabling ExtPlug! ' + 'You cannot re-enable ExtPlug until the next refresh.'); this.ext.disable(); - } + }, }); export default CommandsPlugin; diff --git a/src/plugins/EmojiDataPlugin.js b/src/plugins/EmojiDataPlugin.js index b389955..e7f8232 100644 --- a/src/plugins/EmojiDataPlugin.js +++ b/src/plugins/EmojiDataPlugin.js @@ -1,7 +1,8 @@ -import Plugin from '../Plugin'; +import $ from 'jquery'; +import { around } from 'meld'; import Events from 'plug/core/Events'; import emoji from 'plug/util/emoji'; -import { around } from 'meld'; +import Plugin from '../Plugin'; const EmojiDataPlugin = Plugin.extend({ name: 'Emoji Data', @@ -12,11 +13,11 @@ const EmojiDataPlugin = Plugin.extend({ let name = joinpoint.args[2]; if (!name) { // attempt to find the name in the emoji-data map - let id = joinpoint.args[0]; - let data = emoji.data[id]; + const id = joinpoint.args[0]; + const data = emoji.data[id]; if (data) name = data[3][0]; } - let html = joinpoint.proceed(); + const html = joinpoint.proceed(); if (name) { return html.replace( ' class="emoji-inner', @@ -27,9 +28,9 @@ const EmojiDataPlugin = Plugin.extend({ }); this.listenTo(Events, 'chat:afterreceive', (msg, el) => { - el.find('.gemoji-plug').each(function () { - let inner = $(this); - let emojiName = inner.attr('class').match(/gemoji-plug-(\S+)/); + el.find('.gemoji-plug').each(function addDataAttr() { + const inner = $(this); + const emojiName = inner.attr('class').match(/gemoji-plug-(\S+)/); if (emojiName) { inner.attr('data-emoji-name', emojiName[1]) .addClass(`extplug-emoji-${name}`); @@ -40,7 +41,7 @@ const EmojiDataPlugin = Plugin.extend({ disable() { this.advice.remove(); - } + }, }); export default EmojiDataPlugin; diff --git a/src/plugins/GuestPlugin.js b/src/plugins/GuestPlugin.js index 2d9e83a..d70705c 100644 --- a/src/plugins/GuestPlugin.js +++ b/src/plugins/GuestPlugin.js @@ -1,10 +1,10 @@ import $ from 'jquery'; import { around } from 'meld'; -import Plugin from '../Plugin'; import Events from 'plug/core/Events'; import SaveSettingsAction from 'plug/actions/users/SaveSettingsAction'; import currentUser from 'plug/models/currentUser'; import Lang from 'lang/Lang'; +import Plugin from '../Plugin'; const GuestPlugin = Plugin.extend({ name: 'Guest UI', @@ -12,54 +12,56 @@ const GuestPlugin = Plugin.extend({ 'buttons to the plug.dj footer.', style: { + /* eslint-disable quote-props */ '.is-guest': { '#header-panel-bar': { '#chat-button': { 'width': '33%', - 'span': { 'display': 'none' } + 'span': { 'display': 'none' }, }, '#users-button': { 'left': '33%', - 'width': '34%' + 'width': '34%', }, '#waitlist-button': { 'left': '67%', - 'width': '33%' + 'width': '33%', }, - '#friends-button': { 'display': 'none' } + '#friends-button': { 'display': 'none' }, }, '#user-lists': { // even the staff one doesn't work for guest users! - '.button.staff, .button.ignored': { 'display': 'none' } + '.button.staff, .button.ignored': { 'display': 'none' }, }, '#footer-user': { '.signup': { 'width': '40%' }, '.signup.login': { 'margin-left': 'calc(40% + 1px)', 'width': 'calc(40% - 1px)', - 'background': '#555d70' + 'background': '#555d70', }, '.buttons': { 'display': 'block', '.button': { 'display': 'none' }, '.button.extplug-guest-settings': { 'display': 'block', - 'margin-left': '80%' - } - } + 'margin-left': '80%', + }, + }, }, '#user-menu .item:not(.settings)': { - 'display': 'none' + 'display': 'none', }, '#room-bar': { '.extplug-room-bar-overlay': { 'height': 'inherit', 'width': 'inherit', 'position': 'absolute', - 'z-index': 10 - } - } - } + 'z-index': 10, + }, + }, + }, + /* eslint-enable quote-props */ }, enable() { @@ -96,17 +98,16 @@ const GuestPlugin = Plugin.extend({ e.stopPropagation(); if ($('#room-settings').is(':visible')) { Events.trigger('hide:settings'); - } - else { + } else { Events.trigger('show:settings'); } }); - this._enabled = true; + this.guestEnabled = true; }, disable() { - if (this._enabled) { + if (this.guestEnabled) { this.ssaAdvice.remove(); this.$settings.remove(); this.$roomBar.remove(); @@ -115,7 +116,7 @@ const GuestPlugin = Plugin.extend({ this.$settings = this.$login = this.$signup = null; } - this._enabled = false; + this.guestEnabled = false; }, skipWalkthrough() { @@ -137,7 +138,7 @@ const GuestPlugin = Plugin.extend({ e.stopPropagation(); Events.trigger('tooltip:hide') .trigger('show:user', 'settings', 'extplug'); - } + }, }); diff --git a/src/plugins/MoreChatEventsPlugin.js b/src/plugins/MoreChatEventsPlugin.js index e5d8eaf..8dbb2fe 100644 --- a/src/plugins/MoreChatEventsPlugin.js +++ b/src/plugins/MoreChatEventsPlugin.js @@ -1,12 +1,12 @@ -import Plugin from '../Plugin'; +import $ from 'jquery'; +import { find } from 'underscore'; +import { before, after, joinpoint } from 'meld'; import chatFacade from 'plug/facades/chatFacade'; import currentUser from 'plug/models/currentUser'; import currentRoom from 'plug/models/currentRoom'; import ChatView from 'plug/views/rooms/chat/ChatView'; import Events from 'plug/core/Events'; -import { find } from 'underscore'; -import { before, after, joinpoint } from 'meld'; -import $ from 'jquery'; +import Plugin from '../Plugin'; // Adds a bunch of new chat events. // "chat:incoming" is fired as soon as a new message is received from the socket. @@ -24,7 +24,7 @@ function fireBeforeReceive(message, isSystemMessage) { // "chat:afterreceive" is fired after the message has been rendered. It gets two arguments: // The Message object, and a jQuery object containing the message DOM element. function fireAfterReceive(message) { - let element = $('#chat-messages .cm:last-child'); + const element = $('#chat-messages .cm:last-child'); Events.trigger('chat:afterreceive', message, element); } // "chat:send" is fired when the user sends a message. It takes a single argument: A string @@ -48,7 +48,9 @@ const MoreChatEvents = Plugin.extend({ enable() { Events.on('chat:receive', fireBeforeReceive); // ensure fireBeforeReceive is the first event handler to be called - Events._events['chat:receive'].unshift(Events._events['chat:receive'].pop()); + const receiveHandlers = + Events._events['chat:receive']; // eslint-disable-line no-underscore-dangle + receiveHandlers.unshift(receiveHandlers.pop()); this.incomingAdvice = before(chatFacade, 'onChatReceived', fireIncoming); this.replaceEventHandler(() => { this.afterReceiveAdvice = after(ChatView.prototype, 'onReceived', () => { @@ -67,16 +69,19 @@ const MoreChatEvents = Plugin.extend({ // replace callback without affecting calling order replaceEventHandler(fn) { - let chatView = this.ext.appView.room.chat; + const chatView = this.ext.appView.room.chat; let handler; if (chatView) { - handler = find(Events._events['chat:receive'], e => e.callback === chatView.onReceived); + handler = find( + Events._events['chat:receive'], // eslint-disable-line no-underscore-dangle + e => e.callback === chatView.onReceived + ); } fn(); if (chatView && handler) { handler.callback = chatView.onReceived; } - } + }, }); export default MoreChatEvents; diff --git a/src/plugins/PlugSettingsPlugin.js b/src/plugins/PlugSettingsPlugin.js index 613b779..eac829e 100644 --- a/src/plugins/PlugSettingsPlugin.js +++ b/src/plugins/PlugSettingsPlugin.js @@ -1,6 +1,8 @@ -import Plugin from '../Plugin'; +import $ from 'jquery'; +import { extend } from 'underscore'; import { before } from 'meld'; import plugSettings from 'plug/store/settings'; +import Plugin from '../Plugin'; import extMirror from '../store/settings'; const PlugSettingsPlugin = Plugin.extend({ @@ -18,7 +20,7 @@ const PlugSettingsPlugin = Plugin.extend({ }, sync() { - const newSettings = _.extend({}, plugSettings.settings); + const newSettings = extend({}, plugSettings.settings); const muted = $('#volume .icon').hasClass('icon-volume-off'); // when you mute a song using the volume button, plug.dj does not change the associated setting. // here we fake a volume of 0% anyway if the volume is muted, so ExtPlug modules can just @@ -28,7 +30,7 @@ const PlugSettingsPlugin = Plugin.extend({ } newSettings.muted = muted; extMirror.set(newSettings); - } + }, }); export default PlugSettingsPlugin; diff --git a/src/plugins/SettingsTabPlugin.js b/src/plugins/SettingsTabPlugin.js index 1df16ba..5302675 100644 --- a/src/plugins/SettingsTabPlugin.js +++ b/src/plugins/SettingsTabPlugin.js @@ -7,11 +7,10 @@ import TabMenuView from '../views/users/settings/TabMenuView'; import SettingsSectionView from '../views/users/settings/SettingsView'; const SettingsTabPlugin = Plugin.extend({ - enable() { - let userView = this.ext.appView.user; + const userView = this.ext.appView.user; Events.off('show:user', userView.show); - this._userPaneAdvice = after(UserView.prototype, 'show', (category, sub) => { + this.userPaneAdvice = after(UserView.prototype, 'show', (category, sub) => { if (category === 'settings' && sub === 'ext-plug') { this.view.menu.select(sub); } @@ -19,14 +18,13 @@ const SettingsTabPlugin = Plugin.extend({ Events.on('show:user', userView.show, userView); // Add ExtPlug tab to user settings - this._settingsTabAdvice = around(UserSettingsView.prototype, 'getMenu', () => { - return new TabMenuView(); - }); - this._settingsPaneAdvice = around(UserSettingsView.prototype, 'getView', joinpoint => { + this.settingsTabAdvice = around(UserSettingsView.prototype, 'getMenu', + () => new TabMenuView()); + this.settingsPaneAdvice = around(UserSettingsView.prototype, 'getView', joinpoint => { if (joinpoint.args[0] === 'ext-plug') { return new SettingsSectionView({ - plugins: this.ext._plugins, - ext: this.ext + plugins: this.ext.plugins, + ext: this.ext, }); } return joinpoint.proceed(); @@ -34,14 +32,13 @@ const SettingsTabPlugin = Plugin.extend({ }, disable() { - this._settingsTabAdvice.remove(); - this._settingsPaneAdvice.remove(); - let userView = this.ext.appView.user; + this.settingsTabAdvice.remove(); + this.settingsPaneAdvice.remove(); + const userView = this.ext.appView.user; Events.off('show:user', userView.show); - this._userPaneAdvice.remove(); + this.userPaneAdvice.remove(); Events.on('show:user', userView.show, userView); - } - + }, }); export default SettingsTabPlugin; diff --git a/src/plugins/SocketEventsPlugin.js b/src/plugins/SocketEventsPlugin.js index 2631a66..9f5b06b 100644 --- a/src/plugins/SocketEventsPlugin.js +++ b/src/plugins/SocketEventsPlugin.js @@ -1,36 +1,35 @@ -import Plugin from '../Plugin'; +import { defer, pick } from 'underscore'; +import { before } from 'meld'; import Events from 'plug/core/Events'; import chatFacade from 'plug/facades/chatFacade'; -import receiver from 'plug/server/socketReceiver'; import currentRoom from 'plug/models/currentRoom'; import currentUser from 'plug/models/currentUser'; -import { before } from 'meld'; -import { defer, pick } from 'underscore'; +import Plugin from '../Plugin'; const CHAT_INTERCEPT_STRING = `ExtPlugSocketIntercept${Math.random()}`; // gives the user all permissions client-side temporarily, to make sure that // a chat message will actually be passed to the socket. function sudo(cb) { - let originalUser = currentUser.toJSON(); + const originalUser = currentUser.toJSON(); currentUser.set({ id: 1, guest: false, level: 50, role: 5, - gRole: 5 + gRole: 5, }, { silent: true }); - let originalRoom = pick(currentRoom.toJSON(), 'joined', 'minChatLevel'); + const originalRoom = pick(currentRoom.toJSON(), 'joined', 'minChatLevel'); currentRoom.set({ joined: true, - minChatLevel: 0 + minChatLevel: 0, }, { silent: true }); // this forces the chat slowmode cooldown timer to always return 0, thus // working around slowmode - let originalMax = Math.max; - Math.max = () => 0 + const originalMax = Math.max; + Math.max = () => 0; cb(); @@ -40,12 +39,12 @@ function sudo(cb) { } function getSocket() { - let _send = WebSocket.prototype.send; + const send = WebSocket.prototype.send; let socket; - WebSocket.prototype.send = function (data) { + WebSocket.prototype.send = function sendIntercept(data) { if (data.indexOf(CHAT_INTERCEPT_STRING)) { socket = this; - WebSocket.prototype.send = _send; + WebSocket.prototype.send = send; } }; sudo(() => { @@ -53,14 +52,14 @@ function getSocket() { }); // restore even if it didn't work - WebSocket.prototype.send = _send; + WebSocket.prototype.send = send; return socket; } const SocketEventsPlugin = Plugin.extend({ enable() { - let plugin = this; + const plugin = this; this.socket = getSocket(); if (this.socket) { @@ -71,9 +70,9 @@ const SocketEventsPlugin = Plugin.extend({ // if ExtPlug loads before plug.dj connects, by overriding the WebSocket // constructor const WS = WebSocket; - WebSocket = function (arg) { + window.WebSocket = function WebSocketIntercept(arg) { plugin.debug('instance', arg); - let ws = new WS(arg); + const ws = new WS(arg); // wait for plug.dj to add handlers defer(() => { // find the socket object again, this new connection might be @@ -90,7 +89,7 @@ const SocketEventsPlugin = Plugin.extend({ }, disable() { - if (this.WS) WebSocket = this.WS; + if (this.WS) window.WebSocket = this.WS; if (this.advice) this.advice.remove(); this.WS = null; @@ -111,7 +110,7 @@ const SocketEventsPlugin = Plugin.extend({ }); } }); - } + }, }); export default SocketEventsPlugin; diff --git a/src/plugins/TooltipsPlugin.js b/src/plugins/TooltipsPlugin.js index e8fc95a..676fbe8 100644 --- a/src/plugins/TooltipsPlugin.js +++ b/src/plugins/TooltipsPlugin.js @@ -1,28 +1,28 @@ -import Plugin from '../Plugin'; -import Events from 'plug/core/Events'; import $ from 'jquery'; +import Events from 'plug/core/Events'; +import Plugin from '../Plugin'; const TooltipsPlugin = Plugin.extend({ name: 'Tooltips', description: 'Provides super easy tooltips using data attributes.', enable() { - this._doc = $(document) + this.document = $(document) .on('mouseenter.extplug.core.tooltips', '[data-tooltip]', this.onEnter) .on('mouseleave.extplug.core.tooltips', '[data-tooltip]', this.onLeave); }, disable() { - this._doc.off('.extplug.tooltips'); + this.document.off('.extplug.tooltips'); }, onEnter(e) { - let target = $(e.target).closest('[data-tooltip]'); - let dir = target.attr('data-tooltip-dir'); - let alignLeft = dir && dir.toLowerCase() === 'left'; + const target = $(e.target).closest('[data-tooltip]'); + const dir = target.attr('data-tooltip-dir'); + const alignLeft = dir && dir.toLowerCase() === 'left'; Events.trigger('tooltip:show', target.attr('data-tooltip'), target, alignLeft); }, - onLeave(e) { + onLeave() { Events.trigger('tooltip:hide'); }, diff --git a/src/plugins/UserClassesPlugin.js b/src/plugins/UserClassesPlugin.js index 7303d90..0004dd8 100644 --- a/src/plugins/UserClassesPlugin.js +++ b/src/plugins/UserClassesPlugin.js @@ -1,12 +1,13 @@ -import Plugin from '../Plugin'; -import getUserClasses from '../util/getUserClasses'; +import $ from 'jquery'; +import { defer } from 'underscore'; +import { after } from 'meld'; import Events from 'plug/core/Events'; import currentUser from 'plug/models/currentUser'; import UserRowView from 'plug/views/rooms/users/RoomUserRowView'; import WaitListRowView from 'plug/views/rooms/users/WaitListRowView'; import userRolloverView from 'plug/views/users/userRolloverView'; -import { after } from 'meld'; -import { defer } from 'underscore'; +import Plugin from '../Plugin'; +import getUserClasses from '../util/getUserClasses'; const r = API.ROLE; const { roleClasses } = getUserClasses; @@ -18,20 +19,19 @@ const UserClasses = Plugin.extend({ enable() { this.listenTo(Events, 'chat:beforereceive', this.onChat); - let plugin = this; // common advice for user lists - let rowAdvice = function () { + const rowAdvice = function afterUpdateRow() { // `this` is the row view - let id = this.model.get('id'); + const id = this.model.get('id'); if (id) { this.$el.addClass(getUserClasses(id).join(' ')); } }; this.rowClasses = after(UserRowView.prototype, 'draw', rowAdvice); this.waitListClasses = after(WaitListRowView.prototype, 'render', rowAdvice); - this.rolloverClasses = after(userRolloverView, 'showSimple', function () { + this.rolloverClasses = after(userRolloverView, 'showSimple', function afterShowSimple() { // `this` is the rollover view - let id = this.user.get('id'); + const id = this.user.get('id'); if (id) { this.$el.addClass(getUserClasses(id).join(' ')); } @@ -47,7 +47,7 @@ const UserClasses = Plugin.extend({ }, onChat(msg) { - let classes = msg.classes ? [ msg.classes ] : []; + const classes = msg.classes ? [msg.classes] : []; if (msg.uid) { classes.push(...getUserClasses(msg.uid)); // additional plugCubed chat-only classes @@ -55,15 +55,14 @@ const UserClasses = Plugin.extend({ // just use getUserClasses() classes.push(`fromID-${msg.uid}`); - let user = API.getUser(msg.uid); + const user = API.getUser(msg.uid); if (msg.uid === API.getUser().id) { classes.push('from-you'); } if (user) { if (user.gRole === r.HOST) { classes.push('from-admin'); - } - else if (user.gRole >= r.BOUNCER) { + } else if (user.gRole >= r.BOUNCER) { classes.push('from-ambassador'); } if (user.friend) { @@ -97,16 +96,16 @@ const UserClasses = Plugin.extend({ setUserFooterClass() { defer(() => { - let footer = $('#footer-user'); - let online = footer.hasClass('online'); - let showing = footer.hasClass('showing'); + const footer = $('#footer-user'); + const online = footer.hasClass('online'); + const showing = footer.hasClass('showing'); footer .removeClass() .toggleClass('online', online) .toggleClass('showing', showing) .addClass(getUserClasses(API.getUser().id).join(' ')); }); - } + }, }); export default UserClasses; diff --git a/src/plugins/WaitlistEventsPlugin.js b/src/plugins/WaitlistEventsPlugin.js index 7a5114f..8f9cd41 100644 --- a/src/plugins/WaitlistEventsPlugin.js +++ b/src/plugins/WaitlistEventsPlugin.js @@ -1,19 +1,17 @@ -import Plugin from '../Plugin'; -import booth from 'plug/models/booth'; -import waitlist from 'plug/collections/waitlist'; -import users from 'plug/collections/users'; import { difference, extend } from 'underscore'; +import booth from 'plug/models/booth'; +import Plugin from '../Plugin'; const events = { WAIT_LIST_LEAVE: 'waitListLeave', - WAIT_LIST_JOIN: 'waitListJoin' + WAIT_LIST_JOIN: 'waitListJoin', }; function onChange() { - let newList = booth.get('waitingDJs'); - let oldList = booth.previous('waitingDJs'); - let left = difference(oldList, newList); - let entered = difference(newList, oldList); + const newList = booth.get('waitingDJs'); + const oldList = booth.previous('waitingDJs'); + const left = difference(oldList, newList); + const entered = difference(newList, oldList); left.forEach(uid => { API.dispatch(API.WAIT_LIST_LEAVE, API.getUser(uid)); @@ -37,7 +35,7 @@ const WaitlistEvents = Plugin.extend({ Object.keys(events).forEach(n => { delete API[n]; }); - } + }, }); export default WaitlistEvents; diff --git a/src/styles/badge.js b/src/styles/badge.js index cd09565..68d5e7f 100644 --- a/src/styles/badge.js +++ b/src/styles/badge.js @@ -1,3 +1,5 @@ +/* eslint-disable quote-props */ + // the red ExtPlug badge in the top left corner export default { '#app-menu .button i:after': { @@ -11,6 +13,7 @@ export default { 'padding': '1px 4px', 'margin-top': '5px', 'position': 'relative', - 'float': 'right' - } + 'float': 'right', + }, }; +/* eslint-enable quote-props */ diff --git a/src/styles/inline-chat.js b/src/styles/inline-chat.js index c8ce181..2b35f45 100644 --- a/src/styles/inline-chat.js +++ b/src/styles/inline-chat.js @@ -1,3 +1,4 @@ +/* eslint-disable quote-props */ // inline chat messages show the message contents immediately after // the username instead of below it. export default { @@ -14,21 +15,26 @@ export default { // center badge icons '.icon': { 'top': '50%', - 'margin-top': '-15px' + 'margin-top': '-15px', }, // center & resize actual user badges '.bdg': { 'top': '-7px', - 'transform': 'scale(0.5)' - } + 'transform': 'scale(0.5)', + }, + }, + '.from': { + 'display': 'inline', + }, + '.text': { + 'display': 'inline', + 'margin-left': '5px', }, - '.from': { 'display': 'inline' }, - '.text': { 'display': 'inline', 'margin-left': '5px' }, '.delete-button': { 'padding': '3px 10px', - 'top': '3px' - } + 'top': '3px', + }, }, // remove the empty circle for badge-less users // (it doesn't fit in a 16px high message) @@ -38,6 +44,7 @@ export default { 'top': '0px', 'left': '0px', 'border': 'none', - 'border-radius': '0px' - } + 'border-radius': '0px', + }, }; +/* eslint-enable quote-props */ diff --git a/src/styles/install-plugin-dialog.js b/src/styles/install-plugin-dialog.js index c898a43..d7076a3 100644 --- a/src/styles/install-plugin-dialog.js +++ b/src/styles/install-plugin-dialog.js @@ -1,10 +1,18 @@ +/* eslint-disable quote-props */ export default { '#dialog-install-plugin': { // magic numbers! stolen from other plug.dj dialogs - '.dialog-body': { 'height': '137px' }, - '.message': { 'top': '21px' }, + '.dialog-body': { + 'height': '137px', + }, + '.message': { + 'top': '21px', + }, // centered spinner - '.spinner': { 'top': '50%', 'left': '50%' }, + '.spinner': { + 'top': '50%', + 'left': '50%', + }, // Plugin URL input, center-aligned and wide '.dialog-input-background': { 'top': '67px', @@ -12,8 +20,9 @@ export default { 'height': '43px', 'left': '25px', 'input': { - 'width': '440px' - } - } - } + 'width': '440px', + }, + }, + }, }; +/* eslint-enable quote-props */ diff --git a/src/styles/settings-pane.js b/src/styles/settings-pane.js index 18cb0a2..1050085 100644 --- a/src/styles/settings-pane.js +++ b/src/styles/settings-pane.js @@ -1,3 +1,4 @@ +/* eslint-disable quote-props */ export default { '#user-view #user-settings': { // unlike plug.dj's own settings, ExtPlug settings are grouped @@ -6,7 +7,7 @@ export default { // manual margins around the header to make things look somewhat // alike. '.extplug.control-group:not(:first-child) .header': { - 'margin': '35px 0 8px 0 !important' + 'margin': '35px 0 8px 0 !important', }, // footer below grouped plugin settings @@ -14,8 +15,8 @@ export default { 'clear': 'both', 'button': { 'top': 'auto', - 'position': 'relative' - } + 'position': 'relative', + }, }, // numeric range slider @@ -23,32 +24,32 @@ export default { // plug.dj has three labels on sliders, but ExtPlug sliders // just have two counter labels because it's easier '.counts .count:nth-child(2)': { - 'float': 'right' - } + 'float': 'right', + }, }, '.extplug-dropdown': { '.title': { - 'top': '6px' + 'top': '6px', }, '.dropdown': { 'width': '50%', 'top': '-5px', - 'margin-left': '50%' + 'margin-left': '50%', }, '.extplug-dropdown-up': { 'dd': { 'position': 'absolute', 'bottom': '39px', - 'width': '100%' - } - } + 'width': '100%', + }, + }, }, 'label.title': { 'top': '0px', 'font-size': '14px', - 'width': '50%' + 'width': '50%', }, '.extplug-input': { @@ -61,7 +62,7 @@ export default { 'padding': '1px', 'width': '47%', 'left': '50%', - 'top': '-6px' + 'top': '-6px', }, 'input': { 'padding': '1px 1px 1px 5px', @@ -71,12 +72,12 @@ export default { 'font': '14px "Open Sans", sans-serif', 'color': '#ccc', 'background': 'transparent', - 'border': 'none' + 'border': 'none', }, '.error': { // someone decided to !important the default .focused style ): - 'box-shadow': 'inset 0 0 0 1px #f04f30 !important' - } + 'box-shadow': 'inset 0 0 0 1px #f04f30 !important', + }, }, // colour inputs @@ -86,12 +87,12 @@ export default { 'width': '23px', 'top': '4px', 'left': '4px', - 'position': 'absolute' + 'position': 'absolute', }, 'input': { 'width': 'calc(100% - 29px)', - 'margin-left': '29px' - } + 'margin-left': '29px', + }, }, // playlist select @@ -108,15 +109,16 @@ export default { // cut off long playlist names 'white-space': 'nowrap', 'text-overflow': 'ellipsis', - 'overflow': 'hidden' - } - } + 'overflow': 'hidden', + }, + }, }, '.extplug-playlist-select-menu': { '.icon-playlist': { 'top': '9px', - 'left': '9px' - } - } + 'left': '9px', + }, + }, }; +/* eslint-enable quote-props */ diff --git a/src/util/Style.js b/src/util/Style.js index aea5f8f..8b17393 100644 --- a/src/util/Style.js +++ b/src/util/Style.js @@ -7,8 +7,8 @@ import popoutView from 'plug/views/rooms/popout/PopoutView'; // hack to get plug.dj-like Class inheritance on a not-plug.dj-like Class const Style = Class.extend({ init(defaults) { - this._sistyl = new Sistyl(defaults); - this._timeout = null; + this.sistyl = new Sistyl(defaults); + this.timeout = null; this.refresh = this.refresh.bind(this); this.id = _.uniqueId('eps-'); @@ -17,7 +17,7 @@ const Style = Class.extend({ .attr('id', this.id) .attr('type', 'text/css') .appendTo('head'); - if (popoutView._window) { + if (popoutView._window) { // eslint-disable-line no-underscore-dangle this.el.clone().appendTo(popoutView.$document.find('head')); } this.refresh(); @@ -25,28 +25,28 @@ const Style = Class.extend({ $() { let el = this.el; - if (popoutView._window) { + if (popoutView._window) { // eslint-disable-line no-underscore-dangle el = el.add(popoutView.$document.find(`#${this.id}`)); } return el; }, set(sel, props) { - this._sistyl.set(sel, props); + this.sistyl.set(sel, props); // throttle updates - clearTimeout(this._timeout); - this._timeout = setTimeout(this.refresh, 1); + clearTimeout(this.timeout); + this.timeout = setTimeout(this.refresh, 1); return this; }, unset(sel, prop) { - this._sistyl.unset(sel, prop); + this.sistyl.unset(sel, prop); return this; }, rulesets() { - return this._sistyl.rulesets(); + return this.sistyl.rulesets(); }, refresh() { @@ -58,8 +58,8 @@ const Style = Class.extend({ }, toString() { - return this._sistyl.toString(); - } + return this.sistyl.toString(); + }, }); diff --git a/src/util/getUserClasses.js b/src/util/getUserClasses.js index 7957142..cd8aa29 100644 --- a/src/util/getUserClasses.js +++ b/src/util/getUserClasses.js @@ -7,7 +7,7 @@ const roleClasses = [ 'bouncer', 'manager', 'cohost', - 'host' + 'host', ]; // CSS classes for global roles const gRoleClasses = [ @@ -16,7 +16,7 @@ const gRoleClasses = [ '', 'ambassador', '', - 'admin' + 'admin', ]; /** @@ -35,8 +35,8 @@ const gRoleClasses = [ * "id-${THEIR_ID} role-manager role-none role-friend" */ function getUserClasses(uid) { - let classes = []; - let user = API.getUser(uid); + const classes = []; + const user = API.getUser(uid); classes.push(`id-${uid}`); if (user) { diff --git a/src/util/request.js b/src/util/request.js index b85615b..59c0ce6 100644 --- a/src/util/request.js +++ b/src/util/request.js @@ -1,36 +1,39 @@ import $ from 'jquery'; -export default request; +const corsproxy = 'https://cors-anywhere.herokuapp.com/'; -var corsproxy = 'https://cors-anywhere.herokuapp.com/'; +function mayNeedProxy(url) { + if (url.substr(0, corsproxy.length) !== corsproxy) { + const loc = new URL(url); + if (loc.hostname !== 'plug.dj' && loc.hostname !== 'cdn.plug.dj') { + return true; + } + } + return false; +} -function request(url, options) { - var ajax = $.ajax(url, options); +export default function request(url, options) { + let ajax = $.ajax(url, options); // try to work around CORS blocks if (mayNeedProxy(url)) { - ajax = ajax.then(null, function () { - return $.ajax(corsproxy + url); - }); + ajax = ajax.then(null, () => + $.ajax(corsproxy + url) + ); } return ajax; } -request.url = function (url) { +function proxyUrl(url) { return mayNeedProxy(url) ? corsproxy + url : url; -}; - -request.json = function (url, options) { - options = options || {}; - options.dataType = 'json'; - return request(url, options); -}; +} +export { proxyUrl as url }; -function mayNeedProxy(url) { - if (url.substr(0, corsproxy.length) !== corsproxy) { - let loc = new URL(url); - if (loc.hostname !== 'plug.dj' && loc.hostname !== 'cdn.plug.dj') { - return true; - } - } - return false; +export function json(url, options) { + return request(url, { + ...options, + dataType: 'json', + }); } + +request.url = proxyUrl; +request.json = json; diff --git a/src/views/dialogs/InstallPluginDialog.js b/src/views/dialogs/InstallPluginDialog.js index fd88fe6..1e973ce 100644 --- a/src/views/dialogs/InstallPluginDialog.js +++ b/src/views/dialogs/InstallPluginDialog.js @@ -1,4 +1,5 @@ import $ from 'jquery'; +import { defer } from 'underscore'; import Dialog from 'plug/views/dialogs/Dialog'; import Events from 'plug/core/Events'; import AlertEvent from 'plug/events/AlertEvent'; @@ -7,12 +8,13 @@ import SpinnerView from 'plug/views/spinner/SpinnerView'; const InstallPluginDialog = Dialog.extend({ id: 'dialog-install-plugin', className: 'dialog', + render() { // don't overlay chat $('#dialog-container').addClass('is-preview'); this.$input = $('').attr({ type: 'text', - placeholder: 'https://' + placeholder: 'https://', }); this.$wrap = $('
') .addClass('dialog-input-background') @@ -23,22 +25,24 @@ const InstallPluginDialog = Dialog.extend({ .append(this.getMessage('Enter the URL of the plugin you wish to install:')) .append(this.$wrap)) .append(this.getButtons('Install', true)); - _.defer(this.deferFocus.bind(this)); + defer(this.deferFocus.bind(this)); return this._super(); }, + deferFocus() { this.$input.focus(); }, + submit() { - let inp = this.$input; + const inp = this.$input; if (inp.val().length > 0 && inp.val().length > 0) { - let spinner = new SpinnerView({ size: SpinnerView.LARGE }); + const spinner = new SpinnerView({ size: SpinnerView.LARGE }); this.$el.find('.dialog-body') .empty() .append(spinner.$el); spinner.render(); - let url = inp.val(); - extp.install(url, (err) => { + const url = inp.val(); + window.extp.install(url, (err) => { this.close(); if (err) { Events.dispatch(new AlertEvent( @@ -47,8 +51,7 @@ const InstallPluginDialog = Dialog.extend({ `Error: ${err.message}`, () => {} )); - } - else { + } else { Events.dispatch(new AlertEvent( AlertEvent.ALERT, 'Install Plugin', @@ -59,11 +62,12 @@ const InstallPluginDialog = Dialog.extend({ }); } }, + close() { $('#dialog-container').removeClass('is-preview'); this.$input.off(); this._super(); - } + }, }); export default InstallPluginDialog; diff --git a/src/views/users/settings/CheckboxView.js b/src/views/users/settings/CheckboxView.js index 320b461..e27e7a5 100644 --- a/src/views/users/settings/CheckboxView.js +++ b/src/views/users/settings/CheckboxView.js @@ -20,10 +20,10 @@ const CheckboxView = Backbone.View.extend({ if (this.description) { this.$el - .on('mouseenter', function () { - Events.trigger('tooltip:show', this.description, this.$el); - }.bind(this)) - .on('mouseleave', function () { Events.trigger('tooltip:hide'); }); + .on('mouseenter', () => + Events.trigger('tooltip:show', this.description, this.$el) + ) + .on('mouseleave', () => Events.trigger('tooltip:hide')); } if (this.enabled) { @@ -35,12 +35,12 @@ const CheckboxView = Backbone.View.extend({ }, onChange() { this.$el.toggleClass('selected'); - var enabled = this.enabled; + const enabled = this.enabled; this.enabled = this.$el.hasClass('selected'); if (enabled !== this.enabled) { this.trigger('change', this.enabled); } - } + }, }); export default CheckboxView; diff --git a/src/views/users/settings/ColorInputView.js b/src/views/users/settings/ColorInputView.js index 7a0f31f..bee7e6a 100644 --- a/src/views/users/settings/ColorInputView.js +++ b/src/views/users/settings/ColorInputView.js @@ -1,5 +1,6 @@ -import InputView from './InputView'; +import $ from 'jquery'; import onecolor from 'onecolor'; +import InputView from './InputView'; const ColorInputView = InputView.extend({ className: 'item extplug-input extplug-color-input', @@ -24,27 +25,28 @@ const ColorInputView = InputView.extend({ color() { try { - let c = onecolor(this.$input.val()); + const c = onecolor(this.$input.val()); if (c) return c; + } catch (e) { + // ignore } - catch (e) {} + return null; }, onUpdate() { - let color = this.color(); + const color = this.color(); if (color) { this.$color.css({ 'background-color': color.css() }); this.$wrapper.removeClass('error'); - } - else { + } else { this.$wrapper.addClass('error'); } }, value() { - let color = this.color(); + const color = this.color(); return color ? this.$input.val() : ''; - } + }, }); export default ColorInputView; diff --git a/src/views/users/settings/ControlGroupView.js b/src/views/users/settings/ControlGroupView.js index 3cf8a86..a6bf09d 100644 --- a/src/views/users/settings/ControlGroupView.js +++ b/src/views/users/settings/ControlGroupView.js @@ -9,7 +9,7 @@ const ControlGroupView = View.extend({ }, render() { - let switchAt = Math.ceil(this.controls.length / 2 - 1); + const switchAt = Math.ceil((this.controls.length / 2) - 1); let current = $('
').addClass('left').appendTo(this.$el); this.controls.forEach((item, i) => { current.append(item.$el); @@ -24,7 +24,7 @@ const ControlGroupView = View.extend({ addControl(control) { this.controls.push(control); return this; - } + }, }); export default ControlGroupView; diff --git a/src/views/users/settings/DefaultSettingsView.js b/src/views/users/settings/DefaultSettingsView.js index 20b33b1..bad0a90 100644 --- a/src/views/users/settings/DefaultSettingsView.js +++ b/src/views/users/settings/DefaultSettingsView.js @@ -1,3 +1,4 @@ +import { each, has } from 'underscore'; import ControlGroupView from './ControlGroupView'; import CheckboxView from './CheckboxView'; import ColorInputView from './ColorInputView'; @@ -5,20 +6,19 @@ import DropdownView from './DropdownView'; import InputView from './InputView'; import PlaylistSelectView from './PlaylistSelectView'; import SliderView from './SliderView'; -import { each, has } from 'underscore'; const controlFactory = { boolean(setting, value) { return new CheckboxView({ label: setting.label, - enabled: value + enabled: value, }); }, dropdown(setting, value) { return new DropdownView({ label: setting.label, options: setting.options, - selected: value + selected: value, }); }, slider(setting, value) { @@ -26,14 +26,14 @@ const controlFactory = { label: setting.label, min: setting.min, max: setting.max, - value: settings.get(name) + value, }); }, text(setting, value) { return new InputView({ label: setting.label, description: setting.description, - value: value + value, }); }, number(setting, value) { @@ -41,26 +41,26 @@ const controlFactory = { type: 'number', label: setting.label, description: setting.description, - value: value, - min: has(setting, 'min') ? setting.min : '', - max: has(setting, 'max') ? setting.max : '', - step: has(setting, 'step') ? setting.step : '' + value, + min: has(setting, 'min') ? setting.min : '', + max: has(setting, 'max') ? setting.max : '', + step: has(setting, 'step') ? setting.step : '', }); }, color(setting, value) { return new ColorInputView({ label: setting.label, description: setting.description, - value: value + value, }); }, playlist(setting, value) { return new PlaylistSelectView({ label: setting.label, description: setting.description, - value: value + value, }); - } + }, }; const DefaultSettingsView = ControlGroupView.extend({ @@ -72,7 +72,7 @@ const DefaultSettingsView = ControlGroupView.extend({ const settings = this.model; each(meta, (setting, name) => { if (has(controlFactory, setting.type)) { - let control = controlFactory[setting.type](setting, settings.get(name)); + const control = controlFactory[setting.type](setting, settings.get(name)); control.on('change', value => settings.set(name, value)); this.addControl(control); } @@ -86,7 +86,7 @@ const DefaultSettingsView = ControlGroupView.extend({ remove() { this.controls.forEach(control => control.destroy()); this.controls = []; - } + }, }); diff --git a/src/views/users/settings/DropdownView.js b/src/views/users/settings/DropdownView.js index d340551..cefe441 100644 --- a/src/views/users/settings/DropdownView.js +++ b/src/views/users/settings/DropdownView.js @@ -1,5 +1,5 @@ -import Backbone from 'backbone'; import $ from 'jquery'; +import Backbone from 'backbone'; import { each, defer } from 'underscore'; const DropdownView = Backbone.View.extend({ @@ -25,8 +25,8 @@ const DropdownView = Backbone.View.extend({ this.$rows = $('
'); let selected; each(this.options.options, (text, value) => { - let row = $('
').addClass('row').data('value', value); - let el = $('').text(text); + const row = $('
').addClass('row').data('value', value); + const el = $('').text(text); if (this.options.selected === value) { selected = row; } @@ -61,15 +61,13 @@ const DropdownView = Backbone.View.extend({ $(document).off('click', this.onDocumentClick); }, - onBaseClick(e) { + onBaseClick() { if (this.$dl.hasClass('open')) { this.close(); - } - else { + } else { if (this.canExpandDownward()) { this.$dl.addClass('open'); - } - else { + } else { this.$dl.addClass('open extplug-dropdown-up'); } defer(() => { @@ -79,7 +77,7 @@ const DropdownView = Backbone.View.extend({ }, onRowClick(e) { - let row = $(e.target).closest('.row'); + const row = $(e.target).closest('.row'); this.$rows.children().removeClass('selected'); row.addClass('selected'); @@ -89,17 +87,17 @@ const DropdownView = Backbone.View.extend({ // will be closed by onDocumentClick() }, - onDocumentClick(e) { + onDocumentClick() { defer(() => { this.close(); }); }, canExpandDownward() { - let top = this.$dl.offset().top; - let bottom = top + this.$rows.height(); + const top = this.$dl.offset().top; + const bottom = top + this.$rows.height(); return bottom < $(document).height(); - } + }, }); export default DropdownView; diff --git a/src/views/users/settings/InputView.js b/src/views/users/settings/InputView.js index 5d9c4c3..b8934f7 100644 --- a/src/views/users/settings/InputView.js +++ b/src/views/users/settings/InputView.js @@ -63,7 +63,7 @@ const InputView = View.extend({ onBlur() { this.$wrapper.removeClass('focused'); this.trigger('change', this.$input.val()); - } + }, }); export default InputView; diff --git a/src/views/users/settings/PlaylistSelectMenuView.js b/src/views/users/settings/PlaylistSelectMenuView.js index 7488ea3..a6d1927 100644 --- a/src/views/users/settings/PlaylistSelectMenuView.js +++ b/src/views/users/settings/PlaylistSelectMenuView.js @@ -1,8 +1,9 @@ -import { constructor as GrabMenu } from 'plug/views/grabs/grabMenu'; +import $ from 'jquery'; import Media from 'plug/models/Media'; +import { constructor as GrabMenu } from 'plug/views/grabs/grabMenu'; import Lang from 'lang/Lang'; -const fakeMedia = [ new Media() ]; +const fakeMedia = [new Media()]; const PlaylistSelectMenuView = GrabMenu.extend({ className: 'pop-menu extplug-playlist-select-menu', @@ -15,9 +16,15 @@ const PlaylistSelectMenuView = GrabMenu.extend({ // plug has a little delay in here because it auto-hides the grab // menu when the mouse leaves the area. hide() { - this.$modal && this.$modal.remove(); - if (this._hide) this._hide(); - else this._super(); + if (this.$modal) { + this.$modal.remove(); + } + + if (this._hide) { // eslint-disable-line no-underscore-dangle + this._hide(); // eslint-disable-line no-underscore-dangle + } else { + this._super(); + } }, onRowPress(playlist) { @@ -36,8 +43,7 @@ const PlaylistSelectMenuView = GrabMenu.extend({ if (row.model) { if (row.model.get('id') === this.options.selected.get('id')) { row.$el.append($('').addClass('icon icon-check-purple')); - } - else if (row.model.get('active')) { + } else if (row.model.get('active')) { row.$el.find('.icon-check-purple').remove(); } } @@ -50,7 +56,7 @@ const PlaylistSelectMenuView = GrabMenu.extend({ this.$el.css('z-index', parseInt(this.$modal.css('z-index'), 10) + 1); return this; - } + }, }); export default PlaylistSelectMenuView; diff --git a/src/views/users/settings/PlaylistSelectView.js b/src/views/users/settings/PlaylistSelectView.js index 43b060a..0da6835 100644 --- a/src/views/users/settings/PlaylistSelectView.js +++ b/src/views/users/settings/PlaylistSelectView.js @@ -1,6 +1,7 @@ -import PlaylistSelectMenuView from './PlaylistSelectMenuView'; +import $ from 'jquery'; import { View } from 'backbone'; import playlists from 'plug/collections/playlists'; +import PlaylistSelectMenuView from './PlaylistSelectMenuView'; const PlaylistSelectView = View.extend({ className: 'item extplug-playlist-select', @@ -24,8 +25,8 @@ const PlaylistSelectView = View.extend({ }, open() { - let menu = new PlaylistSelectMenuView({ - selected: this.value + const menu = new PlaylistSelectMenuView({ + selected: this.value, }); menu.show(this.$selected); menu.on('select', playlist => { @@ -33,7 +34,7 @@ const PlaylistSelectView = View.extend({ this.$selected.text(this.value.get('name')); this.trigger('change', playlist.get('id')); }); - } + }, }); export default PlaylistSelectView; diff --git a/src/views/users/settings/PluginsGroupView.js b/src/views/users/settings/PluginsGroupView.js index af69354..3b0f4e6 100644 --- a/src/views/users/settings/PluginsGroupView.js +++ b/src/views/users/settings/PluginsGroupView.js @@ -5,7 +5,6 @@ import ManagingFooterView from './footers/ManagingFooterView'; import ControlGroupView from './ControlGroupView'; const PluginsGroupView = ControlGroupView.extend({ - initialize() { this.collection.on('reset add remove', this.onUpdate, this); this.onUpdate(); @@ -36,19 +35,17 @@ const PluginsGroupView = ControlGroupView.extend({ let box = null; if (this.managing) { box = new RemoveBoxView({ model: plugin }); - } - else { + } else { box = new CheckboxView({ label: plugin.get('name'), description: plugin.get('instance').description || false, - enabled: plugin.get('enabled') + enabled: plugin.get('enabled'), }); } box.on('change', enabled => { if (enabled) { plugin.get('instance').enable(); - } - else { + } else { plugin.get('instance').disable(); } }); @@ -65,8 +62,7 @@ const PluginsGroupView = ControlGroupView.extend({ this.managing = false; this.onUpdate(); this.render(); - } - + }, }); export default PluginsGroupView; diff --git a/src/views/users/settings/RemoveBoxView.js b/src/views/users/settings/RemoveBoxView.js index ecf0115..fb7cdf3 100644 --- a/src/views/users/settings/RemoveBoxView.js +++ b/src/views/users/settings/RemoveBoxView.js @@ -32,11 +32,11 @@ const RemoveBoxView = View.extend({ title: 'Remove Plugin', message: 'Are you sure you want to uninstall this plugin?', action: () => { - extp.uninstall(this.model.get('id')); - } + window.extp.uninstall(this.model.get('id')); + }, }) )); - } + }, }); export default RemoveBoxView; diff --git a/src/views/users/settings/SettingsView.js b/src/views/users/settings/SettingsView.js index 8f4fc1e..bdc1f93 100644 --- a/src/views/users/settings/SettingsView.js +++ b/src/views/users/settings/SettingsView.js @@ -1,26 +1,8 @@ +import $ from 'jquery'; +import { defer } from 'underscore'; import { View } from 'backbone'; -import ControlGroupView from './ControlGroupView'; -import PluginsGroupView from './PluginsGroupView'; -import CheckboxView from './CheckboxView'; -import RemoveBoxView from './RemoveBoxView'; -import PluginMeta from '../../../models/PluginMeta'; -import Events from 'plug/core/Events'; import window from 'plug/util/window'; -import { defer } from 'underscore'; -import $ from 'jquery'; - -/** - * Wires a control to a setting model, updating the model when the control changes. - * - * @param {Backbone.View} el Control view. - * @param {Backbone.Model} settings Model to reflect the settings to. - * @param {string} target Relevant property on the model. - */ -function wireSettingToModel(view, settings, target) { - view.on('change', function (value) { - settings.set(target, value); - }); -} +import PluginsGroupView from './PluginsGroupView'; const SettingsView = View.extend({ className: 'ext-plug section', @@ -56,22 +38,22 @@ const SettingsView = View.extend({ this.groups = []; this.addGroup('Plugins', this.createPluginsGroup(), 1000); this.addGroup('ExtPlug', this.createExtPlugGroup(), 999); - this.plugins.forEach(function (plugin) { + this.plugins.forEach(plugin => { // add plugin settings group for stuff that was already enabled if (plugin.get('enabled')) { - let pluginSettings = this.createSettingsGroup(plugin); + const pluginSettings = this.createSettingsGroup(plugin); if (pluginSettings) { this.addGroup(plugin.get('name'), pluginSettings); } } - }, this); + }); }, render() { if (this.scrollPane) { this.scrollPane.destroy(); defer(() => { - let size = window.getSize(); + const size = window.getSize(); this.onResize(size.width, size.height); }); } @@ -79,15 +61,15 @@ const SettingsView = View.extend({ this.$el.empty().append(this.$container); this.sort(); - this.groups.forEach(function (group) { - let header = $('
').addClass('header').append( + this.groups.forEach(group => { + const header = $('
').addClass('header').append( $('').text(group.name) ); group.view.render(); this.$container .append(header) .append(group.view.$el); - }, this); + }); this.$container.jScrollPane(); this.scrollPane = this.$container.data('jsp'); @@ -96,8 +78,8 @@ const SettingsView = View.extend({ }, createPluginsGroup() { - let pluginsGroup = new PluginsGroupView({ - collection: this.plugins + const pluginsGroup = new PluginsGroupView({ + collection: this.plugins, }); return pluginsGroup; }, @@ -106,9 +88,9 @@ const SettingsView = View.extend({ }, createSettingsGroup(pluginMeta) { - let plugin = pluginMeta.get('instance'); - if (!plugin._settings) { - return; + const plugin = pluginMeta.get('instance'); + if (!plugin._settings) { // eslint-disable-line no-underscore-dangle + return null; } return plugin.getSettingsView(); @@ -118,9 +100,11 @@ const SettingsView = View.extend({ this.groups.sort((a, b) => { let c = b.priority - a.priority; if (c === 0) { - c = a.name > b.name ? 1 - : a.name < b.name ? -1 - : 0; + if (a.name > b.name) { + c = 1; + } else if (a.name < b.name) { + c = -1; + } } return c; }); @@ -135,9 +119,9 @@ const SettingsView = View.extend({ addGroup(name, view, priority) { this.groups.push({ - name: name, - view: view, - priority: typeof priority === 'number' ? priority : 0 + name, + view, + priority: typeof priority === 'number' ? priority : 0, }); }, @@ -147,6 +131,7 @@ const SettingsView = View.extend({ return this.groups[i].view; } } + return null; }, hasGroup(name) { @@ -159,8 +144,8 @@ const SettingsView = View.extend({ return this.groups.splice(i, 1); } } - } - + return null; + }, }); export default SettingsView; diff --git a/src/views/users/settings/SliderView.js b/src/views/users/settings/SliderView.js index 1447e42..1904dcd 100644 --- a/src/views/users/settings/SliderView.js +++ b/src/views/users/settings/SliderView.js @@ -1,5 +1,6 @@ import Backbone from 'backbone'; import $ from 'jquery'; +import { defer } from 'underscore'; function template(o) { return ` @@ -24,28 +25,30 @@ const SliderView = Backbone.View.extend({ this.onStart = this.onStart.bind(this); this.onMove = this.onMove.bind(this); this.onStop = this.onStop.bind(this); - this._value = this.options.value || this.options.min; + this.value = this.options.value || this.options.min; }, + render() { this.$el.append(template(this.options)); this.$bar = this.$('.bar'); this.$hit = this.$('.hit').on('mousedown', this.onStart); this.$circle = this.$('.circle'); this.$value = this.$('.value'); - _.delay(function () { - this.setValue(this._value, true); - }.bind(this)); + defer(() => { + this.setValue(this.value, true); + }); return this; }, + onStart() { $(document) .on('mousemove', this.onMove) .on('mouseup', this.onStop); }, onMove(e) { - let offset = (e.pageX - this.$hit.offset().left); - let percent = Math.max(0, Math.min(1, offset / (this.$hit.width() - this.$circle.width()))); - let value = Math.round(this.options.min + percent * (this.options.max - this.options.min)); + const offset = (e.pageX - this.$hit.offset().left); + const percent = Math.max(0, Math.min(1, offset / (this.$hit.width() - this.$circle.width()))); + const value = Math.round(this.options.min + (percent * (this.options.max - this.options.min))); this.setValue(Math.max(this.options.min, value)); e.preventDefault(); e.stopPropagation(); @@ -56,16 +59,17 @@ const SliderView = Backbone.View.extend({ .off('mouseup', this.onStop); }, setValue(value, force) { - if (value !== this._value || force) { - let percent = (value - this.options.min) / (this.options.max - this.options.min); - this.$circle.css('left', parseInt(this.$hit.css('left'), 10) + - (this.$hit.width() - this.$circle.width()) * percent - - this.$circle.width() / 2); + if (value !== this.value || force) { + const percent = (value - this.options.min) / (this.options.max - this.options.min); + const circleCenter = this.$circle.width() / 2; + const position = (this.$hit.width() - this.$circle.width()) * percent; + const baseOffset = parseInt(this.$hit.css('left'), 10); + this.$circle.css('left', baseOffset + (position - circleCenter)); this.$value.text(value); this.trigger('change', value); - this._value = value; + this.value = value; } - } + }, }); export default SliderView; diff --git a/src/views/users/settings/TabMenuView.js b/src/views/users/settings/TabMenuView.js index 960fdda..b976f95 100644 --- a/src/views/users/settings/TabMenuView.js +++ b/src/views/users/settings/TabMenuView.js @@ -2,25 +2,23 @@ import SettingsTabMenuView from 'plug/views/users/settings/TabMenuView'; import $ from 'jquery'; const TabMenuView = SettingsTabMenuView.extend({ - render() { this._super(); - let extPlugTab = $('