From 40c2411f2a1ce0bbd177f377828f9d6700112b06 Mon Sep 17 00:00:00 2001 From: Maxime Quandalle Date: Tue, 26 May 2015 20:30:01 +0200 Subject: Implement a new system to handle "escape actions" The new EscapeActions object decide what to do when the user press the Escape key (such as closing a opened popup or inlined form). This commit also re-introduced the sidebar current view as a sidebar component local state. --- client/components/boards/router.js | 8 ++++- client/components/cards/details.jade | 3 +- client/components/forms/inlinedform.js | 22 ++++++++---- client/components/main/editor.js | 66 ++++++++++++++++++++++++++++++++++ client/components/main/events.js | 8 ----- client/components/main/rendered.js | 40 --------------------- client/components/main/templates.html | 2 +- client/components/sidebar/sidebar.jade | 6 +--- client/components/sidebar/sidebar.js | 29 ++++++++++++++- 9 files changed, 121 insertions(+), 63 deletions(-) create mode 100644 client/components/main/editor.js delete mode 100644 client/components/main/events.js delete mode 100644 client/components/main/rendered.js (limited to 'client/components') diff --git a/client/components/boards/router.js b/client/components/boards/router.js index 9c5bee35..80fadd9e 100644 --- a/client/components/boards/router.js +++ b/client/components/boards/router.js @@ -39,7 +39,7 @@ Router.route('/boards/:boardId/:slug/:cardId', { template: 'board', onAfterAction: function() { Tracker.nonreactive(function() { - if (! Session.get('currentCard') && typeof Sidebar !== 'undefined') { + if (! Session.get('currentCard') && Sidebar) { Sidebar.hide(); } }); @@ -55,3 +55,9 @@ Router.route('/boards/:boardId/:slug/:cardId', { return Boards.findOne(this.params.boardId); } }); + +// Close the card details pane by pressing escape +EscapeActions.register(50, + function() { return ! Session.equals('currentCard', null); }, + function() { Utils.goBoardId(Session.get('currentBoard')); } +); diff --git a/client/components/cards/details.jade b/client/components/cards/details.jade index 55cc4b9e..b77c3961 100644 --- a/client/components/cards/details.jade +++ b/client/components/cards/details.jade @@ -26,7 +26,8 @@ template(name="cardDetails") h3 Description +inlinedForm(classNames="js-card-description") i.fa.fa-times.js-close-inlined-form - textarea(autofocus)= description + +editor(autofocus=true) + = description button(type="submit") {{_ 'edit'}} else .js-open-inlined-form diff --git a/client/components/forms/inlinedform.js b/client/components/forms/inlinedform.js index 2e2b2eba..200a6f9d 100644 --- a/client/components/forms/inlinedform.js +++ b/client/components/forms/inlinedform.js @@ -15,7 +15,9 @@ // We can only have one inlined form element opened at a time // XXX Could we avoid using a global here ? This is used in Mousetrap // keyboard.js -currentlyOpenedForm = new ReactiveVar(null); +var currentlyOpenedForm = new ReactiveVar(null); + +var inlinedFormEscapePriority = 30; BlazeComponent.extendComponent({ template: function() { @@ -32,9 +34,10 @@ BlazeComponent.extendComponent({ open: function() { // Close currently opened form, if any - if (currentlyOpenedForm.get() !== null) { - currentlyOpenedForm.get().close(); - } + // if (currentlyOpenedForm.get() !== null) { + // currentlyOpenedForm.get().close(); + // } + EscapeActions.executeLowerThan(inlinedFormEscapePriority); this.isOpen.set(true); currentlyOpenedForm.set(this); }, @@ -46,7 +49,8 @@ BlazeComponent.extendComponent({ }, getValue: function() { - return this.isOpen.get() && this.find('textarea,input[type=text]').value; + var input = this.find('textarea,input[type=text]'); + return this.isOpen.get() && input && input.value; }, saveValue: function() { @@ -66,7 +70,7 @@ BlazeComponent.extendComponent({ 'keydown form input, keydown form textarea': function(evt) { if (evt.keyCode === 27) { evt.preventDefault(); - this.close(); + EscapeActions.executeLowest(); } }, @@ -91,3 +95,9 @@ BlazeComponent.extendComponent({ }]; } }).register('inlinedForm'); + +// Press escape to close the currently opened inlinedForm +EscapeActions.register(inlinedFormEscapePriority, + function() { return currentlyOpenedForm.get() !== null; }, + function() { currentlyOpenedForm.get().close(); } +); diff --git a/client/components/main/editor.js b/client/components/main/editor.js new file mode 100644 index 00000000..95a8dc5d --- /dev/null +++ b/client/components/main/editor.js @@ -0,0 +1,66 @@ +var dropdownMenuIsOpened = false; + +Template.editor.onRendered(function() { + var $textarea = this.$('textarea'); + + $textarea.textcomplete([ + // Emojies + { + match: /\B:([\-+\w]*)$/, + search: function(term, callback) { + callback($.map(Emoji.values, function(emoji) { + return emoji.indexOf(term) === 0 ? emoji : null; + })); + }, + template: function(value) { + var image = ''; + return image + value; + }, + replace: function(value) { + return ':' + value + ':'; + }, + index: 1 + }, + + // User mentions + { + match: /\B@(\w*)$/, + search: function(term, callback) { + var currentBoard = Boards.findOne(Session.get('currentBoard')); + callback($.map(currentBoard.members, function(member) { + var username = Users.findOne(member.userId).username; + return username.indexOf(term) === 0 ? username : null; + })); + }, + template: function(value) { + return value; + }, + replace: function(username) { + return '@' + username + ' '; + }, + index: 1 + } + ]); + + // Since commit d474017 jquery-textComplete automatically closes a potential + // opened dropdown menu when the user press Escape. This behavior conflicts + // with our EscapeActions system, but it's too complicated and hacky to + // monkey-pach textComplete to disable it -- I tried. Instead we listen to + // 'open' and 'hide' events, and create a ghost escapeAction when the dropdown + // is opened (and rely on textComplete to execute the actual action). + $textarea.on({ + 'textComplete:show': function() { + dropdownMenuIsOpened = true; + }, + 'textComplete:hide': function() { + Tracker.afterFlush(function() { + dropdownMenuIsOpened = false; + }); + } + }); +}); + +EscapeActions.register(10, + function() { return dropdownMenuIsOpened; }, + function() {} +); diff --git a/client/components/main/events.js b/client/components/main/events.js deleted file mode 100644 index beb90c5e..00000000 --- a/client/components/main/events.js +++ /dev/null @@ -1,8 +0,0 @@ -Template.editor.events({ - // Pressing Ctrl+Enter should submit the form. - 'keydown textarea': function(event) { - if (event.keyCode === 13 && (event.metaKey || event.ctrlKey)) { - $(event.currentTarget).parents('form:first').submit(); - } - } -}); diff --git a/client/components/main/rendered.js b/client/components/main/rendered.js deleted file mode 100644 index 787e8225..00000000 --- a/client/components/main/rendered.js +++ /dev/null @@ -1,40 +0,0 @@ -Template.editor.rendered = function() { - this.$('textarea').textcomplete([ - // Emojies - { - match: /\B:([\-+\w]*)$/, - search: function(term, callback) { - callback($.map(Emoji.values, function(emoji) { - return emoji.indexOf(term) === 0 ? emoji : null; - })); - }, - template: function(value) { - var image = ''; - return image + value; - }, - replace: function(value) { - return ':' + value + ':'; - }, - index: 1 - }, - - // User mentions - { - match: /\B@(\w*)$/, - search: function(term, callback) { - var currentBoard = Boards.findOne(Session.get('currentBoard')); - callback($.map(currentBoard.members, function(member) { - var username = Users.findOne(member.userId).username; - return username.indexOf(term) === 0 ? username : null; - })); - }, - template: function(value) { - return value; - }, - replace: function(username) { - return '@' + username + ' '; - }, - index: 1 - } - ]); -}; diff --git a/client/components/main/templates.html b/client/components/main/templates.html index e9be0f93..4828663a 100644 --- a/client/components/main/templates.html +++ b/client/components/main/templates.html @@ -12,7 +12,7 @@ diff --git a/client/components/sidebar/sidebar.jade b/client/components/sidebar/sidebar.jade index 07cd777c..07d6bbcf 100644 --- a/client/components/sidebar/sidebar.jade +++ b/client/components/sidebar/sidebar.jade @@ -4,11 +4,7 @@ template(name="sidebar") class="{{#if isTongueHidden}}is-hidden{{/if}}") i.fa.fa-chevron-left .sidebar-content.js-board-sidebar-content.js-perfect-scrollbar - //- XXX https://github.com/peerlibrary/meteor-blaze-components/issues/30 - if Filter.isActive - +filterSidebar - else - +homeSidebar + +Template.dynamic(template=getViewTemplate) template(name='homeSidebar') +membersWidget diff --git a/client/components/sidebar/sidebar.js b/client/components/sidebar/sidebar.js index 6e45b5cf..729bc42b 100644 --- a/client/components/sidebar/sidebar.js +++ b/client/components/sidebar/sidebar.js @@ -1,3 +1,7 @@ +var defaultView = 'home'; + +Sidebar = null; + BlazeComponent.extendComponent({ template: function() { return 'sidebar'; @@ -9,9 +13,14 @@ BlazeComponent.extendComponent({ onCreated: function() { this._isOpen = new ReactiveVar(! Session.get('currentCard')); + this._view = new ReactiveVar(defaultView); Sidebar = this; }, + onDestroyed: function() { + Sidebar = null; + }, + isOpen: function() { return this._isOpen.get(); }, @@ -43,7 +52,20 @@ BlazeComponent.extendComponent({ }, isTongueHidden: function() { - return this.isOpen() && Filter.isActive(); + return this.isOpen() && this.getView() !== defaultView; + }, + + getView: function() { + return this._view.get(); + }, + + setView: function(view) { + view = view || defaultView; + this._view.set(view); + }, + + getViewTemplate: function() { + return this.getView() + 'Sidebar'; }, onRendered: function() { @@ -74,3 +96,8 @@ BlazeComponent.extendComponent({ }]); } }).register('sidebar'); + +EscapeActions.register(40, + function() { return Sidebar && Sidebar.getView() !== defaultView; }, + function() { Sidebar.setView(defaultView); } +); -- cgit v1.2.3-1-g7c22