• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

uiv-lib / uiv / 6280707140

22 Sep 2023 09:50PM UTC coverage: 86.751%. Remained the same
6280707140

push

github

web-flow
chore(deps): update dependency eslint to v8.50.0

859 of 1065 branches covered (0.0%)

Branch coverage included in aggregate %.

1531 of 1690 relevant lines covered (90.59%)

183.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.13
/src/components/tabs/Tabs.vue
1
<template>
2
  <section>
3
    <ul :class="navClasses" role="tablist">
4
      <template v-for="(tab, i) in groupedTabs" :key="i">
27✔
5
        <dropdown
6
          v-if="tab.tabs"
7
          v-show="!tab.hidden"
27✔
8
          role="presentation"
9
          tag="li"
10
          :class="getTabClasses(tab)"
11
        >
12
          <a class="dropdown-toggle" role="tab" href="#" @click.prevent
13
            >{{ tab.group }} <span class="caret"></span
14
          ></a>
15
          <template #dropdown>
27✔
16
            <li
17
              v-for="(subTab, j) in tab.tabs"
18
              v-show="!subTab.hidden"
19
              :key="`${i}_${j}`"
20
              :class="getTabClasses(subTab, true)"
21
            >
22
              <a href="#" @click.prevent="select(tabs.indexOf(subTab))">{{
23
                subTab.title
24
              }}</a>
25
            </li>
26
          </template>
15✔
27
        </dropdown>
28
        <li
29
          v-else
30
          v-show="!tab.hidden"
31
          role="presentation"
32
          :class="getTabClasses(tab)"
33
        >
34
          <a
35
            v-if="tab.$slots.title"
36
            :id="tab.uid"
37
            role="tab"
38
            href="#"
39
            @click.prevent="select(tabs.indexOf(tab))"
40
          />
41
          <a
42
            v-else
43
            role="tab"
44
            href="#"
45
            @click.prevent="select(tabs.indexOf(tab))"
46
            v-text="tab.title"
47
          ></a>
48
        </li>
49
      </template>
50
      <li v-if="!justified && $slots['nav-right']" class="pull-right">
51
        <slot name="nav-right" />
16✔
52
      </li>
53
    </ul>
54
    <div :class="contentClasses">
55
      <slot />
56
    </div>
57
  </section>
58
</template>
59

16✔
60
<script>
61
import Dropdown from '../dropdown/Dropdown.vue';
62
import {
63
  isNumber,
64
  isFunction,
16!
65
  isExist,
66
  isString,
16✔
67
  hasOwnProperty,
16✔
68
} from '../../utils/object.utils';
69

