mirror of
https://github.com/wekan/wekan.git
synced 2025-12-16 15:30:13 +01:00
Click on the page to escape the last action
This is a generalization of what we had for closing a popup by clicking outside of it. It now works for inlinedForms and detailsPane as well.
This commit is contained in:
parent
12919cbfc6
commit
92dd05d06d
17 changed files with 199 additions and 145 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
template(name="headerBoard")
|
template(name="headerBoard")
|
||||||
h1.header-board-menu(
|
h1.header-board-menu
|
||||||
class="{{#if currentUser.isBoardMember}}is-clickable js-edit-board-title{{/if}}")
|
a(class="{{#if currentUser.isBoardAdmin}}js-edit-board-title{{else}}is-disabled{{/if}}")
|
||||||
= title
|
= title
|
||||||
|
|
||||||
.board-header-btns.left
|
.board-header-btns.left
|
||||||
unless isSandstorm
|
unless isSandstorm
|
||||||
|
|
@ -12,7 +12,7 @@ template(name="headerBoard")
|
||||||
if showStarCounter
|
if showStarCounter
|
||||||
span {{_ 'board-nb-stars' stars}}
|
span {{_ 'board-nb-stars' stars}}
|
||||||
|
|
||||||
a.board-header-btn.js-change-visibility(class="{{#unless currentUser.isBoardAdmin}}no-edit{{/unless}}")
|
a.board-header-btn(class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}")
|
||||||
i.fa(class="{{#if isPublic}}fa-globe{{else}}fa-lock{{/if}}")
|
i.fa(class="{{#if isPublic}}fa-globe{{else}}fa-lock{{/if}}")
|
||||||
span {{_ permission}}
|
span {{_ permission}}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ Router.route('/boards/:boardId/:slug/:cardId', {
|
||||||
Sidebar.hide();
|
Sidebar.hide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
EscapeActions.executeUpTo('popup');
|
||||||
var params = this.params;
|
var params = this.params;
|
||||||
Session.set('currentBoard', params.boardId);
|
Session.set('currentBoard', params.boardId);
|
||||||
Session.set('currentCard', params.cardId);
|
Session.set('currentCard', params.cardId);
|
||||||
|
|
@ -55,9 +56,3 @@ Router.route('/boards/:boardId/:slug/:cardId', {
|
||||||
return Boards.findOne(this.params.boardId);
|
return Boards.findOne(this.params.boardId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Close the card details pane by pressing escape
|
|
||||||
EscapeActions.register('detailsPane',
|
|
||||||
function() { Utils.goBoardId(Session.get('currentBoard')); },
|
|
||||||
function() { return ! Session.equals('currentCard', null); }
|
|
||||||
);
|
|
||||||
|
|
|
||||||
|
|
@ -94,3 +94,11 @@ Template.moveCardPopup.events({
|
||||||
Popup.close();
|
Popup.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Close the card details pane by pressing escape
|
||||||
|
EscapeActions.register('detailsPane',
|
||||||
|
function() { Utils.goBoardId(Session.get('currentBoard')); },
|
||||||
|
function() { return ! Session.equals('currentCard', null); }, {
|
||||||
|
noClickEscapeOn: '.js-card-details'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
template(name='inlinedForm')
|
template(name='inlinedForm')
|
||||||
if isOpen.get
|
if isOpen.get
|
||||||
form(id=id class=classNames)
|
form.js-inlined-form(id=id class=classNames)
|
||||||
+Template.contentBlock
|
+Template.contentBlock
|
||||||
else
|
else
|
||||||
+Template.elseBlock
|
+Template.elseBlock
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ BlazeComponent.extendComponent({
|
||||||
|
|
||||||
open: function() {
|
open: function() {
|
||||||
// Close currently opened form, if any
|
// Close currently opened form, if any
|
||||||
EscapeActions.executeLowerThan('inlinedForm');
|
EscapeActions.executeUpTo('inlinedForm');
|
||||||
this.isOpen.set(true);
|
this.isOpen.set(true);
|
||||||
currentlyOpenedForm.set(this);
|
currentlyOpenedForm.set(this);
|
||||||
},
|
},
|
||||||
|
|
@ -61,18 +61,6 @@ BlazeComponent.extendComponent({
|
||||||
'click .js-close-inlined-form': this.close,
|
'click .js-close-inlined-form': this.close,
|
||||||
'click .js-open-inlined-form': this.open,
|
'click .js-open-inlined-form': this.open,
|
||||||
|
|
||||||
// Close the inlined form by pressing escape.
|
|
||||||
//
|
|
||||||
// Keydown (and not keypress) in necessary here because the `keyCode`
|
|
||||||
// property is consistent in all browsers, (there is not keyCode for the
|
|
||||||
// `keypress` event in firefox)
|
|
||||||
'keydown form input, keydown form textarea': function(evt) {
|
|
||||||
if (evt.keyCode === 27) {
|
|
||||||
evt.preventDefault();
|
|
||||||
EscapeActions.executeLowest();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Pressing Ctrl+Enter should submit the form
|
// Pressing Ctrl+Enter should submit the form
|
||||||
'keydown form textarea': function(evt) {
|
'keydown form textarea': function(evt) {
|
||||||
if (evt.keyCode === 13 && (evt.metaKey || evt.ctrlKey)) {
|
if (evt.keyCode === 13 && (evt.metaKey || evt.ctrlKey)) {
|
||||||
|
|
@ -98,5 +86,7 @@ BlazeComponent.extendComponent({
|
||||||
// Press escape to close the currently opened inlinedForm
|
// Press escape to close the currently opened inlinedForm
|
||||||
EscapeActions.register('inlinedForm',
|
EscapeActions.register('inlinedForm',
|
||||||
function() { currentlyOpenedForm.get().close(); },
|
function() { currentlyOpenedForm.get().close(); },
|
||||||
function() { return currentlyOpenedForm.get() !== null; }
|
function() { return currentlyOpenedForm.get() !== null; }, {
|
||||||
|
noClickEscapeOn: '.js-inlined-form'
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ BlazeComponent.extendComponent({
|
||||||
placeholder: 'minicard-wrapper placeholder',
|
placeholder: 'minicard-wrapper placeholder',
|
||||||
start: function(evt, ui) {
|
start: function(evt, ui) {
|
||||||
ui.placeholder.height(ui.helper.height());
|
ui.placeholder.height(ui.helper.height());
|
||||||
EscapeActions.executeLowerThan('popup');
|
EscapeActions.executeUpTo('popup');
|
||||||
boardComponent.setIsDragging(true);
|
boardComponent.setIsDragging(true);
|
||||||
},
|
},
|
||||||
stop: function(evt, ui) {
|
stop: function(evt, ui) {
|
||||||
|
|
|
||||||
|
|
@ -12,16 +12,15 @@
|
||||||
font-size: 12px
|
font-size: 12px
|
||||||
display: flex
|
display: flex
|
||||||
|
|
||||||
#header-user-bar
|
#header-user-bar,
|
||||||
ul li
|
ul li
|
||||||
color: darken(white, 17%)
|
color: darken(white, 17%)
|
||||||
|
|
||||||
a, .fa
|
.fa
|
||||||
color: inherit
|
color: inherit
|
||||||
text-decoration: none
|
|
||||||
|
|
||||||
&:hover
|
a:hover, a.is-active
|
||||||
color: white
|
color: white
|
||||||
|
|
||||||
ul
|
ul
|
||||||
flex: 1
|
flex: 1
|
||||||
|
|
@ -76,9 +75,6 @@
|
||||||
float: left
|
float: left
|
||||||
border-radius: 3px
|
border-radius: 3px
|
||||||
|
|
||||||
&.is-clickable
|
|
||||||
cursor: pointer
|
|
||||||
|
|
||||||
.board-header-btns
|
.board-header-btns
|
||||||
display: block
|
display: block
|
||||||
margin-top: 3px
|
margin-top: 3px
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,6 @@ function whichTransitionEvent() {
|
||||||
var transitionEvent = whichTransitionEvent();
|
var transitionEvent = whichTransitionEvent();
|
||||||
|
|
||||||
Popup.template.events({
|
Popup.template.events({
|
||||||
click: function(evt) {
|
|
||||||
if (evt.originalEvent) {
|
|
||||||
evt.originalEvent.clickInPopup = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'click .js-back-view': function() {
|
'click .js-back-view': function() {
|
||||||
Popup.back();
|
Popup.back();
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
.pop-over(
|
.pop-over.js-pop-over(
|
||||||
class="{{#unless title}}miniprofile{{/unless}}"
|
class="{{#unless title}}miniprofile{{/unless}}"
|
||||||
class=currentBoard.colorClass
|
class=currentBoard.colorClass
|
||||||
class="{{#unless title}}no-title{{/unless}}"
|
class="{{#unless title}}no-title{{/unless}}"
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ BlazeComponent.extendComponent({
|
||||||
snap: false,
|
snap: false,
|
||||||
snapMode: 'both',
|
snapMode: 'both',
|
||||||
start: function() {
|
start: function() {
|
||||||
EscapeActions.executeLowerThan('popup');
|
EscapeActions.executeUpTo('popup');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
template(name="headerUserBar")
|
template(name="headerUserBar")
|
||||||
a#header-user-bar
|
#header-user-bar
|
||||||
.header-user-bar-name.js-open-header-member-menu
|
a.header-user-bar-name.js-open-header-member-menu
|
||||||
i.fa.fa-chevron-down
|
i.fa.fa-chevron-down
|
||||||
if currentUser.profile.name
|
if currentUser.profile.name
|
||||||
= currentUser.profile.name
|
= currentUser.profile.name
|
||||||
else
|
else
|
||||||
= currentUser.username
|
= currentUser.username
|
||||||
.header-user-bar-avatar.js-change-avatar
|
a.header-user-bar-avatar.js-change-avatar
|
||||||
+userAvatar(user=currentUser)
|
+userAvatar(user=currentUser)
|
||||||
|
|
||||||
template(name="memberMenuPopup")
|
template(name="memberMenuPopup")
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ Router.configure({
|
||||||
return this.redirect('atSignIn');
|
return this.redirect('atSignIn');
|
||||||
}
|
}
|
||||||
|
|
||||||
// We want to execute our EscapeActions.executeLowerThan method any time the
|
// We want to execute our EscapeActions.executeUpTo method any time the
|
||||||
// route is changed, but not if the stays the same but only the parameters
|
// route is changed, but not if the stays the same but only the parameters
|
||||||
// change (eg when a user is navigation from a card A to a card B). Iron-
|
// change (eg when a user is navigation from a card A to a card B). Iron-
|
||||||
// Router onBeforeAction is a reactive context (which is a bad desig choice
|
// Router onBeforeAction is a reactive context (which is a bad desig choice
|
||||||
|
|
|
||||||
157
client/lib/escapeActions.js
Normal file
157
client/lib/escapeActions.js
Normal file
|
|
@ -0,0 +1,157 @@
|
||||||
|
// Pressing `Escape` should close the last opened “element” and only the last
|
||||||
|
// one. Components can register themselves using a label a condition, and an
|
||||||
|
// action. This is used by Popup or inlinedForm for instance. When we press
|
||||||
|
// escape we execute the action which have a valid condition and his the highest
|
||||||
|
// in the label hierarchy.
|
||||||
|
EscapeActions = {
|
||||||
|
_actions: [],
|
||||||
|
|
||||||
|
// Executed in order
|
||||||
|
hierarchy: [
|
||||||
|
'textcomplete',
|
||||||
|
'popup',
|
||||||
|
'inlinedForm',
|
||||||
|
'detailsPane',
|
||||||
|
'multiselection',
|
||||||
|
'sidebarView'
|
||||||
|
],
|
||||||
|
|
||||||
|
register: function(label, action, condition, options) {
|
||||||
|
condition = condition || function() { return true; };
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
// XXX Rewrite this with ES6: .push({ priority, condition, action })
|
||||||
|
var priority = this.hierarchy.indexOf(label);
|
||||||
|
if (priority === -1) {
|
||||||
|
throw Error('You must define the label in the EscapeActions hierarchy');
|
||||||
|
}
|
||||||
|
|
||||||
|
this._actions.push({
|
||||||
|
priority: priority,
|
||||||
|
condition: condition,
|
||||||
|
action: action,
|
||||||
|
noClickEscapeOn: options.noClickEscapeOn
|
||||||
|
});
|
||||||
|
// XXX Rewrite this with ES6: => function
|
||||||
|
this._actions = _.sortBy(this._actions, function(a) { return a.priority; });
|
||||||
|
},
|
||||||
|
|
||||||
|
executeLowest: function() {
|
||||||
|
return this._execute({
|
||||||
|
multipleAction: false
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
executeAll: function() {
|
||||||
|
return this._execute({
|
||||||
|
multipleActions: true
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
executeUpTo: function(maxLabel) {
|
||||||
|
return this._execute({
|
||||||
|
maxLabel: maxLabel,
|
||||||
|
multipleActions: true
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
clickExecute: function(evt, maxLabel) {
|
||||||
|
return this._execute({
|
||||||
|
maxLabel: maxLabel,
|
||||||
|
multipleActions: false,
|
||||||
|
evt: evt
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_stopClick: function(action, clickTarget) {
|
||||||
|
if (! _.isString(action.noClickEscapeOn))
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return $(clickTarget).closest(action.noClickEscapeOn).length > 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
_execute: function(options) {
|
||||||
|
var maxLabel = options.maxLabel;
|
||||||
|
var evt = options.evt || {};
|
||||||
|
var multipleActions = options.multipleActions;
|
||||||
|
|
||||||
|
var maxPriority, currentAction;
|
||||||
|
var executedAtLeastOne = false;
|
||||||
|
if (! maxLabel)
|
||||||
|
maxPriority = Infinity;
|
||||||
|
else
|
||||||
|
maxPriority = this.hierarchy.indexOf(maxLabel);
|
||||||
|
|
||||||
|
for (var i = 0; i < this._actions.length; i++) {
|
||||||
|
currentAction = this._actions[i];
|
||||||
|
if (currentAction.priority > maxPriority)
|
||||||
|
return executedAtLeastOne;
|
||||||
|
|
||||||
|
if (evt.type === 'click' && this._stopClick(currentAction, evt.target))
|
||||||
|
return executedAtLeastOne;
|
||||||
|
|
||||||
|
if (currentAction.condition()) {
|
||||||
|
currentAction.action(evt);
|
||||||
|
executedAtLeastOne = true;
|
||||||
|
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() {
|
||||||
|
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) {
|
||||||
|
if (evt.which === 1 && $(evt.target).closest('a,button').length === 0) {
|
||||||
|
EscapeActions.clickExecute(evt, 'detailsPane');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -33,72 +33,3 @@ Mousetrap.bind(['down', 'up'], function(evt, key) {
|
||||||
Utils.goCardId(nextCardId);
|
Utils.goCardId(nextCardId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Pressing `Escape` should close the last opened “element” and only the last
|
|
||||||
// one. Components can register themselves using a label a condition, and an
|
|
||||||
// action. This is used by Popup or inlinedForm for instance. When we press
|
|
||||||
// escape we execute the action which have a condition is valid and his the the
|
|
||||||
// highest in the label hierarchy.
|
|
||||||
EscapeActions = {
|
|
||||||
_actions: [],
|
|
||||||
|
|
||||||
// Executed in order
|
|
||||||
hierarchy: [
|
|
||||||
'textcomplete',
|
|
||||||
'popup',
|
|
||||||
'inlinedForm',
|
|
||||||
'multiselection-disable',
|
|
||||||
'sidebarView',
|
|
||||||
'detailsPane',
|
|
||||||
'multiselection-reset'
|
|
||||||
],
|
|
||||||
|
|
||||||
register: function(label, action, condition) {
|
|
||||||
if (_.isUndefined(condition))
|
|
||||||
condition = function() { return true; };
|
|
||||||
|
|
||||||
// XXX Rewrite this with ES6: .push({ priority, condition, action })
|
|
||||||
var priority = this.hierarchy.indexOf(label);
|
|
||||||
if (priority === -1) {
|
|
||||||
throw Error('You must define the label in the EscapeActions hierarchy');
|
|
||||||
}
|
|
||||||
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(label) {
|
|
||||||
var maxPriority, currentAction;
|
|
||||||
if (! label)
|
|
||||||
maxPriority = Infinity;
|
|
||||||
else
|
|
||||||
maxPriority = this.hierarchy.indexOf(label);
|
|
||||||
|
|
||||||
for (var i = 0; i < this._actions.length; i++) {
|
|
||||||
currentAction = this._actions[i];
|
|
||||||
if (currentAction.priority > maxPriority)
|
|
||||||
return;
|
|
||||||
if (!! currentAction.condition())
|
|
||||||
currentAction.action();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
executeAll: function() {
|
|
||||||
return this.executeLowerThan();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Mousetrap.bind('esc', function() {
|
|
||||||
EscapeActions.executeLowest();
|
|
||||||
});
|
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ MultiSelection = {
|
||||||
|
|
||||||
activate: function() {
|
activate: function() {
|
||||||
if (! this.isActive()) {
|
if (! this.isActive()) {
|
||||||
EscapeActions.executeLowerThan('detailsPane');
|
EscapeActions.executeUpTo('detailsPane');
|
||||||
this._isActive.set(true);
|
this._isActive.set(true);
|
||||||
Sidebar.setView(this.sidebarView);
|
Sidebar.setView(this.sidebarView);
|
||||||
Tracker.flush();
|
Tracker.flush();
|
||||||
|
|
@ -91,6 +91,7 @@ MultiSelection = {
|
||||||
if (Sidebar && Sidebar.getView() === this.sidebarView) {
|
if (Sidebar && Sidebar.getView() === this.sidebarView) {
|
||||||
Sidebar.setView();
|
Sidebar.setView();
|
||||||
}
|
}
|
||||||
|
this.reset();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -149,11 +150,7 @@ MultiSelection = {
|
||||||
|
|
||||||
Blaze.registerHelper('MultiSelection', MultiSelection);
|
Blaze.registerHelper('MultiSelection', MultiSelection);
|
||||||
|
|
||||||
EscapeActions.register('multiselection-disable',
|
EscapeActions.register('multiselection',
|
||||||
function() { MultiSelection.disable(); },
|
function() { MultiSelection.disable(); },
|
||||||
function() { return MultiSelection.isActive(); }
|
function() { return MultiSelection.isActive(); }
|
||||||
);
|
);
|
||||||
|
|
||||||
EscapeActions.register('multiselection-reset',
|
|
||||||
function() { MultiSelection.reset(); }
|
|
||||||
);
|
|
||||||
|
|
|
||||||
|
|
@ -40,11 +40,8 @@ Popup = {
|
||||||
self._stack = [];
|
self._stack = [];
|
||||||
openerElement = evt.currentTarget;
|
openerElement = evt.currentTarget;
|
||||||
}
|
}
|
||||||
$(openerElement).addClass('is-active');
|
|
||||||
|
|
||||||
// We modify the event to prevent the popup being closed when the event
|
$(openerElement).addClass('is-active');
|
||||||
// bubble up to the document element.
|
|
||||||
evt.originalEvent.clickInPopup = true;
|
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
|
|
||||||
// We push our popup data to the stack. The top of the stack is always
|
// We push our popup data to the stack. The top of the stack is always
|
||||||
|
|
@ -201,19 +198,11 @@ Popup = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// We automatically close a potential opened popup on any left click on the
|
// We close a potential opened popup on any left click on the document, or go
|
||||||
// document. To avoid closing it unexpectedly we modify the bubbled event in
|
// one step back by pressing escape.
|
||||||
// case the click event happen in the popup or in a button that open a popup.
|
|
||||||
$(document).on('click', function(evt) {
|
|
||||||
if (evt.which === 1 && ! (evt.originalEvent &&
|
|
||||||
evt.originalEvent.clickInPopup)) {
|
|
||||||
Popup.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Press escape to go back, or close the popup.
|
|
||||||
var bindPopup = function(f) { return _.bind(f, Popup); };
|
|
||||||
EscapeActions.register('popup',
|
EscapeActions.register('popup',
|
||||||
bindPopup(Popup.back),
|
function(evt) { Popup[evt.type === 'click' ? 'close' : 'back'](); },
|
||||||
bindPopup(Popup.isOpen)
|
_.bind(Popup.isOpen, Popup), {
|
||||||
|
noClickEscapeOn: '.js-pop-over'
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -63,16 +63,12 @@ h3, h4, h5, h6
|
||||||
color: #aa8f09
|
color: #aa8f09
|
||||||
|
|
||||||
a
|
a
|
||||||
color: #444
|
color: inherit
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
text-decoration: none
|
text-decoration: none
|
||||||
|
|
||||||
&:hover
|
&.is-disabled,
|
||||||
color: #111
|
&.is-disabled:hover
|
||||||
|
|
||||||
&.disabled,
|
|
||||||
&.disabled:hover
|
|
||||||
color: #8c8c8c
|
|
||||||
cursor: default
|
cursor: default
|
||||||
text-decoration: none
|
text-decoration: none
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue