<commit_before><!DOCTYPE html>
<!--
Copyright (c) 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->

<link rel="import" href="/tracing/base/base.html">

<!--
@fileoverview A view that allows the user to control which single tab is
displayed.

We follow a fairly standard web convention of backing our tabs with hidden radio
buttons but visible radio button labels (the tabs themselves) which toggle the
input element when clicked. Using hidden radio buttons makes sense, as both tabs
and radio buttons are input elements that allow user selection through clicking
and limit users to having one option selected at a time.
-->
<dom-module id='tr-ui-b-tab-view'>
  <template>
    <style>
      :host {
        display: flex;
        flex-direction: column;
      }

      #selection_description, #tabs {
        font-size: 12px;
      }

      #selection_description {
        display: inline-block;
        font-weight: bold;
        margin: 9px 0px 4px 20px;
      }

      #tabs {
        flex: 0 0 auto;
        border-top: 1px solid #8e8e8e;
        border-bottom: 1px solid #8e8e8e;
        background-color: #ececec;
        overflow: hidden;
        margin: 0;
      }

      #tabs input[type=radio] {
        display: none;
      }

      #tabs tab label {
        cursor: pointer;
        display: inline-block;
        border: 1px solid #ececec;
        margin: 5px 0px 0px 15px;
        padding: 3px 10px 3px 10px;
      }

      #tabs tab label span {
        font-weight: bold;
      }

      #tabs input[type=radio]:checked ~ label {
        background-color: white;
        border: 1px solid #8e8e8e;
        border-bottom: 1px solid white;
      }

      #subView {
        flex: 1 1 auto;
        overflow: auto;
      }
    </style>
    <div id='tabs' hidden="[[tabsHidden]]">
      <label id=selection_description>[[label_]]</label>
      <template is=dom-repeat items=[[subViews_]]>
        <tab>
          <input type=radio name=tabs id$=[[computeRadioId_(item)]]
              on-change='onTabChanged_'
              checked$='[[isChecked_(item)]]' />
          <label for$=[[computeRadioId_(item)]]>
            <template is=dom-if if=[[item.tabIcon]]>
              <span style$='[[item.tabIcon.style]]'>[[item.tabIcon.text]]</span>
            </template>
            [[item.tabLabel]]
          </label>
        </tab>
      </template>
    </div>
    <div id='subView'></div>
    <content>
    </content>
  </template>
</dom-module>
<script>
'use strict';

Polymer({
  is: 'tr-ui-b-tab-view',

  properties: {
    label_: {
      type: String,
      value: () => ''
    },
    selectedSubView_: Object,
    subViews_: {
      type: Array,
      value: () => []
    },
    tabsHidden: {
      type: Boolean,
      value: false
    }
  },

  set label(newLabel) {
    this.set('label_', newLabel);
  },

  get tabs() {
    return this.get('subViews_');
  },

  get selectedSubView() {
    return this.selectedSubView_;
  },

  set selectedSubView(subView) {
    if (subView === this.selectedSubView_)
      return;

    if (this.selectedSubView_)
      Polymer.dom(this.$.subView).removeChild(this.selectedSubView_);

    this.set('selectedSubView_', subView);

    if (subView)
      Polymer.dom(this.$.subView).appendChild(subView);

    this.fire('selected-tab-change');
  },

  clearSubViews: function() {
    this.splice('subViews_', 0, this.subViews_.length);
    this.selectedSubView = undefined;
  },

  addSubView: function(subView) {
    if (!this.selectedSubView_)
      this.selectedSubView = subView;

    this.push('subViews_', subView);
  },

  resetSubViews: function(subViews) {
    this.splice('subViews_', 0, this.subViews_.length);
    if (subViews.length) {
      for (var subView of subViews)
        this.push('subViews_', subView);
      this.selectedSubView = subViews[0];
    }
    else {
      this.selectedSubView = undefined;
    }
  },

  onTabChanged_: function(event) {
    this.selectedSubView = event.model.item;
  },

  isChecked_: function(subView) {
    return this.selectedSubView_ === subView;
  },

  computeRadioId_: function(subView) {
    // We can't just use the tagName as the radio's ID because there are
    // instances where a single subview type can handle multiple event types,
    // and thus might be present multiple times in a single tab view. In order
    // to avoid the case where we might have two tabs with the same ID, we
    // uniquify this ID by appending the tab's label with all spaces replaced
    // by dashes (because spaces aren't allowed in HTML IDs).
    return subView.tagName + '-' + subView.tabLabel.replace(/ /g, '-');
  }
});<commit_msg>[tracing] Add keyboard navigation to the tab view<commit_after><!DOCTYPE html>
<!--
Copyright (c) 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->

<link rel="import" href="/tracing/base/base.html">

<!--
@fileoverview A view that allows the user to control which single tab is
displayed.