70
export default {
71
  components: { Dropdown },
72
  props: {
73
    modelValue: {
74
      type: Number,
2✔
75
      validator: (v) => v >= 0,
76
      default: undefined,
77
    },
78
    transition: {
79
      type: Number,
80
      default: 150,
81
    },
1✔
82
    justified: Boolean,
83
    pills: Boolean,
84
    stacked: Boolean,
85
    customNavClass: { type: null, default: undefined },
86
    customContentClass: { type: null, default: undefined },
1✔
87
    beforeChange: { type: Function, default: undefined },
88
  },
89
  emits: ['update:modelValue', 'change', 'changed'],
90
  data() {
91
    return {
92
      tabs: [],
14✔
93
      activeIndex: 0, // Make v-model not required
94
    };
95
  },
96
  computed: {
16✔
97
    navClasses() {
98
      const tabClasses = {
99
        nav: true,
16✔
100
        'nav-justified': this.justified,
16!
101
        'nav-tabs': !this.pills,
102
        'nav-pills': this.pills,
103
        'nav-stacked': this.stacked && this.pills,
104
      };
105
      const customNavClass = this.customNavClass;
106
      if (isExist(customNavClass)) {
107
        if (isString(customNavClass)) {
×
108
          return {
109
            ...tabClasses,
110
            [customNavClass]: true,
111
          };
112
        } else {
113
          return {
114
            ...tabClasses,
×
115
            ...customNavClass,
116
          };
117
        }
118
      } else {
119
        return tabClasses;
×
120
      }
121
    },
122
    contentClasses() {
123
      const contentClasses = {
124
        'tab-content': true,
125
      };
16✔
126
      const customContentClass = this.customContentClass;
127
      if (isExist(customContentClass)) {
128
        if (isString(customContentClass)) {
129
          return { ...contentClasses, [customContentClass]: true };
39✔
130
        } else {
39✔
131
          return { ...contentClasses, ...customContentClass };
39✔
132
        }
61✔
133
      } else {
14✔
134
        return contentClasses;
135
      }
136
    },
137
    groupedTabs() {
138
      let tabs = [];
139
      const hash = {};
140
      this.tabs.forEach((tab) => {
7✔
141
        if (tab.group) {
142
          if (hasOwnProperty(hash, tab.group)) {
7✔
143
            tabs[hash[tab.group]].tabs.push(tab);
144
          } else {
145
            tabs.push({
146
              tabs: [tab],
7✔
147
              group: tab.group,
148
            });
14✔
149
            hash[tab.group] = tabs.length - 1;
1✔
150
          }
151
          if (tab.active) {
14!
152
            tabs[hash[tab.group]].active = true;
×
153
          }
154
          if (tab.pullRight) {
155
            tabs[hash[tab.group]].pullRight = true;
47✔
156
          }
157
        } else {
158
          tabs.push(tab);
39✔
159
        }
54✔
160
      });
14✔
161
      tabs = tabs.map((tab) => {
162
        if (Array.isArray(tab.tabs)) {
54✔
163
          tab.hidden =
164
            tab.tabs.filter((v) => v.hidden).length === tab.tabs.length;
39✔
165
        }
166
        return tab;
167
      });
168
      return tabs;
169
    },
170
  },
26✔
171
  watch: {
172
    modelValue: {
173
      handler(value) {
174
        if (isNumber(value)) {
175
          this.activeIndex = value;
176
          this.selectCurrent();
177
        }
15✔
178
      },
15✔
179
      immediate: true,
180
    },
181
    tabs(tabs) {
182
      tabs.forEach((tab, index) => {
183
        tab.transition = this.transition;
184
        if (index === this.activeIndex) {
×
185
          tab.show();
×
186
        }
×
187
      });
×
188
      this.selectCurrent();
189
    },
190
  },
×
191
  mounted() {
192
    this.selectCurrent();
193
  },
194
  methods: {
16✔
195
    getTabClasses(tab, isSubTab = false) {
196
      const defaultClasses = {
197
        active: tab.active,
100✔
198
        disabled: tab.disabled,
118✔
199
        'pull-right': tab.pullRight && !isSubTab,
200
      };
201

118!
202
      // return with new classes added to tab
203
      return { ...defaultClasses, ...tab.tabClasses };
204
    },
205
    selectCurrent() {
118✔
206
      let found = false;
207
      this.tabs.forEach((tab, index) => {
208
        if (index === this.activeIndex) {
209
          found = !tab.active;
210
          tab.active = true;
211
        } else {
35✔
212
          tab.active = false;
35✔
213
        }
83✔
214
      });
29✔
215
      if (found) {
29✔
216
        this.$emit('change', this.activeIndex);
217
      }
54✔
218
    },
219
    selectValidate(index) {
220
      if (isFunction(this.beforeChange)) {
35✔
221
        this.beforeChange(this.activeIndex, index, (result) => {
29✔
222
          if (!isExist(result)) {
223
            this.$select(index);
224
          }
225
        });
7✔
226
      } else {
227
        this.$select(index);
228
      }
229
    },
230
    select(index) {
231
      if (!this.tabs[index].disabled && index !== this.activeIndex) {
232
        this.selectValidate(index);
2✔
233
      }
2✔
234
    },
235
    $select(index) {
236
      if (isNumber(this.modelValue)) {
237
        this.$emit('update:modelValue', index);
238
      } else {
239
        this.activeIndex = index;
240
        this.selectCurrent();
1✔
241
      }
242
    },
243
  },
244
};
5✔
245
</script>
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc