<commit_before><div class="btn-group dropdown dropdown-select {{isOpen ? 'open' : ''}}"
     style="display: inline-block;">
  <button class="btn btn-select dropdown-toggle" type="button"
          on-click="{{items.length ? 'toggleShow' : ''}}">
    {{#items}}
      {{#if .value === selected}}
        {{#icon}}
          <i class="fa {{icon}}"></i>
        {{/icon}}

        {{label}}
      {{/if}}
    {{else}}
      {{emptyText || '暂无数据'}}
    {{/items}}

    <span class="caret"></span>
  </button>

  {{#isOpen}}
  <ul class="dropdown-menu" style="display: block;min-width: inherit;max-height: 200px; overflow: auto;">
    {{#items:i}}
    <li class="{{.value === selected ? 'selected-dropdown-menu' : ''}}" on-click="select:{{i}}">
      <a tabindex="-1" href="javascript:;">
        {{#icon}}
        <i class="fa {{icon}}"></i>
        {{/icon}}
        {{label}}
      </a>
    </li>
    {{else}}
    <li class="">
      <a href="javascript:;">
        {{emptyText || '暂无数据'}}
      </a>
    </li>
    {{/items}}
  </ul>
  {{/isOpen}}
</div>

<script>
  /**
   * 使用方式
   * <dropdown items="{{items}}" selected="{{value}}" on-itemchange="selectChange" />
   * list = [{label: 'X', value: '1'}]
   */
  var $ = require('jquery')
  var Ractive = require('ractive')
  var _ = require('lodash')
  var MSG = {
    SET_VALUE_MANUALLY: '变更数据源后请主动更新value',
    EMPTY_DATA: '数据源items为空',
    INVALID_VALUE: '当前设置value未找到'
  }

  /**
   * 调整下拉框的位置，避免在底部被遮挡
   * 使用fixed，有些scroll的容器不好处理
   */
  function adjustPosition(node, btn, margin) {
    var offset = btn[0].getBoundingClientRect()
    var height = node.outerHeight()
    var docHeight = document.documentElement.clientHeight
    var btnHeight = btn.outerHeight()
    var goDown = docHeight - margin > offset.top + btnHeight + height

    node.css({
      position: 'fixed',
      left: offset.left + 'px',
      top: goDown ? (offset.top + btnHeight) + 'px' : (offset.top - height) + 'px'
    })
  }

  component.exports = {
    isolated: true,
    data: {
      isOpen: false
    },
    onrender: function () {
      var self = this

      /**
       * 监听数据源改变，其实只是做了数据监测
       * 检测value是否设置正确即可（需要调研方主动设置）
       */
      function onDataSourceChange(items) {
        if (Array.isArray(items) && items.length) {
          var value = self.get('selected')
          var index = _.findIndex(items, {
            value: value
          })

          if (index === -1) {
            console.warn(MSG.SET_VALUE_MANUALLY)
          }
        } else {
          console.warn(MSG.EMPTY_DATA)
        }
      }

      function onSelectedChange(value) {
        var context = _.find(self.get('items'), {value: value})
        if (!context) {
          console.warn(MSG.INVALID_VALUE)
          return
        }

        // 兼容老事件
        self.fire('changed', null, context.value, context)
        // 新的事件
        self.fire('itemchange', null, context.value, context)
      }

      self.on('toggleShow', function() {
        self.toggle('isOpen')

        var ul = $(this.find('ul'))
        var btn = $(this.find('button'))
        if (ul.length) {
          adjustPosition(ul, btn, self.get('offset') || 100)
        }
      })

      self.on('select', function(e) {
        self.set('isOpen', false)

        // 不要随便变更selected，如果修改为一个不一致的值会切断外部组件的双向绑定关系
        self.set('selected', e.context.value)
      })

      self.observe('items', onDataSourceChange)

      self.observe('selected', onSelectedChange)
    }
  }

</script>
<commit_msg>fix dropdown展开的bug（scroll的容器）<commit_after><div class="btn-group dropdown dropdown-select {{isOpen ? 'open' : ''}}"
     style="display: inline-block;">
  <button class="btn btn-select dropdown-toggle" type="button"
          on-click="{{items.length ? 'toggleShow' : ''}}">
    {{#items}}
      {{#if .value === selected}}
        {{#icon}}
          <i class="fa {{icon}}"></i>
        {{/icon}}

        {{label}}
      {{/if}}
    {{else}}
      {{emptyText || '暂无数据'}}
    {{/items}}

    <span class="caret"></span>
  </button>

  {{#isOpen}}
  <ul class="dropdown-menu" style="display: block;min-width: inherit;max-height: 200px; overflow: auto;">
    {{#items:i}}
    <li class="{{.value === selected ? 'selected-dropdown-menu' : ''}}" on-click="select:{{i}}">
      <a tabindex="-1" href="javascript:;">
        {{#icon}}
        <i class="fa {{icon}}"></i>
        {{/icon}}
        {{label}}
      </a>
    </li>
    {{else}}
    <li class="">
      <a href="javascript:;">
        {{emptyText || '暂无数据'}}
      </a>
    </li>
    {{/items}}
  </ul>
  {{/isOpen}}
</div>

<script>
  /**
   * 使用方式
   * <dropdown items="{{items}}" selected="{{value}}" on-itemchange="selectChange" />
   * list = [{label: 'X', value: '1'}]
   */
  var $ = require('jquery')
  var Ractive = require('ractive')
  var _ = require('lodash')
  var MSG = {
    SET_VALUE_MANUALLY: '变更数据源后请主动更新value',
    EMPTY_DATA: '数据源items为空',
    INVALID_VALUE: '当前设置value未找到'
  }

  /**
   * 调整下拉框的位置，避免在底部被遮挡
   * 使用fixed，有些scroll的容器不好处理
   */
  function adjustPosition(node, btn, margin) {
    var offset = btn[0].getBoundingClientRect()
    var height = node.outerHeight()
    var docHeight = document.documentElement.clientHeight
    var btnHeight = btn.outerHeight()
    var goDown = docHeight - margin > offset.top + btnHeight + height
    var width = node.width()

    node.css({
      position: 'fixed',
      width: width + 'px',
      left: offset.left + 'px',
      top: goDown ? (offset.top + btnHeight) + 'px' : (offset.top - height) + 'px'
    })
  }

  component.exports = {
    isolated: true,
    data: {
      isOpen: false
    },
    onrender: function () {
      var self = this

      /**
       * 监听数据源改变，其实只是做了数据监测
       * 检测value是否设置正确即可（需要调研方主动设置）
       */
      function onDataSourceChange(items) {
        if (Array.isArray(items) && items.length) {
          var value = self.get('selected')
          var index = _.findIndex(items, {
            value: value
          })

          if (index === -1) {
            console.warn(MSG.SET_VALUE_MANUALLY)
          }
        } else {
          console.warn(MSG.EMPTY_DATA)
        }
      }

      function onSelectedChange(value) {
        var context = _.find(self.get('items'), {value: value})
        if (!context) {
          console.warn(MSG.INVALID_VALUE)
          return
        }

        // 兼容老事件
        self.fire('changed', null, context.value, context)
        // 新的事件
        self.fire('itemchange', null, context.value, context)
      }

      self.on('toggleShow', function() {
        self.toggle('isOpen')

        var ul = $(this.find('ul'))
        var btn = $(this.find('button'))
        if (ul.length) {
          adjustPosition(ul, btn, self.get('offset') || 100)
        }
      })

      self.on('select', function(e) {
        self.set('isOpen', false)

        // 不要随便变更selected，如果修改为一个不一致的值会切断外部组件的双向绑定关系
        self.set('selected', e.context.value)
      })

      self.observe('items', onDataSourceChange)

      self.observe('selected', onSelectedChange)
    }
  }

</script>

{'fraction_non_alphanumeric': 0.17956349206349206, 'fraction_numerical': 0.002834467120181406, 'mean_word_length': 2.2209036969420355, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 51, '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': '3604486', 'n_tokens_mistral': 2523, 'n_tokens_neox': 2522, 'n_words': 441}