mirror of
https://github.com/VTECRM/vtenext.git
synced 2026-02-27 16:48:47 +00:00
250 lines
8.3 KiB
JavaScript
250 lines
8.3 KiB
JavaScript
/*************************************
|
|
* SPDX-FileCopyrightText: 2009-2020 Vtenext S.r.l. <info@vtenext.com>
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
************************************/
|
|
(function ($) {
|
|
|
|
var methods = {
|
|
init : function(options) {
|
|
var defaults = {
|
|
onShow: null,
|
|
swipeable: false,
|
|
responsiveThreshold: Infinity, // breakpoint for swipeable
|
|
};
|
|
options = $.extend(defaults, options);
|
|
var namespace = Materialize.objectSelectorString($(this));
|
|
|
|
return this.each(function(i) {
|
|
|
|
var uniqueNamespace = namespace+i;
|
|
|
|
// For each set of tabs, we want to keep track of
|
|
// which tab is active and its associated content
|
|
var $this = $(this),
|
|
window_width = $(window).width();
|
|
|
|
var $active, $content, $links = $this.find('li.tab a'),
|
|
$tabs_width = $this.width(),
|
|
$tabs_content = $(),
|
|
$tabs_wrapper,
|
|
$tab_width = Math.max($tabs_width, $this[0].scrollWidth) / $links.length,
|
|
$indicator,
|
|
index = 0,
|
|
prev_index = 0,
|
|
clicked = false,
|
|
clickedTimeout,
|
|
transition = 300;
|
|
|
|
|
|
// Finds right attribute for indicator based on active tab.
|
|
// el: jQuery Object
|
|
var calcRightPos = function(el) {
|
|
return Math.ceil($tabs_width - el.position().left - el[0].getBoundingClientRect().width - $this.scrollLeft());
|
|
};
|
|
|
|
// Finds left attribute for indicator based on active tab.
|
|
// el: jQuery Object
|
|
var calcLeftPos = function(el) {
|
|
return Math.floor(el.position().left + $this.scrollLeft());
|
|
};
|
|
|
|
// Animates Indicator to active tab.
|
|
// prev_index: Number
|
|
var animateIndicator = function(prev_index) {
|
|
if ((index - prev_index) >= 0) {
|
|
$indicator.velocity({"right": calcRightPos($active) }, { duration: transition, queue: false, easing: 'easeOutQuad'});
|
|
$indicator.velocity({"left": calcLeftPos($active) }, {duration: transition, queue: false, easing: 'easeOutQuad', delay: 90});
|
|
|
|
} else {
|
|
$indicator.velocity({"left": calcLeftPos($active) }, { duration: transition, queue: false, easing: 'easeOutQuad'});
|
|
$indicator.velocity({"right": calcRightPos($active) }, {duration: transition, queue: false, easing: 'easeOutQuad', delay: 90});
|
|
}
|
|
};
|
|
|
|
// Change swipeable according to responsive threshold
|
|
if (options.swipeable) {
|
|
if (window_width > options.responsiveThreshold) {
|
|
options.swipeable = false;
|
|
}
|
|
}
|
|
|
|
|
|
// If the location.hash matches one of the links, use that as the active tab.
|
|
$active = $($links.filter('[href="'+location.hash+'"]'));
|
|
|
|
// If no match is found, use the first link or any with class 'active' as the initial active tab.
|
|
if ($active.length === 0) {
|
|
$active = $(this).find('li.tab a.active').first();
|
|
}
|
|
if ($active.length === 0) {
|
|
$active = $(this).find('li.tab a').first();
|
|
}
|
|
|
|
$active.addClass('active');
|
|
index = $links.index($active);
|
|
if (index < 0) {
|
|
index = 0;
|
|
}
|
|
|
|
if ($active[0] !== undefined) {
|
|
$content = $($active[0].hash);
|
|
$content.addClass('active');
|
|
}
|
|
|
|
// append indicator then set indicator width to tab width
|
|
if (!$this.find('.indicator').length) {
|
|
$this.append('<li class="indicator"></li>');
|
|
}
|
|
$indicator = $this.find('.indicator');
|
|
|
|
// we make sure that the indicator is at the end of the tabs
|
|
$this.append($indicator);
|
|
|
|
if ($this.is(":visible")) {
|
|
// $indicator.css({"right": $tabs_width - ((index + 1) * $tab_width)});
|
|
// $indicator.css({"left": index * $tab_width});
|
|
setTimeout(function() {
|
|
$indicator.css({"right": calcRightPos($active) });
|
|
$indicator.css({"left": calcLeftPos($active) });
|
|
}, 0);
|
|
}
|
|
$(window).off('resize.tabs-'+uniqueNamespace).on('resize.tabs-'+uniqueNamespace, function () {
|
|
$tabs_width = $this.width();
|
|
$tab_width = Math.max($tabs_width, $this[0].scrollWidth) / $links.length;
|
|
if (index < 0) {
|
|
index = 0;
|
|
}
|
|
if ($tab_width !== 0 && $tabs_width !== 0) {
|
|
$indicator.css({"right": calcRightPos($active) });
|
|
$indicator.css({"left": calcLeftPos($active) });
|
|
}
|
|
});
|
|
|
|
// Initialize Tabs Content.
|
|
if (options.swipeable) {
|
|
// TODO: Duplicate calls with swipeable? handle multiple div wrapping.
|
|
$links.each(function () {
|
|
var $curr_content = $(Materialize.escapeHash(this.hash));
|
|
$curr_content.addClass('carousel-item');
|
|
$tabs_content = $tabs_content.add($curr_content);
|
|
});
|
|
$tabs_wrapper = $tabs_content.wrapAll('<div class="tabs-content carousel"></div>');
|
|
$tabs_content.css('display', '');
|
|
$('.tabs-content.carousel').carousel({
|
|
fullWidth: true,
|
|
noWrap: true,
|
|
onCycleTo: function(item) {
|
|
if (!clicked) {
|
|
var prev_index = index;
|
|
index = $tabs_wrapper.index(item);
|
|
$active.removeClass('active');
|
|
$active = $links.eq(index);
|
|
$active.addClass('active');
|
|
animateIndicator(prev_index);
|
|
if (typeof(options.onShow) === "function") {
|
|
options.onShow.call($this[0], $content);
|
|
}
|
|
}
|
|
},
|
|
});
|
|
} else {
|
|
// Hide the remaining content
|
|
$links.not($active).each(function () {
|
|
$(Materialize.escapeHash(this.hash)).hide();
|
|
});
|
|
}
|
|
|
|
|
|
// Bind the click event handler
|
|
$this.off('click.tabs').on('click.tabs', 'a', function(e) {
|
|
if ($(this).parent().hasClass('disabled')) {
|
|
e.preventDefault();
|
|
return;
|
|
}
|
|
|
|
// Act as regular link if target attribute is specified.
|
|
if (!!$(this).attr("target")) {
|
|
return;
|
|
}
|
|
|
|
clicked = true;
|
|
$tabs_width = $this.width();
|
|
$tab_width = Math.max($tabs_width, $this[0].scrollWidth) / $links.length;
|
|
|
|
// Make the old tab inactive.
|
|
$active.removeClass('active');
|
|
var $oldContent = $content
|
|
|
|
// Update the variables with the new link and content
|
|
$active = $(this);
|
|
$content = $(Materialize.escapeHash(this.hash));
|
|
$links = $this.find('li.tab a');
|
|
var activeRect = $active.position();
|
|
|
|
// Make the tab active.
|
|
$active.addClass('active');
|
|
prev_index = index;
|
|
index = $links.index($(this));
|
|
if (index < 0) {
|
|
index = 0;
|
|
}
|
|
// Change url to current tab
|
|
// window.location.hash = $active.attr('href');
|
|
|
|
// Swap content
|
|
if (options.swipeable) {
|
|
if ($tabs_content.length) {
|
|
$tabs_content.carousel('set', index, function() {
|
|
if (typeof(options.onShow) === "function") {
|
|
options.onShow.call($this[0], $content);
|
|
}
|
|
});
|
|
}
|
|
} else {
|
|
if ($content !== undefined) {
|
|
$content.show();
|
|
$content.addClass('active');
|
|
if (typeof(options.onShow) === "function") {
|
|
options.onShow.call(this, $content);
|
|
}
|
|
}
|
|
|
|
if ($oldContent !== undefined &&
|
|
!$oldContent.is($content)) {
|
|
$oldContent.hide();
|
|
$oldContent.removeClass('active');
|
|
}
|
|
}
|
|
|
|
// Reset clicked state
|
|
clickedTimeout = setTimeout(function(){ clicked = false; }, transition);
|
|
|
|
// Update indicator
|
|
animateIndicator(prev_index);
|
|
|
|
// Prevent the anchor's default click action
|
|
e.preventDefault();
|
|
});
|
|
});
|
|
|
|
},
|
|
select_tab : function( id ) {
|
|
this.find('a[href="#' + id + '"]').trigger('click');
|
|
}
|
|
};
|
|
|
|
$.fn.tabs = function(methodOrOptions) {
|
|
if ( methods[methodOrOptions] ) {
|
|
return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
|
|
} else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
|
|
// Default to "init"
|
|
return methods.init.apply( this, arguments );
|
|
} else {
|
|
$.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.tabs' );
|
|
}
|
|
};
|
|
|
|
$(document).ready(function(){
|
|
$('ul.tabs').tabs();
|
|
});
|
|
}( jQuery )); |