<commit_before>import Component from 'ember-component';
import layout from '../templates/components/power-select';
import fallbackIfUndefined from '../utils/computed-fallback-if-undefined';
import { assign } from 'ember-platform';
import { assert } from 'ember-metal/utils';
import { isBlank } from 'ember-utils';
import { isEmberArray } from 'ember-array/utils';
import computed from 'ember-computed';
import get from 'ember-metal/get';
import set, { setProperties } from 'ember-metal/set';
import { scheduleOnce, debounce, cancel } from 'ember-runloop';
import { defaultMatcher, indexOfOption, optionAtIndex, filterOptions, countOptions } from '../utils/group-utils';

function concatWithProperty(strings, property) {
  if (property) { strings.push(property); }
  return strings.join(' ');
}

function defaultHighlighted(results, selected) {
  if (selected === undefined || indexOfOption(results, selected) === -1) {
    return advanceSelectableOption(results, selected, 1);
  }
  return selected;
}

function advanceSelectableOption(options, currentOption, step) {
  let resultsLength = countOptions(options);
  let startIndex = Math.min(Math.max(indexOfOption(options, currentOption) + step, 0), resultsLength - 1);
  let { disabled, option } = optionAtIndex(options, startIndex);
  while (option && disabled) {
    let next = optionAtIndex(options, startIndex += step);
    disabled = next.disabled;
    option = next.option;
  }
  return option;
}

function toPlainArray(collection) {
  return collection.toArray ? collection.toArray() : collection;
}

