From b3851817ecd59b039f2c2228d08a1c6fd8e60d60 Mon Sep 17 00:00:00 2001 From: Maxime Quandalle Date: Thu, 3 Sep 2015 23:12:46 +0200 Subject: Enforce a consistent ES6 coding style Replace the old (and broken) jshint + jscsrc by eslint and configure it to support some of the ES6 features. The command `eslint` currently has one error which is a bug that was discovered by its static analysis and should be fixed (usage of a dead object). --- client/lib/cssEvents.js | 28 +++++----- client/lib/escapeActions.js | 72 ++++++------------------- client/lib/filter.js | 88 +++++++++++++++---------------- client/lib/i18n.js | 9 ++-- client/lib/inlinedform.js | 32 +++++------ client/lib/keyboard.js | 18 +++---- client/lib/modal.js | 2 +- client/lib/multiSelection.js | 93 ++++++++++++++++---------------- client/lib/popup.js | 123 +++++++++++++++++++++---------------------- client/lib/unsavedEdits.js | 20 +++---- client/lib/utils.js | 66 +++++++++++++---------- 11 files changed, 252 insertions(+), 299 deletions(-) (limited to 'client/lib') diff --git a/client/lib/cssEvents.js b/client/lib/cssEvents.js index 487ba69b..39c3fb90 100644 --- a/client/lib/cssEvents.js +++ b/client/lib/cssEvents.js @@ -1,42 +1,40 @@ // XXX Should we use something like Moderniz instead of our custom detector? -var whichTransitionEvent = function() { - var t; - var el = document.createElement('fakeelement'); - var transitions = { +function whichTransitionEvent() { + const el = document.createElement('fakeelement'); + const transitions = { transition:'transitionend', OTransition:'oTransitionEnd', MSTransition:'msTransitionEnd', MozTransition:'transitionend', - WebkitTransition:'webkitTransitionEnd' + WebkitTransition:'webkitTransitionEnd', }; - for (t in transitions) { + for (const t in transitions) { if (el.style[t] !== undefined) { return transitions[t]; } } -}; +} -var whichAnimationEvent = function() { - var t; - var el = document.createElement('fakeelement'); - var transitions = { +function whichAnimationEvent() { + const el = document.createElement('fakeelement'); + const transitions = { animation:'animationend', OAnimation:'oAnimationEnd', MSTransition:'msAnimationEnd', MozAnimation:'animationend', - WebkitAnimation:'webkitAnimationEnd' + WebkitAnimation:'webkitAnimationEnd', }; - for (t in transitions) { + for (const t in transitions) { if (el.style[t] !== undefined) { return transitions[t]; } } -}; +} CSSEvents = { transitionend: whichTransitionEvent(), - animationend: whichAnimationEvent() + animationend: whichAnimationEvent(), }; diff --git a/client/lib/escapeActions.js b/client/lib/escapeActions.js index ff793b1d..f2dc3dcb 100644 --- a/client/lib/escapeActions.js +++ b/client/lib/escapeActions.js @@ -31,7 +31,7 @@ EscapeActions = { enabledOnClick = true; } - let noClickEscapeOn = options.noClickEscapeOn; + const noClickEscapeOn = options.noClickEscapeOn; this._actions = _.sortBy([...this._actions, { priority, @@ -44,20 +44,20 @@ EscapeActions = { executeLowest() { return this._execute({ - multipleAction: false + multipleAction: false, }); }, executeAll() { return this._execute({ - multipleActions: true + multipleActions: true, }); }, executeUpTo(maxLabel) { return this._execute({ - maxLabel: maxLabel, - multipleActions: true + maxLabel, + multipleActions: true, }); }, @@ -66,10 +66,10 @@ EscapeActions = { this._nextclickPrevented = false; } else { return this._execute({ - maxLabel: maxLabel, + maxLabel, multipleActions: false, isClick: true, - clickTarget: target + clickTarget: target, }); } }, @@ -79,7 +79,7 @@ EscapeActions = { }, _stopClick(action, clickTarget) { - if (! _.isString(action.noClickEscapeOn)) + if (!_.isString(action.noClickEscapeOn)) return false; else return $(clickTarget).closest(action.noClickEscapeOn).length > 0; @@ -88,86 +88,46 @@ EscapeActions = { _execute(options) { const maxLabel = options.maxLabel; const multipleActions = options.multipleActions; - const isClick = !! options.isClick; + const isClick = Boolean(options.isClick); const clickTarget = options.clickTarget; let executedAtLeastOne = false; let maxPriority; - if (! maxLabel) + if (!maxLabel) maxPriority = Infinity; else maxPriority = this.hierarchy.indexOf(maxLabel); - for (let currentAction of this._actions) { + for (const currentAction of this._actions) { if (currentAction.priority > maxPriority) return executedAtLeastOne; if (isClick && this._stopClick(currentAction, clickTarget)) return executedAtLeastOne; - let isEnabled = currentAction.enabledOnClick || ! isClick; + const isEnabled = currentAction.enabledOnClick || !isClick; if (isEnabled && currentAction.condition()) { currentAction.action(); executedAtLeastOne = true; - if (! multipleActions) + if (!multipleActions) return executedAtLeastOne; } } return executedAtLeastOne; - } -}; - -// MouseTrap plugin bindGlobal plugin. Adds a bindGlobal method to Mousetrap -// that allows you to bind specific keyboard shortcuts that will still work -// inside a text input field. -// -// usage: -// Mousetrap.bindGlobal('ctrl+s', _saveChanges); -// -// source: -// https://github.com/ccampbell/mousetrap/tree/master/plugins/global-bind -var _globalCallbacks = {}; -var _originalStopCallback = Mousetrap.stopCallback; - -Mousetrap.stopCallback = function(e, element, combo, sequence) { - var self = this; - - if (self.paused) { - return true; - } - - if (_globalCallbacks[combo] || _globalCallbacks[sequence]) { - return false; - } - - return _originalStopCallback.call(self, e, element, combo); -}; - -Mousetrap.bindGlobal = function(keys, callback, action) { - var self = this; - self.bind(keys, callback, action); - - if (keys instanceof Array) { - for (var i = 0; i < keys.length; i++) { - _globalCallbacks[keys[i]] = true; - } - return; - } - - _globalCallbacks[keys] = true; + }, }; // Pressing escape to execute one escape action. We use `bindGloabal` vecause // the shortcut sould work on textarea and inputs as well. -Mousetrap.bindGlobal('esc', function() { +Mousetrap.bindGlobal('esc', () => { EscapeActions.executeLowest(); }); // On a left click on the document, we try to exectute one escape action (eg, // close the popup). We don't execute any action if the user has clicked on a // link or a button. -$(document).on('click', function(evt) { +$(document).on('click', (evt) => { if (evt.button === 0 && $(evt.target).closest('a,button,.is-editable').length === 0) { EscapeActions.clickExecute(evt.target, 'multiselection'); diff --git a/client/lib/filter.js b/client/lib/filter.js index 359b65d3..532ef236 100644 --- a/client/lib/filter.js +++ b/client/lib/filter.js @@ -4,66 +4,66 @@ // goal is to filter complete documents by using the local filters for each // fields. -var showFilterSidebar = function() { +function showFilterSidebar() { Sidebar.setView('filter'); -}; +} // Use a "set" filter for a field that is a set of documents uniquely // identified. For instance `{ labels: ['labelA', 'labelC', 'labelD'] }`. -var SetFilter = function() { - this._dep = new Tracker.Dependency(); - this._selectedElements = []; -}; +class SetFilter { + constructor() { + this._dep = new Tracker.Dependency(); + this._selectedElements = []; + } -_.extend(SetFilter.prototype, { - isSelected: function(val) { + isSelected(val) { this._dep.depend(); return this._selectedElements.indexOf(val) > -1; - }, + } - add: function(val) { + add(val) { if (this._indexOfVal(val) === -1) { this._selectedElements.push(val); this._dep.changed(); showFilterSidebar(); } - }, + } - remove: function(val) { - var indexOfVal = this._indexOfVal(val); + remove(val) { + const indexOfVal = this._indexOfVal(val); if (this._indexOfVal(val) !== -1) { this._selectedElements.splice(indexOfVal, 1); this._dep.changed(); } - }, + } - toogle: function(val) { + toogle(val) { if (this._indexOfVal(val) === -1) { this.add(val); } else { this.remove(val); } - }, + } - reset: function() { + reset() { this._selectedElements = []; this._dep.changed(); - }, + } - _indexOfVal: function(val) { + _indexOfVal(val) { return this._selectedElements.indexOf(val); - }, + } - _isActive: function() { + _isActive() { this._dep.depend(); return this._selectedElements.length !== 0; - }, + } - _getMongoSelector: function() { + _getMongoSelector() { this._dep.depend(); return { $in: this._selectedElements }; } -}); +} // The global Filter object. // XXX It would be possible to re-write this object more elegantly, and removing @@ -84,50 +84,46 @@ Filter = { _exceptions: [], _exceptionsDep: new Tracker.Dependency(), - isActive: function() { - var self = this; - return _.any(self._fields, function(fieldName) { - return self[fieldName]._isActive(); + isActive() { + return _.any(this._fields, (fieldName) => { + return this[fieldName]._isActive(); }); }, - _getMongoSelector: function() { - var self = this; - - if (! self.isActive()) + _getMongoSelector() { + if (!this.isActive()) return {}; - var filterSelector = {}; - _.forEach(self._fields, function(fieldName) { - var filter = self[fieldName]; + const filterSelector = {}; + _.forEach(this._fields, (fieldName) => { + const filter = this[fieldName]; if (filter._isActive()) filterSelector[fieldName] = filter._getMongoSelector(); }); - var exceptionsSelector = {_id: {$in: this._exceptions}}; + const exceptionsSelector = {_id: {$in: this._exceptions}}; this._exceptionsDep.depend(); return {$or: [filterSelector, exceptionsSelector]}; }, - mongoSelector: function(additionalSelector) { - var filterSelector = this._getMongoSelector(); + mongoSelector(additionalSelector) { + const filterSelector = this._getMongoSelector(); if (_.isUndefined(additionalSelector)) return filterSelector; else return {$and: [filterSelector, additionalSelector]}; }, - reset: function() { - var self = this; - _.forEach(self._fields, function(fieldName) { - var filter = self[fieldName]; + reset() { + _.forEach(this._fields, (fieldName) => { + const filter = this[fieldName]; filter.reset(); }); - self.resetExceptions(); + this.resetExceptions(); }, - addException: function(_id) { + addException(_id) { if (this.isActive()) { this._exceptions.push(_id); this._exceptionsDep.changed(); @@ -135,10 +131,10 @@ Filter = { } }, - resetExceptions: function() { + resetExceptions() { this._exceptions = []; this._exceptionsDep.changed(); - } + }, }; Blaze.registerHelper('Filter', Filter); diff --git a/client/lib/i18n.js b/client/lib/i18n.js index 7d7e3ebb..a03fb398 100644 --- a/client/lib/i18n.js +++ b/client/lib/i18n.js @@ -2,9 +2,9 @@ // the language reactively. If the user is not connected we use the language // information provided by the browser, and default to english. -Tracker.autorun(function() { - var language; - var currentUser = Meteor.user(); +Tracker.autorun(() => { + const currentUser = Meteor.user(); + let language; if (currentUser) { language = currentUser.profile && currentUser.profile.language; } else { @@ -12,11 +12,10 @@ Tracker.autorun(function() { } if (language) { - TAPi18n.setLanguage(language); // XXX - var shortLanguage = language.split('-')[0]; + const shortLanguage = language.split('-')[0]; T9n.setLanguage(shortLanguage); } }); diff --git a/client/lib/inlinedform.js b/client/lib/inlinedform.js index 15074f40..2732a2e3 100644 --- a/client/lib/inlinedform.js +++ b/client/lib/inlinedform.js @@ -13,66 +13,66 @@ // // the content when the form is close (optional) // We can only have one inlined form element opened at a time -currentlyOpenedForm = new ReactiveVar(null); +const currentlyOpenedForm = new ReactiveVar(null); InlinedForm = BlazeComponent.extendComponent({ - template: function() { + template() { return 'inlinedForm'; }, - onCreated: function() { + onCreated() { this.isOpen = new ReactiveVar(false); }, - onDestroyed: function() { + onDestroyed() { currentlyOpenedForm.set(null); }, - open: function() { + open() { // Close currently opened form, if any EscapeActions.executeUpTo('inlinedForm'); this.isOpen.set(true); currentlyOpenedForm.set(this); }, - close: function() { + close() { this.isOpen.set(false); currentlyOpenedForm.set(null); }, - getValue: function() { - var input = this.find('textarea,input[type=text]'); + getValue() { + const input = this.find('textarea,input[type=text]'); return this.isOpen.get() && input && input.value; }, - events: function() { + events() { return [{ 'click .js-close-inlined-form': this.close, 'click .js-open-inlined-form': this.open, // Pressing Ctrl+Enter should submit the form - 'keydown form textarea': function(evt) { + 'keydown form textarea'(evt) { if (evt.keyCode === 13 && (evt.metaKey || evt.ctrlKey)) { this.find('button[type=submit]').click(); } }, // Close the inlined form when after its submission - submit: function() { + submit() { if (this.currentData().autoclose !== false) { Tracker.afterFlush(() => { this.close(); }); } - } + }, }]; - } + }, }).register('inlinedForm'); // Press escape to close the currently opened inlinedForm EscapeActions.register('inlinedForm', - function() { currentlyOpenedForm.get().close(); }, - function() { return currentlyOpenedForm.get() !== null; }, { - noClickEscapeOn: '.js-inlined-form' + () => { currentlyOpenedForm.get().close(); }, + () => { return currentlyOpenedForm.get() !== null; }, { + noClickEscapeOn: '.js-inlined-form', } ); diff --git a/client/lib/keyboard.js b/client/lib/keyboard.js index 2b327b33..0bb9c380 100644 --- a/client/lib/keyboard.js +++ b/client/lib/keyboard.js @@ -24,7 +24,7 @@ Mousetrap.bind('x', () => { }); Mousetrap.bind(['down', 'up'], (evt, key) => { - if (! Session.get('currentCard')) { + if (!Session.get('currentCard')) { return; } @@ -39,24 +39,24 @@ Mousetrap.bind(['down', 'up'], (evt, key) => { Template.keyboardShortcuts.helpers({ mapping: [{ keys: ['W'], - action: 'shortcut-toogle-sidebar' + action: 'shortcut-toogle-sidebar', }, { keys: ['Q'], - action: 'shortcut-filter-my-cards' + action: 'shortcut-filter-my-cards', }, { keys: ['X'], - action: 'shortcut-clear-filters' + action: 'shortcut-clear-filters', }, { keys: ['?'], - action: 'shortcut-show-shortcuts' + action: 'shortcut-show-shortcuts', }, { keys: ['ESC'], - action: 'shortcut-close-dialog' + action: 'shortcut-close-dialog', }, { keys: ['@'], - action: 'shortcut-autocomplete-members' + action: 'shortcut-autocomplete-members', }, { keys: [':'], - action: 'shortcut-autocomplete-emojies' - }] + action: 'shortcut-autocomplete-emojies', + }], }); diff --git a/client/lib/modal.js b/client/lib/modal.js index 9b204bb4..5b3392b2 100644 --- a/client/lib/modal.js +++ b/client/lib/modal.js @@ -1,4 +1,4 @@ -const closedValue = null +const closedValue = null; window.Modal = new class { constructor() { diff --git a/client/lib/multiSelection.js b/client/lib/multiSelection.js index e6db42cd..77f351a4 100644 --- a/client/lib/multiSelection.js +++ b/client/lib/multiSelection.js @@ -1,53 +1,53 @@ -var getCardsBetween = function(idA, idB) { +function getCardsBetween(idA, idB) { - var pluckId = function(doc) { + function pluckId(doc) { return doc._id; - }; + } - var getListsStrictlyBetween = function(id1, id2) { + function getListsStrictlyBetween(id1, id2) { return Lists.find({ $and: [ { sort: { $gt: Lists.findOne(id1).sort } }, - { sort: { $lt: Lists.findOne(id2).sort } } + { sort: { $lt: Lists.findOne(id2).sort } }, ], - archived: false + archived: false, }).map(pluckId); - }; + } - var cards = _.sortBy([Cards.findOne(idA), Cards.findOne(idB)], function(c) { + const cards = _.sortBy([Cards.findOne(idA), Cards.findOne(idB)], (c) => { return c.sort; }); - var selector; + let selector; if (cards[0].listId === cards[1].listId) { selector = { listId: cards[0].listId, sort: { $gte: cards[0].sort, - $lte: cards[1].sort + $lte: cards[1].sort, }, - archived: false + archived: false, }; } else { selector = { $or: [{ listId: cards[0].listId, - sort: { $lte: cards[0].sort } + sort: { $lte: cards[0].sort }, }, { listId: { - $in: getListsStrictlyBetween(cards[0].listId, cards[1].listId) - } + $in: getListsStrictlyBetween(cards[0].listId, cards[1].listId), + }, }, { listId: cards[1].listId, - sort: { $gte: cards[1].sort } + sort: { $gte: cards[1].sort }, }], - archived: false + archived: false, }; } return Cards.find(Filter.mongoSelector(selector)).map(pluckId); -}; +} MultiSelection = { sidebarView: 'multiselection', @@ -58,30 +58,30 @@ MultiSelection = { startRangeCardId: null, - reset: function() { + reset() { this._selectedCards.set([]); }, - getMongoSelector: function() { + getMongoSelector() { return Filter.mongoSelector({ - _id: { $in: this._selectedCards.get() } + _id: { $in: this._selectedCards.get() }, }); }, - isActive: function() { + isActive() { return this._isActive.get(); }, - count: function() { + count() { return Cards.find(this.getMongoSelector()).count(); }, - isEmpty: function() { + isEmpty() { return this.count() === 0; }, - activate: function() { - if (! this.isActive()) { + activate() { + if (!this.isActive()) { EscapeActions.executeUpTo('detailsPane'); this._isActive.set(true); Tracker.flush(); @@ -89,7 +89,7 @@ MultiSelection = { Sidebar.setView(this.sidebarView); }, - disable: function() { + disable() { if (this.isActive()) { this._isActive.set(false); if (Sidebar && Sidebar.getView() === this.sidebarView) { @@ -99,19 +99,19 @@ MultiSelection = { } }, - add: function(cardIds) { + add(cardIds) { return this.toogle(cardIds, { add: true, remove: false }); }, - remove: function(cardIds) { + remove(cardIds) { return this.toogle(cardIds, { add: false, remove: true }); }, - toogleRange: function(cardId) { - var selectedCards = this._selectedCards.get(); - var startRange; + toogleRange(cardId) { + const selectedCards = this._selectedCards.get(); + let startRange; this.reset(); - if (! this.isActive() || selectedCards.length === 0) { + if (!this.isActive() || selectedCards.length === 0) { this.toogle(cardId); } else { startRange = selectedCards[selectedCards.length - 1]; @@ -119,23 +119,22 @@ MultiSelection = { } }, - toogle: function(cardIds, options) { - var self = this; + toogle(cardIds, options) { cardIds = _.isString(cardIds) ? [cardIds] : cardIds; options = _.extend({ add: true, - remove: true + remove: true, }, options || {}); - if (! self.isActive()) { - self.reset(); - self.activate(); + if (!this.isActive()) { + this.reset(); + this.activate(); } - var selectedCards = self._selectedCards.get(); + const selectedCards = this._selectedCards.get(); - _.each(cardIds, function(cardId) { - var indexOfCard = selectedCards.indexOf(cardId); + _.each(cardIds, (cardId) => { + const indexOfCard = selectedCards.indexOf(cardId); if (options.remove && indexOfCard > -1) selectedCards.splice(indexOfCard, 1); @@ -144,19 +143,19 @@ MultiSelection = { selectedCards.push(cardId); }); - self._selectedCards.set(selectedCards); + this._selectedCards.set(selectedCards); }, - isSelected: function(cardId) { + isSelected(cardId) { return this._selectedCards.get().indexOf(cardId) > -1; - } + }, }; Blaze.registerHelper('MultiSelection', MultiSelection); EscapeActions.register('multiselection', - function() { MultiSelection.disable(); }, - function() { return MultiSelection.isActive(); }, { - noClickEscapeOn: '.js-minicard,.js-board-sidebar-content' + () => { MultiSelection.disable(); }, + () => { return MultiSelection.isActive(); }, { + noClickEscapeOn: '.js-minicard,.js-board-sidebar-content', } ); diff --git a/client/lib/popup.js b/client/lib/popup.js index b2340e04..3c39af29 100644 --- a/client/lib/popup.js +++ b/client/lib/popup.js @@ -1,55 +1,53 @@ // A simple tracker dependency that we invalidate every time the window is // resized. This is used to reactively re-calculate the popup position in case // of a window resize. This is the equivalent of a "Signal" in some other -// programming environments. -let windowResizeDep = new Tracker.Dependency() -$(window).on('resize', () => windowResizeDep.changed()) +// programming environments (eg, elm). +const windowResizeDep = new Tracker.Dependency(); +$(window).on('resize', () => windowResizeDep.changed()); window.Popup = new class { constructor() { // The template we use to render popups - this.template = Template.popup + this.template = Template.popup; // We only want to display one popup at a time and we keep the view object // in this `Popup._current` variable. If there is no popup currently opened // the value is `null`. - this._current = null + this._current = null; // It's possible to open a sub-popup B from a popup A. In that case we keep // the data of popup A so we can return back to it. Every time we open a new // popup the stack grows, every time we go back the stack decrease, and if // we close the popup the stack is reseted to the empty stack []. - this._stack = [] + this._stack = []; // We invalidate this internal dependency every time the top of the stack // has changed and we want to re-render a popup with the new top-stack data. - this._dep = new Tracker.Dependency() + this._dep = new Tracker.Dependency(); } /// This function returns a callback that can be used in an event map: - /// /// Template.tplName.events({ - /// 'click .elementClass': Popup.open("popupName") - /// }) - /// + /// 'click .elementClass': Popup.open("popupName"), + /// }); /// The popup inherit the data context of its parent. open(name) { - let self = this - const popupName = `${name}Popup` + const self = this; + const popupName = `${name}Popup`; function clickFromPopup(evt) { - return $(evt.target).closest('.js-pop-over').length !== 0 + return $(evt.target).closest('.js-pop-over').length !== 0; } return function(evt) { // If a popup is already opened, clicking again on the opener element // should close it -- and interrupt the current `open` function. if (self.isOpen()) { - let previousOpenerElement = self._getTopStack().openerElement + const previousOpenerElement = self._getTopStack().openerElement; if (previousOpenerElement === evt.currentTarget) { - return self.close() + return self.close(); } else { - $(previousOpenerElement).removeClass('is-active') + $(previousOpenerElement).removeClass('is-active'); } } @@ -58,16 +56,16 @@ window.Popup = new class { // if the popup has no parent, or from the parent `openerElement` if it // has one. This allows us to position a sub-popup exactly at the same // position than its parent. - let openerElement + let openerElement; if (clickFromPopup(evt)) { - openerElement = self._getTopStack().openerElement + openerElement = self._getTopStack().openerElement; } else { - self._stack = [] - openerElement = evt.currentTarget + self._stack = []; + openerElement = evt.currentTarget; } - $(openerElement).addClass('is-active') - evt.preventDefault() + $(openerElement).addClass('is-active'); + evt.preventDefault(); // We push our popup data to the stack. The top of the stack is always // used as the data source for our current popup. @@ -79,7 +77,7 @@ window.Popup = new class { depth: self._stack.length, offset: self._getOffset(openerElement), dataContext: this.currentData && this.currentData() || this, - }) + }); // If there are no popup currently opened we use the Blaze API to render // one into the DOM. We use a reactive function as the data parameter that @@ -90,39 +88,38 @@ window.Popup = new class { // Otherwise if there is already a popup open we just need to invalidate // our internal dependency, and since we just changed the top element of // our internal stack, the popup will be updated with the new data. - if (! self.isOpen()) { + if (!self.isOpen()) { self.current = Blaze.renderWithData(self.template, () => { - self._dep.depend() - return _.extend(self._getTopStack(), { stack: self._stack }) - }, document.body) + self._dep.depend(); + return _.extend(self._getTopStack(), { stack: self._stack }); + }, document.body); } else { - self._dep.changed() + self._dep.changed(); } - } + }; } /// This function returns a callback that can be used in an event map: - /// /// Template.tplName.events({ /// 'click .elementClass': Popup.afterConfirm("popupName", function() { /// // What to do after the user has confirmed the action - /// }) - /// }) + /// }), + /// }); afterConfirm(name, action) { - let self = this + const self = this; return function(evt, tpl) { - let context = this.currentData && this.currentData() || this - context.__afterConfirmAction = action - self.open(name).call(context, evt, tpl) - } + const context = this.currentData && this.currentData() || this; + context.__afterConfirmAction = action; + self.open(name).call(context, evt, tpl); + }; } /// The public reactive state of the popup. isOpen() { - this._dep.changed() - return !! this.current + this._dep.changed(); + return Boolean(this.current); } /// In case the popup was opened from a parent popup we can get back to it @@ -132,45 +129,45 @@ window.Popup = new class { /// steps back is greater than the popup stack size, the popup will be closed. back(n = 1) { if (this._stack.length > n) { - _.times(n, () => this._stack.pop()) - this._dep.changed() + _.times(n, () => this._stack.pop()); + this._dep.changed(); } else { - this.close() + this.close(); } } /// Close the current opened popup. close() { if (this.isOpen()) { - Blaze.remove(this.current) - this.current = null + Blaze.remove(this.current); + this.current = null; - let openerElement = this._getTopStack().openerElement - $(openerElement).removeClass('is-active') + const openerElement = this._getTopStack().openerElement; + $(openerElement).removeClass('is-active'); - this._stack = [] + this._stack = []; } } // An utility fonction that returns the top element of the internal stack _getTopStack() { - return this._stack[this._stack.length - 1] + return this._stack[this._stack.length - 1]; } // We automatically calculate the popup offset from the reference element // position and dimensions. We also reactively use the window dimensions to // ensure that the popup is always visible on the screen. _getOffset(element) { - let $element = $(element) + const $element = $(element); return () => { - windowResizeDep.depend() - const offset = $element.offset() - const popupWidth = 300 + 15 + windowResizeDep.depend(); + const offset = $element.offset(); + const popupWidth = 300 + 15; return { left: Math.min(offset.left, $(window).width() - popupWidth), top: offset.top + $element.outerHeight(), - } - } + }; + }; } // We get the title from the translation files. Instead of returning the @@ -178,22 +175,22 @@ window.Popup = new class { // is a reactive data source, the title will be changed reactively. _getTitle(popupName) { return () => { - const translationKey = `${popupName}-title` + const translationKey = `${popupName}-title`; // XXX There is no public API to check if there is an available // translation for a given key. So we try to translate the key and if the // translation output equals the key input we deduce that no translation // was available and returns `false`. There is a (small) risk a false // positives. - const title = TAPi18n.__(translationKey) - return title !== translationKey ? title : false - } + const title = TAPi18n.__(translationKey); + return title !== translationKey ? title : false; + }; } -} +}; // We close a potential opened popup on any left click on the document, or go // one step back by pressing escape. -const escapeActions = ['back', 'close'] +const escapeActions = ['back', 'close']; _.each(escapeActions, (actionName) => { EscapeActions.register(`popup-${actionName}`, () => Popup[actionName](), @@ -202,6 +199,6 @@ _.each(escapeActions, (actionName) => { noClickEscapeOn: '.js-pop-over', enabledOnClick: actionName === 'close', } - ) -}) + ); +}); diff --git a/client/lib/unsavedEdits.js b/client/lib/unsavedEdits.js index 55ea2529..dc267bfb 100644 --- a/client/lib/unsavedEdits.js +++ b/client/lib/unsavedEdits.js @@ -27,9 +27,9 @@ UnsavedEdits = { // _collection: UnsavedEditCollection, get({ fieldName, docId }, defaultTo = '') { - let unsavedValue = this._getCollectionDocument(fieldName, docId); + const unsavedValue = this._getCollectionDocument(fieldName, docId); if (unsavedValue) { - return unsavedValue.value + return unsavedValue.value; } else { return defaultTo; } @@ -40,13 +40,9 @@ UnsavedEdits = { }, set({ fieldName, docId }, value) { - let currentDoc = this._getCollectionDocument(fieldName, docId); + const currentDoc = this._getCollectionDocument(fieldName, docId); if (currentDoc) { - UnsavedEditCollection.update(currentDoc._id, { - $set: { - value: value - } - }); + UnsavedEditCollection.update(currentDoc._id, { $set: { value }}); } else { UnsavedEditCollection.insert({ fieldName, @@ -57,7 +53,7 @@ UnsavedEdits = { }, reset({ fieldName, docId }) { - let currentDoc = this._getCollectionDocument(fieldName, docId); + const currentDoc = this._getCollectionDocument(fieldName, docId); if (currentDoc) { UnsavedEditCollection.remove(currentDoc._id); } @@ -65,13 +61,13 @@ UnsavedEdits = { _getCollectionDocument(fieldName, docId) { return UnsavedEditCollection.findOne({fieldName, docId}); - } -} + }, +}; Blaze.registerHelper('getUnsavedValue', (fieldName, docId, defaultTo) => { // Workaround some blaze feature that ass a list of keywords arguments as the // last parameter (even if the caller didn't specify any). - if (! _.isString(defaultTo)) { + if (!_.isString(defaultTo)) { defaultTo = ''; } return UnsavedEdits.get({ fieldName, docId }, defaultTo); diff --git a/client/lib/utils.js b/client/lib/utils.js index c6a9adc5..0cd93419 100644 --- a/client/lib/utils.js +++ b/client/lib/utils.js @@ -1,62 +1,70 @@ Utils = { // XXX We should remove these two methods - goBoardId: function(_id) { - var board = Boards.findOne(_id); + goBoardId(_id) { + const board = Boards.findOne(_id); return board && FlowRouter.go('board', { id: board._id, - slug: board.slug + slug: board.slug, }); }, - goCardId: function(_id) { - var card = Cards.findOne(_id); - var board = Boards.findOne(card.boardId); + goCardId(_id) { + const card = Cards.findOne(_id); + const board = Boards.findOne(card.boardId); return board && FlowRouter.go('card', { cardId: card._id, boardId: board._id, - slug: board.slug + slug: board.slug, }); }, - capitalize: function(string) { + capitalize(string) { return string.charAt(0).toUpperCase() + string.slice(1); }, - getLabelIndex: function(boardId, labelId) { - var board = Boards.findOne(boardId); - var labels = {}; - _.each(board.labels, function(a, b) { + getLabelIndex(boardId, labelId) { + const board = Boards.findOne(boardId); + const labels = {}; + _.each(board.labels, (a, b) => { labels[a._id] = b; }); return { index: labels[labelId], - key: function(key) { - return 'labels.' + labels[labelId] + '.' + key; - } + key(key) { + return `labels.${labels[labelId]}.${key}`; + }, }; }, // Determine the new sort index - calculateIndex: function(prevCardDomElement, nextCardDomElement, nCards) { - nCards = nCards || 1; - + calculateIndex(prevCardDomElement, nextCardDomElement, nCards = 1) { + let base, increment; // If we drop the card to an empty column - if (! prevCardDomElement && ! nextCardDomElement) { - return {base: 0, increment: 1}; + if (!prevCardDomElement && !nextCardDomElement) { + base = 0; + increment = 1; // If we drop the card in the first position - } else if (! prevCardDomElement) { - return {base: Blaze.getData(nextCardDomElement).sort - 1, increment: -1}; + } else if (!prevCardDomElement) { + base = Blaze.getData(nextCardDomElement).sort - 1; + increment = -1; // If we drop the card in the last position - } else if (! nextCardDomElement) { - return {base: Blaze.getData(prevCardDomElement).sort + 1, increment: 1}; + } else if (!nextCardDomElement) { + base = Blaze.getData(prevCardDomElement).sort + 1; + increment = 1; } // In the general case take the average of the previous and next element // sort indexes. else { - var prevSortIndex = Blaze.getData(prevCardDomElement).sort; - var nextSortIndex = Blaze.getData(nextCardDomElement).sort; - var increment = (nextSortIndex - prevSortIndex) / (nCards + 1); - return {base: prevSortIndex + increment, increment: increment}; + const prevSortIndex = Blaze.getData(prevCardDomElement).sort; + const nextSortIndex = Blaze.getData(nextCardDomElement).sort; + increment = (nextSortIndex - prevSortIndex) / (nCards + 1); + base = prevSortIndex + increment; } - } + // XXX Return a generator that yield values instead of a base with a + // increment number. + return { + base, + increment, + }; + }, }; -- cgit v1.2.3-1-g7c22