Viewing File: /home/ubuntu/code_review/phabricator/webroot/rsrc/js/application/herald/PathTypeahead.js

/**
 * @requires javelin-install
 *           javelin-typeahead
 *           javelin-dom
 *           javelin-request
 *           javelin-typeahead-ondemand-source
 *           javelin-util
 * @provides path-typeahead
 * @javelin
 */

JX.install('PathTypeahead', {
  construct : function(config) {
    this._repositoryTokenizer = config.repositoryTokenizer;
    this._hardpoint = config.hardpoint;
    this._input = config.path_input;
    this._completeURI = config.completeURI;
    this._validateURI = config.validateURI;
    this._errorDisplay = config.error_display;
    this._textInputValues = {};

    this._icons = config.icons;

    this._initializeDatasource();
    this._initializeTypeahead(this._input);
  },
  members : {
    _repositoryTokenizer : null,

    /*
     * DOM parent div "hardpoint" to be passed to the JX.Typeahead.
     */
    _hardpoint : null,
    /*
     * DOM element to display errors.
     */
    _errorDisplay : null,
    /*
     * URI to query for typeahead results, to be passed to the
     * TypeaheadOnDemandSource.
    */
    _completeURI : null,

    /*
     * Underlying JX.TypeaheadOnDemandSource instance
     */
    _datasource : null,

    /*
     * Underlying JX.Typeahead instance
     */
    _typeahead : null,

    /*
     * Underlying input
     */
    _input : null,

    /*
     * Whenever the user changes the typeahead value, we track the change
     * here, keyed by the selected repository ID. That way, we can restore
     * typed values if they change the repository choice and then change back.
     */
    _textInputValues : null,

    /*
     * Configurable endpoint for server-side path validation
     */
    _validateURI : null,

    /*
     * Keep the validation AJAX request so we don't send several.
     */
    _validationInflight : null,

    /*
     * Installs path-specific behaviors and then starts the underlying
     * typeahead.
     */
    start : function() {
      if (this._typeahead.getValue()) {
        var phid = this._getRepositoryPHID();
        if (phid) {
          this._textInputValues[phid] = this._typeahead.getValue();
        }
      }

      this._typeahead.listen(
        'change',
        JX.bind(this, function(value) {
          var phid = this._getRepositoryPHID();
          if (phid) {
            this._textInputValues[phid] = value;
          }

          this._validate();
        }));

      var repo_set_input = JX.bind(this, this._onrepochange);

      this._typeahead.listen('start', repo_set_input);

      this._repositoryTokenizer.listen('change', repo_set_input);

      this._typeahead.start();
      this._validate();
    },

    _onrepochange : function() {
      this._setPathInputBasedOnRepository(
        this._typeahead,
        this._textInputValues);

      this._datasource.setAuxiliaryData(
        {
          repositoryPHID: this._getRepositoryPHID()
        });

      // Since we've changed the repository, reset the results.
      this._datasource.resetResults();
    },

    _setPathInputBasedOnRepository : function(typeahead, lookup) {
      var phid = this._getRepositoryPHID();
      if (phid && lookup[phid]) {
        typeahead.setValue(lookup[phid]);
      } else {
        typeahead.setValue('/');
      }
    },

    _initializeDatasource : function() {
      this._datasource = new JX.TypeaheadOnDemandSource(this._completeURI);
      this._datasource.setNormalizer(this._datasourceNormalizer);
      this._datasource.setQueryDelay(40);
    },

    /*
     * Construct and initialize the Typeahead.
     * Must be called after initializing the datasource.
     */
    _initializeTypeahead : function(path_input) {
      this._typeahead = new JX.Typeahead(this._hardpoint, path_input);
      this._datasource.setMaximumResultCount(15);
      this._typeahead.setDatasource(this._datasource);
    },

    _datasourceNormalizer : function(str) {
      return ('' + str).replace(/[\/]+/g, '\/');
    },

    _getRepositoryPHID: function() {
      var tokens = this._repositoryTokenizer.getTokens();
      var keys = JX.keys(tokens);

      if (keys.length) {
        return keys[0];
      }

      return null;
    },

    _validate : function() {
      var repo_phid = this._getRepositoryPHID();
      if (!repo_phid) {
        return;
      }

      var input = this._input;
      var input_value = input.value;
      var error_display = this._errorDisplay;

      if (!input_value.length) {
        input.value = '/';
        input_value = '/';
      }

      if (this._validationInflight) {
        this._validationInflight.abort();
        this._validationInflight = null;
      }

      var validation_request = new JX.Request(
        this._validateURI,
        JX.bind(this, function(payload) {
          // Don't change validation display state if the input has been
          // changed since we started validation
          if (input.value !== input_value) {
            return;
          }

          if (payload.valid) {
            JX.DOM.setContent(error_display, JX.$H(this._icons.okay));
          } else {
            JX.DOM.setContent(error_display, JX.$H(this._icons.fail));
          }
        }));

      validation_request.listen('finally', function() {
        this._validationInflight = null;
      });

      validation_request.setData(
        {
          repositoryPHID : repo_phid,
          path : input_value
        });

      this._validationInflight = validation_request;
      JX.DOM.setContent(error_display, JX.$H(this._icons.test));
      validation_request.send();
    }
  }
});
Back to Directory File Manager