We follow a fairly standard web convention of backing our tabs with hidden radio
buttons but visible radio button labels (the tabs themselves) which toggle the
input element when clicked. Using hidden radio buttons makes sense, as both tabs
and radio buttons are input elements that allow user selection through clicking
and limit users to having one option selected at a time.
-->
<dom-module id='tr-ui-b-tab-view'>
  <template>
    <style>
      :host {
        display: flex;
        flex-direction: column;
      }

      #selection_description, #tabs {
        font-size: 12px;
      }

      #selection_description {
        display: inline-block;
        font-weight: bold;
        margin: 9px 0px 4px 20px;
      }

      #tabs {
        flex: 0 0 auto;
        border-top: 1px solid #8e8e8e;
        border-bottom: 1px solid #8e8e8e;
        background-color: #ececec;
        overflow: hidden;
        margin: 0;
      }

      #tabs input[type=radio] {
        display: none;
      }

      #tabs tab label {
        cursor: pointer;
        display: inline-block;
        border: 1px solid #ececec;
        margin: 5px 0px 0px 15px;
        padding: 3px 10px 3px 10px;
      }

      #tabs tab label span {
        font-weight: bold;
      }

      #tabs:focus input[type=radio]:checked ~ label {
        outline: dotted 1px #8e8e8e;
        outline-offset: -2px;
      }

      #tabs input[type=radio]:checked ~ label {
        background-color: white;
        border: 1px solid #8e8e8e;
        border-bottom: 1px solid white;
      }

      #subView {
        flex: 1 1 auto;
        overflow: auto;
      }
    </style>
    <div id='tabs' hidden="[[tabsHidden]]">
      <label id=selection_description>[[label_]]</label>
      <template is=dom-repeat items=[[subViews_]]>
        <tab>
          <input type=radio name=tabs id$=[[computeRadioId_(item)]]
              on-change='onTabChanged_'
              checked$='[[isChecked_(item)]]' />
          <label for$=[[computeRadioId_(item)]]>
            <template is=dom-if if=[[item.tabIcon]]>
              <span style$='[[item.tabIcon.style]]'>[[item.tabIcon.text]]</span>
            </template>
            [[item.tabLabel]]
          </label>
        </tab>
      </template>
    </div>
    <div id='subView'></div>
    <content>
    </content>
  </template>
</dom-module>
<script>
'use strict';

Polymer({
  is: 'tr-ui-b-tab-view',

  properties: {
    label_: {
      type: String,
      value: () => ''
    },
    selectedSubView_: Object,
    subViews_: {
      type: Array,
      value: () => []
    },
    tabsHidden: {
      type: Boolean,
      value: false,
      observer: 'tabsHiddenChanged_'
    }
  },

  ready: function() {
    this.$.tabs.addEventListener('keydown', this.onKeyDown_.bind(this), true);
    this.updateFocusability_();
  },

  set label(newLabel) {
    this.set('label_', newLabel);
  },

  get tabs() {
    return this.get('subViews_');
  },

  get selectedSubView() {
    return this.selectedSubView_;
  },

  set selectedSubView(subView) {
    if (subView === this.selectedSubView_)
      return;

    if (this.selectedSubView_)
      Polymer.dom(this.$.subView).removeChild(this.selectedSubView_);

    this.set('selectedSubView_', subView);

    if (subView)
      Polymer.dom(this.$.subView).appendChild(subView);

    this.fire('selected-tab-change');
  },

  clearSubViews: function() {
    this.splice('subViews_', 0, this.subViews_.length);
    this.selectedSubView = undefined;
    this.updateFocusability_();
  },

  addSubView: function(subView) {
    if (!this.selectedSubView_)
      this.selectedSubView = subView;

    this.push('subViews_', subView);
    this.updateFocusability_();
  },

  resetSubViews: function(subViews) {
    this.splice('subViews_', 0, this.subViews_.length);
    if (subViews.length) {
      for (var subView of subViews)
        this.push('subViews_', subView);
      this.selectedSubView = subViews[0];
    }
    else {
      this.selectedSubView = undefined;
    }
    this.updateFocusability_();
  },

  onTabChanged_: function(event) {
    this.selectedSubView = event.model.item;
  },

  isChecked_: function(subView) {
    return this.selectedSubView_ === subView;
  },

  tabsHiddenChanged_: function() {
    this.updateFocusability_();
  },

  onKeyDown_: function(e) {
    if (this.tabsHidden || !this.selectedSubView_)
      return;

    var currentIndex = this.subViews_.indexOf(this.selectedSubView_);
    var nextIndex = undefined;
    switch (e.keyCode) {
      // Arrow left.
      case 37:
        nextIndex = currentIndex - 1;
        break;
      // Arrow right.
      case 39:
        nextIndex = currentIndex + 1;
        break;
      default:
        return;
    }

    var tab = Polymer.dom(this.root).querySelectorAll('#tabs tab')[nextIndex];
    if (tab)
      tab.querySelector('input').click();

    e.stopPropagation();
    e.preventDefault();
  },

  shouldBeFocusable_: function() {
    return !this.tabsHidden && this.subViews_.length > 0;
  },

  updateFocusability_: function() {
    if (this.shouldBeFocusable_()) {
      Polymer.dom(this.$.tabs).setAttribute('tabindex', 0);
    } else {
      Polymer.dom(this.$.tabs).removeAttribute('tabindex');
    }
  },

  computeRadioId_: function(subView) {
    // We can't just use the tagName as the radio's ID because there are
    // instances where a single subview type can handle multiple event types,
    // and thus might be present multiple times in a single tab view. In order
    // to avoid the case where we might have two tabs with the same ID, we
    // uniquify this ID by appending the tab's label with all spaces replaced
    // by dashes (because spaces aren't allowed in HTML IDs).
    return subView.tagName + '-' + subView.tabLabel.replace(/ /g, '-');
  }
});
{'fraction_non_alphanumeric': 0.12607502287282707, 'fraction_numerical': 0.009240622140896614, 'mean_word_length': 2.4812101910828024, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 68, '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': '2749399', 'n_tokens_mistral': 3520, 'n_tokens_neox': 3324, 'n_words': 903}