| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 | // 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;    }    const noClickEscapeOn = options.noClickEscapeOn;    this._actions = _.sortBy(      [        ...this._actions,        {          priority,          condition,          action,          noClickEscapeOn,          enabledOnClick,        },      ],      action => action.priority,    );  },  executeLowest() {    return this._execute({      multipleActions: false,    });  },  executeAll() {    return this._execute({      multipleActions: true,    });  },  executeUpTo(maxLabel) {    return this._execute({      maxLabel,      multipleActions: true,    });  },  clickExecute(target, maxLabel) {    if (this._nextclickPrevented) {      this._nextclickPrevented = false;      return false;    } else {      return this._execute({        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 = Boolean(options.isClick);    const clickTarget = options.clickTarget;    let executedAtLeastOne = false;    let maxPriority;    if (!maxLabel) maxPriority = Infinity;    else maxPriority = this.hierarchy.indexOf(maxLabel);    for (const currentAction of this._actions) {      if (currentAction.priority > maxPriority) return executedAtLeastOne;      if (isClick && this._stopClick(currentAction, clickTarget))        return executedAtLeastOne;      const isEnabled = currentAction.enabledOnClick || !isClick;      if (isEnabled && currentAction.condition()) {        currentAction.action();        executedAtLeastOne = true;        if (!multipleActions) return executedAtLeastOne;      }    }    return executedAtLeastOne;  },};// Pressing escape to execute one escape action. We use `bindGloabal` vecause// the shortcut sould work on textarea and inputs as well.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', evt => {  if (    evt.button === 0 &&    $(evt.target).closest('a,button,.is-editable').length === 0  ) {    EscapeActions.clickExecute(evt.target, 'multiselection');  }});$(document).on('click', 'a[href=\\#]', evt => {  evt.preventDefault();});
 |