Я работаю над устаревшим проектом, который использует вкладки пользовательского интерфейса jQuery для структурированного отображения пользовательских данных. Система не ограничивает количество вкладок, которые может создать пользователь (но обычно их около 30), а вкладки jQuery UI просто оборачивают вкладки, что выглядит очень непрофессионально.
![Wrapping tabs in my project.](https://i.stack.imgur.com/xrLGA.png)
Я наткнулся на красивый плагин Пола Бланделла OverflowTabs с 2014 года (вот его JSFiddle: http://jsfiddle.net/o1wLbtj4/,), но, к сожалению, я не могу заставить его работатьпрямо с моими 2 уровнями вкладок. Я использую jQuery 1.10.2 и jQuery UI 1.10.4. ![Gathered tabs in a dropdown menu in Paul Blundell's JSFiddle.](https://i.stack.imgur.com/tyXWG.png)
Я сделал упрощенный JSFiddle, который показывает, что я пытаюсь сделать: откройте диалоговое окно, содержащее данные на двух уровнях вкладок. Если вкладок слишком много, предполагается, что оба уровня помещают переполняющиеся вкладки в меню, открывающее раскрывающийся список при нажатии, но в данный момент (на уровне с именами) отображается только последняя вкладка, а кнопка раскрывающегося списка не работает. и читает 0: http://jsfiddle.net/megahra/6s2xwgec/18/
Насколько я могу судить, плагин правильно удаляет вкладки из первого уровня и добавляет их в div переполнения (функция _hideTab), но по какой-то причине позже он перезаписывается. Я подозреваю, что плагин не может правильно работать со вторым уровнем, но я не знаю, где это исправить.
Я был бы очень признателен, если бы кто-нибудь мог указать мне правильное направление!
EDIT:
Благодаря помощи Twisty плагин теперь работает для нескольких уровней вкладок, и я исправил несколько ошибок.
Вот рабочий JSFiddle: https://jsfiddle.net/megahra/uexr4qfw/289/
- Известная ошибка: этот плагин не применяется к вкладкам в div с style="display: none"
во время инициализации.
$.widget("ui.tabs", $.ui.tabs, {
options: {
overflowTabs: false,
tabPadding: 25,
containerPadding: 0,
dropdownSize: 50
},
_create: function() {
this._super("_create");
this.tabsWidth = 0;
this.containerWidth = 0;
this.overflowTabsId = "id" + this._createUniqueId();
$(this.element).addClass(this.overflowTabsId);
if (!this.options.overflowTabs)
return;
// update the tabs
this.updateOverflowTabs();
// Detect a window resize and check the tabs again
var that = this;
var el = this.element;
$(window).resize(function() {
// Add a slight delay after resize, to fix Maximise issue.
setTimeout(function() {
that.updateOverflowTabs();
}, 150);
});
// Detect dropdown click
$(el).on("click", '> .overflow-selector', function(e) {
$('> .ui-tabs-overflow', el).toggleClass('hide');
$overflowTabs = $('.ui-tabs-overflow').not($('> .ui-tabs-overflow', el));
//if there is more than the currently clicked one, close all others
if($overflowTabs) {
$overflowTabs.toggleClass('hide', true);
}
});
//Detect tab click
$('li a').on("click", function(e) {
//close dropdown if open
$('> .ui-tabs-overflow', el).toggleClass('hide', true);
//ToDo: apply overflowTabs plugin to content of new tab (if it contains tabs)
});
},
refresh: function() {
this._super("refresh");
this.updateOverflowTabs();
},
updateOverflowTabs: function() {
var failsafe = 0;
this._calculateWidths();
var el = this.element;
// Loop until tabsWidth is less than the containerWidth
while (this.tabsWidth > this.containerWidth -10 && failsafe < 30) {
this._hideTab();
this._calculateWidths();
failsafe++;
}
// Finish now if there are no tabs in the overflow list
if ($('> .ui-tabs-overflow li', el).length === 0)
return;
// Reset
failsafe = 0;
// Get the first tab in the overflow list
var next = this._nextTab();
// Loop until we cannot fit any more tabs
while (next.totalSize < this.containerWidth && $('> .ui-tabs-overflow li', el).length > 0 && failsafe < 30) {
this._showTab(next.tab);
this._calculateWidths();
next = this._nextTab();
failsafe++;
}
$('> .overflow-selector .total', el).html($('> .ui-tabs-overflow li', el).length);
},
_calculateWidths: function() {
var width = 0;
$(this.element).find('> .ui-tabs-nav > li').each(function() {
width += $(this).outerWidth(true);
});
this.tabsWidth = width;
this.containerWidth = $(this.element).parent().width() - this.options.containerPadding - this.options.dropdownSize;
},
_hideTab: function() {
if (!$(this.element).find('> .ui-tabs-overflow').length) {
$(this.element).find('> .ui-tabs-nav').after('<ul class="ui-tabs-overflow hide"></ul>');
$(this.element).find('> .ui-tabs-overflow').after('<div class="overflow-selector">↓ <span class="total">0</span></div>');
//calculate position of overflow-selector relativ to tab row (overflow-selector is 15px high)
let topOffset = ($(this.element).find('> .ui-tabs-nav').innerHeight() * 0.48) - 12;
$(this.element).find('> .overflow-selector').css('top', topOffset);
}
var lastTab = $('> .ui-tabs-nav li', this.element).last();
lastTab.prependTo($('> .ui-tabs-overflow', this.element));
},
_showTab: function(tab) {
tab.appendTo($('> .ui-tabs-nav', this.element));
// Check to see if overflow list is now empty
if ($(this.element).find('> .ui-tabs-overflow li').size() == 0) {
$(this.element).find('> .ui-tabs-overflow').remove();
$(this.element).find('> .overflow-selector').remove();
}
},
_nextTab: function() {
var result = {};
var firstTab = $(this.element).find('> .ui-tabs-overflow li').first();
result.tab = firstTab;
result.totalSize = this.tabsWidth + this._textWidth(firstTab) + this.options.tabPadding;
return result;
},
_textWidth: function(element) {
var self = $(element),
children = self.children(),
calculator = $('<span style="display: inline-block;" />'),
width;
children.wrap(calculator);
width = children.parent().width();
children.unwrap();
return width;
},
_createUniqueId: function() {
// Math.random should be unique because of its seeding algorithm.
// Convert it to base 36 (numbers + letters), and grab the first 9 characters
// after the decimal.
return '_' + Math.random().toString(36).substr(2, 9);
}
});