export default Component.extend({
  // HTML
  layout,
  tagName: '',

  // Options
  searchEnabled: fallbackIfUndefined(true),
  matchTriggerWidth: fallbackIfUndefined(true),
  matcher: fallbackIfUndefined(defaultMatcher),
  loadingMessage: fallbackIfUndefined('Loading options...'),
  noMatchesMessage: fallbackIfUndefined('No results found'),
  searchMessage: fallbackIfUndefined("Type to search"),
  closeOnSelect: fallbackIfUndefined(true),

  afterOptionsComponent: fallbackIfUndefined(null),
  beforeOptionsComponent: fallbackIfUndefined('power-select/before-options'),
  optionsComponent: fallbackIfUndefined('power-select/options'),
  selectedItemComponent: fallbackIfUndefined(null),
  triggerComponent: fallbackIfUndefined('power-select/trigger'),

  // Private state
  expirableSearchText: '',
  expirableSearchDebounceId: null,
  activeSearch: null,
  publicAPI: {
    options: [],              // Contains the resolved collection of options
    results: [],              // Contains the active set of results
    resultsCount: 0,          // Contains the number of results incuding those nested/disabled
    selected: undefined,      // Contains the resolved selected option
    highlighted: undefined,   // Contains the currently highlighted option (if any)
    searchText: '',           // Contains the text of the current search
    lastSearchedText: '',     // Contains the text of the last finished search
    loading: false,           // Truthy if there is a pending promise that will update the results
    isActive: false           // Truthy if the trigger is focused. Other subcomponents can mark it as active depending on other logic.
  },

  // Lifecycle hooks
  init() {
    this._super(...arguments);
    assert('{{power-select}} requires an `onchange` function', this.get('onchange') && typeof this.get('onchange') === 'function');
  },

  willDestroy() {
    this._super(...arguments);
    this.activeSearch = this.activeSelectedPromise = this.activeOptionsPromise = null;
    if (this.publicAPI.options && this.publicAPI.options.removeObserver) {
      this.publicAPI.options.removeObserver('[]', this, this._updateOptionsAndResults);
    }
    cancel(this.expirableSearchDebounceId);
  },

  // CPs
  selected: computed({
    get() { return null; },
    set(_, selected) {
      if (selected && selected.then) {
        this.activeSelectedPromise = selected;
        selected.then(selection => {
          if (this.activeSelectedPromise === selected) {
            this.updateSelection(selection);
          }
        });
      } else {
        scheduleOnce('actions', this, this.updateSelection, selected);
      }
      return selected;
    }
  }),

  options: computed({
    get() { return []; },
    set(_, options) {
      if (options && options.then) {
        set(this.publicAPI, 'loading', true);
        this.activeOptionsPromise = options;
        options.then(resolvedOptions => {
          if (this.activeOptionsPromise === options) {
            this.updateOptions(resolvedOptions);
          }
        }, () => {
          if (this.activeOptionsPromise === options) {
            set(this.publicAPI, 'loading', false);
          }
        });
      } else {
        scheduleOnce('actions', this, this.updateOptions, options);
      }
      return options;
    }
  }),

  optionMatcher: computed('searchField', 'matcher', function() {
    let { matcher, searchField } = this.getProperties('matcher', 'searchField');
    if (searchField && matcher === defaultMatcher) {
      return (option, text) => matcher(get(option, searchField), text);
    } else {
      return (option, text) => matcher(option, text);
    }
  }),
<commit_msg>prevent accidentally resetting results when options are opdate with no changes<commit_after>import Component from 'ember-component';
import layout from '../templates/components/power-select';
import fallbackIfUndefined from '../utils/computed-fallback-if-undefined';
import { assign } from 'ember-platform';
import { assert } from 'ember-metal/utils';
import { isBlank } from 'ember-utils';
import { isEmberArray } from 'ember-array/utils';
import computed from 'ember-computed';
import get from 'ember-metal/get';
import set, { setProperties } from 'ember-metal/set';
import { scheduleOnce, debounce, cancel } from 'ember-runloop';
import { defaultMatcher, indexOfOption, optionAtIndex, filterOptions, countOptions } from '../utils/group-utils';

function concatWithProperty(strings, property) {
  if (property) { strings.push(property); }
  return strings.join(' ');
}

function defaultHighlighted(results, selected) {
  if (selected === undefined || indexOfOption(results, selected) === -1) {
    return advanceSelectableOption(results, selected, 1);
  }
  return selected;
}

function advanceSelectableOption(options, currentOption, step) {
  let resultsLength = countOptions(options);
  let startIndex = Math.min(Math.max(indexOfOption(options, currentOption) + step, 0), resultsLength - 1);
  let { disabled, option } = optionAtIndex(options, startIndex);
  while (option && disabled) {
    let next = optionAtIndex(options, startIndex += step);
    disabled = next.disabled;
    option = next.option;
  }
  return option;
}

function toPlainArray(collection) {
  return collection.toArray ? collection.toArray() : collection;
}

export default Component.extend({
  // HTML
  layout,
  tagName: '',

  // Options
  searchEnabled: fallbackIfUndefined(true),
  matchTriggerWidth: fallbackIfUndefined(true),
  matcher: fallbackIfUndefined(defaultMatcher),
  loadingMessage: fallbackIfUndefined('Loading options...'),
  noMatchesMessage: fallbackIfUndefined('No results found'),
  searchMessage: fallbackIfUndefined("Type to search"),
  closeOnSelect: fallbackIfUndefined(true),

  afterOptionsComponent: fallbackIfUndefined(null),
  beforeOptionsComponent: fallbackIfUndefined('power-select/before-options'),
  optionsComponent: fallbackIfUndefined('power-select/options'),
  selectedItemComponent: fallbackIfUndefined(null),
  triggerComponent: fallbackIfUndefined('power-select/trigger'),

  // Private state
  expirableSearchText: '',
  expirableSearchDebounceId: null,
  activeSearch: null,
  publicAPI: {
    options: [],              // Contains the resolved collection of options
    results: [],              // Contains the active set of results
    resultsCount: 0,          // Contains the number of results incuding those nested/disabled
    selected: undefined,      // Contains the resolved selected option
    highlighted: undefined,   // Contains the currently highlighted option (if any)
    searchText: '',           // Contains the text of the current search
    lastSearchedText: '',     // Contains the text of the last finished search
    loading: false,           // Truthy if there is a pending promise that will update the results
    isActive: false           // Truthy if the trigger is focused. Other subcomponents can mark it as active depending on other logic.
  },

  // Lifecycle hooks
  init() {
    this._super(...arguments);
    assert('{{power-select}} requires an `onchange` function', this.get('onchange') && typeof this.get('onchange') === 'function');
  },

  willDestroy() {
    this._super(...arguments);
    this.activeSearch = this.activeSelectedPromise = this.activeOptionsPromise = null;
    if (this.publicAPI.options && this.publicAPI.options.removeObserver) {
      this.publicAPI.options.removeObserver('[]', this, this._updateOptionsAndResults);
    }
    cancel(this.expirableSearchDebounceId);
  },

  // CPs
  selected: computed({
    get() { return null; },
    set(_, selected) {
      if (selected && selected.then) {
        this.activeSelectedPromise = selected;
        selected.then(selection => {
          if (this.activeSelectedPromise === selected) {
            this.updateSelection(selection);
          }
        });
      } else {
        scheduleOnce('actions', this, this.updateSelection, selected);
      }
      return selected;
    }
  }),

  options: computed({
    get() { return []; },
    set(_, options, oldOptions) {
      if (options === oldOptions) {
        return options;
      }
      if (options && options.then) {
        set(this.publicAPI, 'loading', true);
        this.activeOptionsPromise = options;
        options.then(resolvedOptions => {
          if (this.activeOptionsPromise === options) {
            this.updateOptions(resolvedOptions);
          }
        }, () => {
          if (this.activeOptionsPromise === options) {
            set(this.publicAPI, 'loading', false);
          }
        });
      } else {
        scheduleOnce('actions', this, this.updateOptions, options);
      }
      return options;
    }
  }),

  optionMatcher: computed('searchField', 'matcher', function() {
    let { matcher, searchField } = this.getProperties('matcher', 'searchField');
    if (searchField && matcher === defaultMatcher) {
      return (option, text) => matcher(get(option, searchField), text);
    } else {
      return (option, text) => matcher(option, text);
    }
  }),

{'fraction_non_alphanumeric': 0.12296240459813436, 'fraction_numerical': 0.000942240648261566, 'mean_word_length': 3.493649449618967, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4869669', 'n_tokens_mistral': 2884, 'n_tokens_neox': 2845, 'n_words': 736}