summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js.es6
blob: 2955bda1a36261cd4f645a701ae7b47ef155a17d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/**
 * Linked Tabs
 *
 * Handles persisting and restores the current tab selection and content.
 * Reusable component for static content.
 *
 * ### Example Markup
 *
 *  <ul class="nav-links tab-links">
 *    <li class="active">
 *      <a data-action="tab1" data-target="#tab1" data-toggle="tab" href="/path/tab1">
 *        Tab 1
 *      </a>
 *    </li>
 *    <li class="groups-tab">
 *      <a data-action="tab2" data-target="#tab2" data-toggle="tab" href="/path/tab2">
 *        Tab 2
 *      </a>
 *    </li>
 *
 *
 *  <div class="tab-content">
 *    <div class="tab-pane" id="tab1">
 *      Tab 1 Content
 *    </div>
 *    <div class="tab-pane" id="tab2">
 *      Tab 2 Content
 *    </div>
 * </div>
 *
 *
 * ### How to use
 *
 *  new window.gl.LinkedTabs({
 *    action: "#{controller.action_name}",
 *    defaultAction: 'tab1',
 *    parentEl: '.tab-links'
 *  });
 */

(() => {
  window.gl = window.gl || {};

  window.gl.LinkedTabs = class LinkedTabs {
    /**
     * Binds the events and activates de default tab.
     *
     * @param  {Object} options
     */
    constructor(options) {
      this.options = options || {};

      this.defaultAction = this.options.defaultAction;
      this.action = this.options.action || this.defaultAction;

      if (this.action === 'show') {
        this.action = this.defaultAction;
      }

      this.currentLocation = window.location;

      const tabSelector = `${this.options.parentEl} a[data-toggle="tab"]`;

      // since this is a custom event we need jQuery :(
      $(document)
        .off('shown.bs.tab', tabSelector)
        .on('shown.bs.tab', tabSelector, e => this.tabShown(e));

      this.activateTab(this.action);
    }

    /**
     * Handles the `shown.bs.tab` event to set the currect url action.
     *
     * @param  {type} evt
     * @return {Function}
     */
    tabShown(evt) {
      const source = evt.target.getAttribute('href');

      return this.setCurrentAction(source);
    }

    /**
     * Updates the URL with the path that matched the given action.
     *
     * @param  {String} source
     * @return {String}
     */
    setCurrentAction(source) {
      const copySource = source;

      copySource.replace(/\/+$/, '');

      const newState = `${copySource}${this.currentLocation.search}${this.currentLocation.hash}`;

      history.replaceState({
        url: newState,
      }, document.title, newState);
      return newState;
    }

    /**
     * Given the current action activates the correct tab.
     * http://getbootstrap.com/javascript/#tab-show
     * Note: Will trigger `shown.bs.tab`
     */
    activateTab() {
      return $(`${this.options.parentEl} a[data-action='${this.action}']`).tab('show');
    }
  };
})();