| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 | // 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 = {  _nextclickPrevented: false,  _actions: [],  // Executed in order  hierarchy: [    'textcomplete',    'popup-back',    'popup-close',    'modalWindow',    'inlinedForm',    'detailsPane',    'multiselection',    'sidebarView',  ],  register(label, action, condition = () => true, options = {}) {    const priority = this.hierarchy.indexOf(label);    if (priority === -1) {      throw Error('You must define the label in the EscapeActions hierarchy');    }    let enabledOnClick = options.enabledOnClick;    if (_.isUndefined(enabledOnClick)) {      enabledOnClick = true;    }    let noClickEscapeOn = options.noClickEscapeOn;    this._actions = _.sortBy([...this._actions, {      priority,      condition,      action,      noClickEscapeOn,      enabledOnClick,    }], (action) => action.priority);  },  executeLowest() {    return this._execute({      multipleAction: false    });  },  executeAll() {    return this._execute({      multipleActions: true    });  },  executeUpTo(maxLabel) {    return this._execute({      maxLabel: maxLabel,      multipleActions: true    });  },  clickExecute(target, maxLabel) {    if (this._nextclickPrevented) {      this._nextclickPrevented = false;    } else {      return this._execute({        maxLabel: maxLabel,        multipleActions: false,        isClick: true,        clickTarget: target      });    }  },  preventNextClick() {    this._nextclickPrevented = true;  },  _stopClick(action, clickTarget) {    if (! _.isString(action.noClickEscapeOn))      return false;    else      return $(clickTarget).closest(action.noClickEscapeOn).length > 0;  },  _execute(options) {    const maxLabel = options.maxLabel;    const multipleActions = options.multipleActions;    const isClick = !! options.isClick;    const clickTarget = options.clickTarget;    let executedAtLeastOne = false;    let maxPriority;    if (! maxLabel)      maxPriority = Infinity;    else      maxPriority = this.hierarchy.indexOf(maxLabel);    for (let currentAction of this._actions) {      if (currentAction.priority > maxPriority)        return executedAtLeastOne;      if (isClick && this._stopClick(currentAction, clickTarget))        return executedAtLeastOne;      let isEnabled = currentAction.enabledOnClick || ! isClick;      if (isEnabled && currentAction.condition()) {        currentAction.action();        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-bindvar _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.button === 0 &&    $(evt.target).closest('a,button,.is-editable').length === 0) {    EscapeActions.clickExecute(evt.target, 'multiselection');  }});
 |