コード例 #1
0
ファイル: inputter.js プロジェクト: edc/gcli
/**
 * A wrapper to take care of the functions concerning an input element
 */
function Inputter(options) {
  if (!inputterCssImported && !options.preStyled) {
    dom.importCssString(inputterCss, this.doc);
    inputterCssImported = true;
  }

  this.requ = options.requisition;

  // Suss out where the input element is
  this.element = options.inputElement || 'gcliInput';
  if (typeof this.element === 'string') {
    this.doc = options.document || document;
    var name = this.element;
    this.element = this.doc.getElementById(name);
    if (!this.element) {
      throw new Error('No element with id=' + name + '.');
    }
  }
  else {
    // Assume we've been passed in the correct node
    this.doc = this.element.ownerDocument;
  }

  this.element.spellcheck = false;

  // Used to distinguish focus from TAB in CLI. See onKeyUp()
  this.lastTabDownAt = 0;

  // Ensure that TAB/UP/DOWN isn't handled by the browser
  event.addListener(this.element, 'keydown', this.onKeyDown.bind(this));
  event.addListener(this.element, 'keyup', this.onKeyUp.bind(this));

  // Use our document if no other is supplied
  options.document = options.document || this.doc;

  if (options.completer == null) {
    options.completer = new Completer(options);
  }
  else if (typeof options.completer === 'function') {
    options.completer = new options.completer(options);
  }
  this.completer = options.completer;
  this.completer.decorate(this);

  // Use the provided history object, or instantiate our own.
  this.history = options.history = options.history || new History(options);
  this._scrollingThroughHistory = false;

  // cursor position affects hint severity.
  event.addListener(this.element, 'mouseup', function(ev) {
    this.completer.update(this.getInputState());
  }.bind(this));

  this.requ.inputChange.add(this.onInputChange, this);
}
コード例 #2
0
ファイル: inputter.js プロジェクト: edc/gcli
Completer.prototype.decorate = function(inputter) {
  this.inputter = inputter;
  this.input = inputter.element;

  // If we were told which element to use, then assume it is already
  // correctly positioned. Otherwise insert it alongside the input element
  if (this.elementCreated) {
    this.inputter.appendAfter(this.element);

    Completer.copyStyles.forEach(function(style) {
      this.element.style[style] = dom.computedStyle(this.input, style);
    }, this);

    // If there is a separate backgroundElement, then we make the element
    // transparent, otherwise it inherits the color of the input node
    // It's not clear why backgroundColor doesn't work when used from
    // computedStyle, but it doesn't. Patches welcome!
    this.element.style.backgroundColor = (this.backgroundElement != this.element) ?
        'transparent' :
        this.input.style.backgroundColor;
    this.input.style.backgroundColor = 'transparent';

    // Make room for the prompt
    this.input.style.paddingLeft = '20px';

    var resizer = this.resizer.bind(this);
    event.addListener(this.doc.defaultView, 'resize', resizer);
    resizer();
  }
};
コード例 #3
0
ファイル: inputter.js プロジェクト: edc/gcli
Inputter.prototype.onKeyDown = function(ev) {
  if (ev.keyCode === KeyEvent.DOM_VK_UP || ev.keyCode === KeyEvent.DOM_VK_DOWN) {
    event.stopEvent(ev);
  }
  if (ev.keyCode === KeyEvent.DOM_VK_TAB) {
    this.lastTabDownAt = 0;
    if (!ev.shiftKey) {
      event.stopEvent(ev);
      // Record the timestamp of this TAB down so onKeyUp can distinguish
      // focus from TAB in the CLI.
      this.lastTabDownAt = ev.timeStamp;
    }
    if (ev.metaKey || ev.altKey || ev.crtlKey) {
      if (this.doc.commandDispatcher) {
        this.doc.commandDispatcher.advanceFocus();
      }
      else {
        this.element.blur();
      }
    }
  }
};
コード例 #4
0
ファイル: popup.js プロジェクト: edc/gcli
/**
 * Popup is responsible for containing the popup hints that are displayed
 * above the command line.
 * Some implementations of GCLI require an element to be visible whenever the
 * GCLI has the focus.
 * This can be somewhat tricky because the definition of 'has the focus' is
 * one where a group of elements could have the focus.
 */
function Popup(options) {
  this.doc = options.document || document;

  this.inputter = options.inputter;
  this.children = options.children;
  this.style = options.style || Popup.style.doubleColumnFirstFixedLeft;

  // Focus Management.
  this.outputHideTimeout;
  this.preventBlurTimeout;
  this.preventBlurInputFocus;

  this.showOutput = this.showOutput.bind(this);
  this.hideOutput = this.hideOutput.bind(this);
  this.preventBlur = this.preventBlur.bind(this);
  this.resizer = this.resizer.bind(this);
  this.autoHide = false;

  this.element = options.popupElement || 'gcliOutput';
  if (typeof this.element === 'string') {
    var name = this.element;
    this.element = this.doc.getElementById(name);

    if (!this.element) {
      this.autoHide = true;
      this.element = dom.createElement('div', null, this.doc);
      this.element.id = name;
      if (this.inputter) {
        this.inputter.appendAfter(this.element);
      }

      this.element.style.position = 'absolute';
      this.element.style.zIndex = '999';
    }

    // this.element.style.overflow = 'auto';
  }

  // Allow options to override the autoHide option
  if (options.autoHide != null) {
    this.autoHide = options.autoHide;
  }

  this.children.forEach(function(child) {
    if (child.element) {
      this.element.appendChild(child.element);
    }
  }, this);

  this.win = this.element.ownerDocument.defaultView;

  event.addListener(this.win, 'resize', this.resizer);
  this.resizer();

  // Attach events to this.output to check if any DOM node inside of the
  // output node is focused/clicked on. This kind of events prevent the
  // output node from getting hidden.
  // If any of the DOM nodes inside of output get blurred, hide the
  // output node. If the focus is set to a different node in output,
  // the focus event will prevent closing the output.
  // The third argument to addEventListener MUST be set to true!
  this.element.addEventListener('click', this.preventBlur, true);
  // Commenting this out is a quick workaround for bug 653140 but it probably
  // breaks the popup mechanism, however for now selection is more important
  // that popup.
  // this.element.addEventListener('mousedown', this.preventBlur, true);
  this.element.addEventListener('focus', this.preventBlur, true);
  this.element.addEventListener('blur', this.hideOutput,  true);

  if (this.inputter) {
    this.inputter.sendFocusEventsToPopup(this);
  }

  if (this.style === Popup.style.doubleColumnFirstFixedLeft) {
    var left = this.children[0].element;
    left.style.position = 'absolute';
    left.style.bottom = '0';
    left.style.left = '0';
    left.style.maxWidth = '300px';

    var right = this.children[1].element;
    right.style.position = 'absolute';
    right.style.bottom = '0';
    right.style.left = '320px';
    right.style.right = '0';

    // What height should the output panel be, by default?
    this._outputHeight = options.outputHeight || 300;
  }
  else if (this.style === Popup.style.singleColumnVariable) {
    this._outputHeight = -1;
  }
  else {
    throw new Error('Invalid style setting');
  }

  // Adjust to the current outputHeight only when we created the output
  if (this.autoHide) {
    this.setOutputHeight(this._outputHeight);
  }

  // Hide the cli's output at after startup.
  this.hideOutput();
}
コード例 #5
0
ファイル: inputter.js プロジェクト: edc/gcli
Inputter.prototype.sendFocusEventsToPopup = function(popup) {
  event.addListener(this.element, 'focus', popup.showOutput);
  event.addListener(this.element, 'blur', popup.hideOutput);
};