<commit_before><link rel="import" href="../polymer/polymer.html">
<link rel="import" href="io-menu-option.html">

<dom-module id="io-menu-group">
  <style>
    :host {
      overflow-y: scroll;
      overflow-x: hidden;
      max-height: 80%;
      display: none;
      position: absolute;
      top: 0;
      left: 0;
      background: rgba(255, 255, 255, 1);
      padding: 0.25em 0;
      border: 1px solid rgba(0, 0, 0, 0.125);
      border-top: none;
      border-left: none;
      border-radius: 0.2em;
      box-shadow: 0.2em 0.2em 0.1em rgba(0, 0, 0, 0.25),
        0.1em 0.1em 0.5em rgba(0, 0, 0, 0.5);
    }
    :host([opened]) {
      display: block;
    }
    input {
      width: calc(100% - 0.5em);
      padding: 0.25em;
      border: 1px solid rgba(0, 0, 0, 0.125);
      border-top: 1px solid rgba(0, 0, 0, 0.25);
      border-left: 1px solid rgba(0, 0, 0, 0.25);
      margin: 0 0.5em 0.25em 0.25em;
      box-sizing: border-box;
    }
    input:focus {
      outline: 0;
      border-color: rgba(63, 127, 255, 0.5);
      border-top: 1px solid rgba(63, 127, 255, 1.0);
      border-left: 1px solid rgba(63, 127, 255, 1.0);
    }
  </style>
  <template>
    <template is="dom-if" if="{{search}}">
      <input type="text" placeholder="[[placeholder]]" on-keydown="_onSearchKeyUp" on-focus="_closeSubmenus" />
    </template>
    <template is="dom-repeat" items="{{_filteredOptions}}">
      <io-menu-option
          options="{{item.options}}"
          label="{{item.label}}"
          info="{{item.info}}"
          icon="{{item.icon}}"
          action="{{item.action}}"
          button="{{item.button}}"
          value="{{item.value}}"
          disabled="{{item.disabled}}"
          tooltip="{{item.tooltip}}"
          help="{{item.help}}"
          type="{{item.type}}">
      </io-menu-option>
    </template>
  </template>
