docs: function onContextMenu(cm, e) {
      if (signalDOMEvent(cm, e, "contextmenu")) return;
      var display = cm.display;
      if (eventInWidget(display, e) || contextMenuInGutter(cm, e)) return;
  
      var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
      if (!pos || presto) return; // Opera is difficult.
  
      // Reset the current text selection only if the click is done outside of the selection
      // and 'resetSelectionOnContextMenu' option is true.
      var reset = cm.options.resetSelectionOnContextMenu;
      if (reset && cm.doc.sel.contains(pos) == -1)
        operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll);
  
      var oldCSS = display.input.style.cssText;
      display.inputDiv.style.position = "absolute";
      display.input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
        "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " +
        (ie ? "rgba(255, 255, 255, .05)" : "transparent") +
        "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
      if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712)
      focusInput(cm);
      if (webkit) window.scrollTo(null, oldScrollY);
      resetInput(cm);
      // Adds "Select all" to context menu in FF
      if (!cm.somethingSelected()) display.input.value = display.prevInput = " ";
      display.contextMenuPending = true;
      display.selForContextMenu = cm.doc.sel;
      clearTimeout(display.detectingSelectAll);
  
      // Select-all will be greyed out if there's nothing to select, so
      // this adds a zero-width space so that we can later check whether
      // it got selected.
      function prepareSelectAllHack() {
        if (display.input.selectionStart != null) {
          var selected = cm.somethingSelected();
          var extval = display.input.value = "\u200b" + (selected ? display.input.value : "");
          display.prevInput = selected ? "" : "\u200b";
          display.input.selectionStart = 1; display.input.selectionEnd = extval.length;
          // Re-set this, in case some other handler touched the
          // selection in the meantime.
          display.selForContextMenu = cm.doc.sel;
        }
      }
      function rehide() {
        display.contextMenuPending = false;
        display.inputDiv.style.position = "relative";
        display.input.style.cssText = oldCSS;
        if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos);
        slowPoll(cm);
  
        // Try to detect the user choosing select-all
        if (display.input.selectionStart != null) {
          if (!ie || (ie && ie_version < 9)) prepareSelectAllHack();
          var i = 0, poll = function() {
            if (display.selForContextMenu == cm.doc.sel && display.input.selectionStart == 0)
              operation(cm, commands.selectAll)(cm);
            else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500);
            else resetInput(cm);
          };
          display.detectingSelectAll = setTimeout(poll, 200);
        }
      }
  
      if (ie && ie_version >= 9) prepareSelectAllHack();
      if (captureRightClick) {
        e_stop(e);
        var mouseup = function() {
          off(window, "mouseup", mouseup);
          setTimeout(rehide, 20);
        };
        on(window, "mouseup", mouseup);
      } else {
        setTimeout(rehide, 50);
      }
    }