summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/components/boards/router.js8
-rw-r--r--client/components/cards/details.jade3
-rw-r--r--client/components/forms/inlinedform.js22
-rw-r--r--client/components/main/editor.js (renamed from client/components/main/rendered.js)32
-rw-r--r--client/components/main/events.js8
-rw-r--r--client/components/main/templates.html2
-rw-r--r--client/components/sidebar/sidebar.jade6
-rw-r--r--client/components/sidebar/sidebar.js29
-rw-r--r--client/config/router.js4
-rw-r--r--client/lib/filter.js18
-rw-r--r--client/lib/keyboard.js58
-rw-r--r--client/lib/popup.js4
12 files changed, 144 insertions, 50 deletions
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/rendered.js b/client/components/main/editor.js
index 787e8225..95a8dc5d 100644
--- a/client/components/main/rendered.js
+++ b/client/components/main/editor.js
@@ -1,5 +1,9 @@
-Template.editor.rendered = function() {
- this.$('textarea').textcomplete([
+var dropdownMenuIsOpened = false;
+
+Template.editor.onRendered(function() {
+ var $textarea = this.$('textarea');
+
+ $textarea.textcomplete([
// Emojies
{
match: /\B:([\-+\w]*)$/,
@@ -37,4 +41,26 @@ Template.editor.rendered = function() {
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/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 @@
</template>
<template name="editor">
- <textarea class="{{class}}" placeholder="{{_ 'comment-placeholder'}}" id="{{id}}" tabindex="1">{{> UI.contentBlock }}</textarea>
+ <textarea class="{{class}}" placeholder="{{_ 'comment-placeholder'}}" id="{{id}}" autofocus="{{autofocus}}">{{> UI.contentBlock}}</textarea>
</template>
<template name="viewer">{{#markdown}}{{#emoji}}{{#mentions}}{{> UI.contentBlock }}{{/mentions}}{{/emoji}}{{/markdown}}</template>
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); }
+);
diff --git a/client/config/router.js b/client/config/router.js
index 2fa1908d..d4bc3c4f 100644
--- a/client/config/router.js
+++ b/client/config/router.js
@@ -20,7 +20,9 @@ Router.configure({
// Reset default sessions
Session.set('error', false);
- Popup.close();
+ Tracker.nonreactive(function() {
+ EscapeActions.executeLowerThan(40);
+ });
this.next();
}
diff --git a/client/lib/filter.js b/client/lib/filter.js
index 507a2bb7..d96fa89c 100644
--- a/client/lib/filter.js
+++ b/client/lib/filter.js
@@ -4,6 +4,10 @@
// goal is to filter complete documents by using the local filters for each
// fields.
+var showFilterSidebar = function() {
+ 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() {
@@ -18,29 +22,27 @@ _.extend(SetFilter.prototype, {
},
add: function(val) {
- if (this.indexOfVal(val) === -1) {
+ if (this._indexOfVal(val) === -1) {
this._selectedElements.push(val);
this._dep.changed();
+ showFilterSidebar();
}
},
remove: function(val) {
var indexOfVal = this._indexOfVal(val);
- if (this.indexOfVal(val) !== -1) {
+ if (this._indexOfVal(val) !== -1) {
this._selectedElements.splice(indexOfVal, 1);
this._dep.changed();
}
},
toogle: function(val) {
- var indexOfVal = this._indexOfVal(val);
- if (indexOfVal === -1) {
- this._selectedElements.push(val);
+ if (this._indexOfVal(val) === -1) {
+ this.add(val);
} else {
- this._selectedElements.splice(indexOfVal, 1);
+ this.remove(val);
}
-
- this._dep.changed();
},
reset: function() {
diff --git a/client/lib/keyboard.js b/client/lib/keyboard.js
index 8601e623..723d498b 100644
--- a/client/lib/keyboard.js
+++ b/client/lib/keyboard.js
@@ -3,21 +3,6 @@
// XXX There is no reason to define these shortcuts globally, they should be
// attached to a template (most of them will go in the `board` template).
-// Pressing `Escape` should close the last opened “element” and only the last
-// one -- curently we handle popups and the card detailed view of the sidebar.
-Mousetrap.bind('esc', function() {
- if (currentlyOpenedForm.get() !== null) {
- currentlyOpenedForm.get().close();
-
- } else if (Popup.isOpen()) {
- Popup.back();
-
- // XXX We should have a higher level API
- } else if (Session.get('currentCard')) {
- Utils.goBoardId(Session.get('currentBoard'));
- }
-});
-
Mousetrap.bind('w', function() {
Sidebar.toogle();
});
@@ -48,3 +33,46 @@ Mousetrap.bind(['down', 'up'], function(evt, key) {
Utils.goCardId(nextCardId);
}
});
+
+// Pressing `Escape` should close the last opened “element” and only the last
+// one. Components can register themself using a priority number (smaller is
+// closed first), a condition, and an action.This is used by Popup or
+// inlinedForm for instance. When we press escape we execute the action which
+// condition is valid with the highest priority.
+EscapeActions = {
+ _actions: [],
+
+ register: function(priority, condition, action) {
+ // XXX Rewrite this with ES6: .push({ priority, condition, action })
+ this._actions.push({
+ priority: priority,
+ condition: condition,
+ action: action
+ });
+ // XXX Rewrite this with ES6: => function
+ this._actions = _.sortBy(this._actions, function(a) { return a.priority; });
+ },
+
+ executeLowest: function() {
+ var topActiveAction = _.find(this._actions, function(a) {
+ return !! a.condition();
+ });
+ return topActiveAction && topActiveAction.action();
+ },
+
+ executeLowerThan: function(maxPriority) {
+ maxPriority = maxPriority || Infinity;
+ var currentAction;
+ for (var i = 0; i < this._actions.length; i++) {
+ currentAction = this._actions[i];
+ if (currentAction.priority > maxPriority)
+ return;
+ if (!! currentAction.condition())
+ currentAction.action();
+ }
+ }
+};
+
+Mousetrap.bind('esc', function() {
+ EscapeActions.executeLowest();
+});
diff --git a/client/lib/popup.js b/client/lib/popup.js
index 04f7dbf6..70f2660f 100644
--- a/client/lib/popup.js
+++ b/client/lib/popup.js
@@ -201,3 +201,7 @@ $(document).on('click', function(evt) {
Popup.close();
}
});
+
+// Press escape to close the popup.
+var bindPopup = function(f) { return _.bind(f, Popup); };
+EscapeActions.register(20, bindPopup(Popup.isOpen), bindPopup(Popup.close));