</dom-module>
<script>
(function() {
  var y, filteredOptions;

  var closeMenuGroups = function(menuGroup) {
    var menuOptions = menuGroup.querySelectorAll('io-menu-option');
    for (var i = 0; i < menuOptions.length; i++) {
      menuOptions[i].opened = false;
      // TOD: link opened attribute between optiona and submenu
      if (menuOptions[i].options && menuOptions[i].options._menuGroup) {
        closeMenuGroups(menuOptions[i].options._menuGroup);
        menuOptions[i].options._menuGroup.opened = false;
      } 
    }
  };

  Polymer({
    is: 'io-menu-group',
    properties: {
      opened: {
        type: Boolean,
        reflectToAttribute: true
      },
      x: {
        type: Number,
        observer: '_xChanged'
      },
      y: {
        type: Number,
        observer: '_yChanged'
      },
      options: {
        type: Array,
        observer: '_optionsChanged'
      },
      search: {
        type: Boolean
      },
      //
      _filteredOptions: {
        type: Array
      },
      _searchString: {
        type: String
      },
      placeholder: String
    },
    listeners: {
      'mouseenter': '_onMouseenter',
      'mouseout': '_onMouseout',
      'mousemove': '_onMousemove'
    },
    ready: function() {
      this._animate = this.animate.bind(this);
    },
    startAnimation: function() {
      this.playing = true;
      this.animate();
    },
    stopAnimation: function() {
      this.playing = false;
    },
    animate: function() {
      if (!this.playing) return;
      this._nudge();
      requestAnimationFrame(this._animate);
    },
    _onMouseenter: function(event) {
      if (event.target === this) {
        this.startAnimation();
      }
    },
    _onMousemove: function(event) {
      y = event.clientY;
    },
    _onMouseout: function(event) {
      // TODO: profile. Make efficient.
      var rect = this.getBoundingClientRect();
      if (event.clientX <= rect.left || event.clientX >= (rect.left + rect.width) ||
            event.clientY <= rect.top || event.clientY >= (rect.top + rect.height)) {
        this.stopAnimation();
      }
    },
    _nudge: function() {
      this.async(function() {
        // TODO: too many asyncs. Check for glitches.
        var rect = this.getBoundingClientRect();
        // nudge up
        var bottomDist = rect.bottom - window.innerHeight;
        if (bottomDist > 0) {
          this.y = window.innerHeight - rect.height;
        }
        // TODO: also scroll on key commands
        // nudge left
        var rightDist = rect.right - window.innerWidth;
        if (rightDist > 0) {
          if (this._parent) {
            var parentRect = this._parent.getBoundingClientRect();
            this.x = parentRect.left - rect.width;
          } else {
            this.x = window.innerWidth - rect.width;
          }
        }
      }.bind(this));
    },
    _filterOptions: function(options) {
      var filteredOptions = [];
      if (this._searchString && options.length) {
        options.forEach(function(option) {
          // TODO: use regex
          if ((option.action || option.value) && 
              option.label.toLowerCase().search(this._searchString.toLowerCase()) != -1) {
            filteredOptions.push(option);
          }
          if (option.options) {
            filteredOptions = filteredOptions.concat(this._filterOptions(option.options));
          }
        }.bind(this));
      }
      return filteredOptions;
    },
    _sortOptions: function(options) {
      return options.concat().sort(function(a, b) {
        if (a.label.toLowerCase() < b.label.toLowerCase()) {
          return -1;
        }
        if (a.label.toLowerCase() > b.label.toLowerCase()) {
          return 1;
        }
        return 0;
      });
    },
    _closeSubmenus: function() {
      closeMenuGroups(this);
    },
    _xChanged: function() {
      this.style.left = this.x + 'px';
      this.async(function() {
        this._nudge();
      }.bind(this));
    },
    _yChanged: function() {
      this.style.top = (this.y - 50) + 'px';
      this.async(function() {
        this._nudge();
      }.bind(this));
    },
    _optionsChanged: function() {
      this._filteredOptions = this.options;
    },
    _onSearchKeyUp: function(event) {
      event.stopPropagation();<commit_msg>Revert "Update io-menu-group.html"<commit_after><link rel="import" href="../polymer/polymer.html">
<link rel="import" href="io-menu-option.html">

<dom-module id="io-menu-group">
  <style>
    :host {
      display: none;
      position: absolute;
      top: 0;
      left: 0;
      background: rgba(255, 255, 255, 1);
      padding: 0.25em 0;
      border: 1px solid rgba(0, 0, 0, 0.125);
      border-top: none;
      border-left: none;
      border-radius: 0.2em;
      box-shadow: 0.2em 0.2em 0.1em rgba(0, 0, 0, 0.25),
        0.1em 0.1em 0.5em rgba(0, 0, 0, 0.5);
    }
    :host([opened]) {
      display: block;
    }
    input {
      width: calc(100% - 0.5em);
      padding: 0.25em;
      border: 1px solid rgba(0, 0, 0, 0.125);
      border-top: 1px solid rgba(0, 0, 0, 0.25);
      border-left: 1px solid rgba(0, 0, 0, 0.25);
      margin: 0 0.5em 0.25em 0.25em;
      box-sizing: border-box;
    }
    input:focus {
      outline: 0;
      border-color: rgba(63, 127, 255, 0.5);
      border-top: 1px solid rgba(63, 127, 255, 1.0);
      border-left: 1px solid rgba(63, 127, 255, 1.0);
    }
  </style>
  <template>
    <template is="dom-if" if="{{search}}">
      <input type="text" placeholder="[[placeholder]]" on-keydown="_onSearchKeyUp" on-focus="_closeSubmenus" />
    </template>
    <template is="dom-repeat" items="{{_filteredOptions}}">
      <io-menu-option
          options="{{item.options}}"
          label="{{item.label}}"
          info="{{item.info}}"
          icon="{{item.icon}}"
          action="{{item.action}}"
          button="{{item.button}}"
          value="{{item.value}}"
          disabled="{{item.disabled}}"
          tooltip="{{item.tooltip}}"
          help="{{item.help}}"
          type="{{item.type}}">
      </io-menu-option>
    </template>
  </template>
</dom-module>
<script>
(function() {
  var y, filteredOptions;

  var closeMenuGroups = function(menuGroup) {
    var menuOptions = menuGroup.querySelectorAll('io-menu-option');
    for (var i = 0; i < menuOptions.length; i++) {
      menuOptions[i].opened = false;
      // TOD: link opened attribute between optiona and submenu
      if (menuOptions[i].options && menuOptions[i].options._menuGroup) {
        closeMenuGroups(menuOptions[i].options._menuGroup);
        menuOptions[i].options._menuGroup.opened = false;
      } 
    }
  };

  Polymer({
    is: 'io-menu-group',
    properties: {
      opened: {
        type: Boolean,
        reflectToAttribute: true
      },
      x: {
        type: Number,
        observer: '_xChanged'
      },
      y: {
        type: Number,
        observer: '_yChanged'
      },
      options: {
        type: Array,
        observer: '_optionsChanged'
      },
      search: {
        type: Boolean
      },
      //
      _filteredOptions: {
        type: Array
      },
      _searchString: {
        type: String
      },
      placeholder: String
    },
    listeners: {
      'mouseenter': '_onMouseenter',
      'mouseout': '_onMouseout',
      'mousemove': '_onMousemove'
    },
    ready: function() {
      this._animate = this.animate.bind(this);
    },
    startAnimation: function() {
      this.playing = true;
      this.animate();
    },
    stopAnimation: function() {
      this.playing = false;
    },
    animate: function() {
      if (!this.playing) return;
      this._nudge();
      requestAnimationFrame(this._animate);
    },
    _onMouseenter: function(event) {
      if (event.target === this) {
        this.startAnimation();
      }
    },
    _onMousemove: function(event) {
      y = event.clientY;
    },
    _onMouseout: function(event) {
      // TODO: profile. Make efficient.
      var rect = this.getBoundingClientRect();
      if (event.clientX <= rect.left || event.clientX >= (rect.left + rect.width) ||
            event.clientY <= rect.top || event.clientY >= (rect.top + rect.height)) {
        this.stopAnimation();
      }
    },
    _nudge: function() {
      this.async(function() {
        // TODO: too many asyncs. Check for glitches.
        var rect = this.getBoundingClientRect();
        // nudge up
        var bottomDist = rect.bottom - window.innerHeight;
        if (bottomDist > 0) {
          this.y = window.innerHeight - rect.height;
        }
        // SCROLL IF CANT FIT WINDOW
        // if (y < 100 && rect.top < 0) {
        //   var scrollSpeed = (100 - y) / 5000;
        //   var overflow = rect.top;
        //   this.y = this.y - Math.ceil(overflow * scrollSpeed) + 1;
        // } else if (y > window.innerHeight - 100 && rect.bottom > window.innerHeight) {
        //   var scrollSpeed = (100 - (window.innerHeight - y)) / 5000;
        //   var overflow = (rect.bottom - window.innerHeight);
        //   this.y = this.y - Math.ceil(overflow * scrollSpeed) - 1;
        // }
        // TODO: also scroll on key commands
        // nudge left
        var rightDist = rect.right - window.innerWidth;
        if (rightDist > 0) {
          if (this._parent) {
            var parentRect = this._parent.getBoundingClientRect();
            this.x = parentRect.left - rect.width;
          } else {
            this.x = window.innerWidth - rect.width;
          }
        }
      }.bind(this));
    },
    _filterOptions: function(options) {
      var filteredOptions = [];
      if (this._searchString && options.length) {
        options.forEach(function(option) {
          // TODO: use regex
          if ((option.action || option.value) && 
              option.label.toLowerCase().search(this._searchString.toLowerCase()) != -1) {
            filteredOptions.push(option);
          }
          if (option.options) {
            filteredOptions = filteredOptions.concat(this._filterOptions(option.options));
          }
        }.bind(this));
      }
      return filteredOptions;
    },
    _sortOptions: function(options) {
      return options.concat().sort(function(a, b) {
        if (a.label.toLowerCase() < b.label.toLowerCase()) {
          return -1;
        }
        if (a.label.toLowerCase() > b.label.toLowerCase()) {
          return 1;
        }
        return 0;
      });
    },
    _closeSubmenus: function() {
      closeMenuGroups(this);
    },
    _xChanged: function() {
      this.style.left = this.x + 'px';
      this.async(function() {
        this._nudge();
      }.bind(this));
    },
    _yChanged: function() {
      this.style.top = this.y + 'px';
      this.async(function() {
        this._nudge();
      }.bind(this));
    },
    _optionsChanged: function() {
      this._filteredOptions = this.options;
    },
    _onSearchKeyUp: function(event) {
      event.stopPropagation();
{'fraction_non_alphanumeric': 0.15378006872852235, 'fraction_numerical': 0.02210246797875664, 'mean_word_length': 1.9696196660482375, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 47, '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': '3696991', 'n_tokens_mistral': 4277, 'n_tokens_neox': 4009, 'n_words': 833}