224 lines
7 KiB
JavaScript
224 lines
7 KiB
JavaScript
|
/**
|
||
|
* jQuery Tabs for ProcessWire
|
||
|
*
|
||
|
* ProcessWire 3.x (development), Copyright 2015 by Ryan Cramer
|
||
|
* https://processwire.com
|
||
|
*
|
||
|
*/
|
||
|
(function($) {
|
||
|
|
||
|
$.fn.WireTabs = function(customOptions) {
|
||
|
|
||
|
var options = {
|
||
|
rememberTabs: 0, // -1 = no, 0 = only after submit, 1 = always
|
||
|
requestID: '',
|
||
|
cookieName: 'WireTabs',
|
||
|
items: null,
|
||
|
skipRememberTabIDs: [],
|
||
|
itemsParent: null,
|
||
|
ulClass: 'WireTabs nav',
|
||
|
ulAttrs: '',
|
||
|
liActiveClass: '',
|
||
|
aActiveClass: 'on',
|
||
|
id: '' // id for tabList. if already exists, existing tabList will be used
|
||
|
};
|
||
|
|
||
|
var totalTabs = 0;
|
||
|
var cfg = ProcessWire.config.JqueryWireTabs;
|
||
|
var keys = [ 'rememberTabs', 'requestID', 'cookieName', 'liActiveClass', 'aActiveClass', 'ulClass', 'ulAttrs' ];
|
||
|
|
||
|
for(var n = 0; n < keys.length; n++) {
|
||
|
var key = keys[n];
|
||
|
if(typeof cfg[key] != "undefined") options[key] = cfg[key];
|
||
|
}
|
||
|
|
||
|
$.extend(options, customOptions);
|
||
|
|
||
|
return this.each(function(index) {
|
||
|
|
||
|
var $tabList = null;
|
||
|
var $target = $(this);
|
||
|
var lastTabID = ''; // ID attribute of last tab that was clicked
|
||
|
var generate = true; // generate markup/manipulate DOM?
|
||
|
var queueTabClick = []; // queued wiretabclick event, becomes false after document.ready
|
||
|
|
||
|
function init() {
|
||
|
|
||
|
if(!options.items) return;
|
||
|
if(options.items.length < 1) return;
|
||
|
|
||
|
if(options.id.length) {
|
||
|
$tabList = $("#" + options.id);
|
||
|
if($tabList.length) generate = false;
|
||
|
else $tabList = null;
|
||
|
}
|
||
|
if(!$tabList) {
|
||
|
$tabList = $('<ul' + (options.ulAttrs ? ' ' + options.ulAttrs : '') + '></ul>');
|
||
|
$tabList.addClass(options.ulClass);
|
||
|
if(options.id.length) $tabList.attr('id', options.id);
|
||
|
}
|
||
|
|
||
|
options.items.each(addTab);
|
||
|
if(generate) $target.prepend($tabList); // DOM manipulation
|
||
|
|
||
|
var $form = $target;
|
||
|
var $rememberTab = null;
|
||
|
var cookieTab = getTabCookie();
|
||
|
|
||
|
if(options.rememberTabs == 0) {
|
||
|
$form.on('submit', function() {
|
||
|
setTabCookie(lastTabID);
|
||
|
return true;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
var href = window.location.href;
|
||
|
var hrefMatch = '';
|
||
|
if(href.indexOf('WireTab')) {
|
||
|
var regex = new RegExp('[&;?]WireTab=([-_a-z0-9]+)', 'i');
|
||
|
hrefMatch = href.match(regex);
|
||
|
hrefMatch = hrefMatch ? hrefMatch[1] : '';
|
||
|
if(hrefMatch.length) {
|
||
|
$rememberTab = $tabList.find("a#_" + hrefMatch);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if($rememberTab == null) {
|
||
|
var hash = document.location.hash.replace("#", ""); // thanks to @da-fecto
|
||
|
if(hash.length) {
|
||
|
$rememberTab = $tabList.find("a#_" + hash);
|
||
|
if($rememberTab.length == 0) {
|
||
|
$rememberTab = null;
|
||
|
} else {
|
||
|
document.location.hash = '';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if($rememberTab == null && cookieTab.length > 0 && options.rememberTabs > -1) {
|
||
|
$rememberTab = $tabList.find("a#" + cookieTab);
|
||
|
}
|
||
|
if($rememberTab && $rememberTab.length > 0) {
|
||
|
$rememberTab.trigger('click');
|
||
|
if (options.rememberTabs == 0) setTabCookie(''); // don't clear cookie when rememberTabs=1, so it continues
|
||
|
setTimeout(function() { $rememberTab.trigger('click'); }, 200); // extra backup, necessary for some event monitoring
|
||
|
} else {
|
||
|
$tabList.children("li").first().children("a").trigger('click');
|
||
|
}
|
||
|
|
||
|
$(document).ready(function() {
|
||
|
// if a wiretabclick event queued before document.ready, trigger it now
|
||
|
if(queueTabClick.length) $(document).trigger('wiretabclick', [ queueTabClick[0], queueTabClick[1] ]);
|
||
|
queueTabClick = false;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function addTab() {
|
||
|
totalTabs++;
|
||
|
var $t = $(this);
|
||
|
if(!$t.attr('id')) $t.attr('id', "WireTab" + totalTabs);
|
||
|
var title = $t.attr('title') || $t.attr('id');
|
||
|
$t.removeAttr('title');
|
||
|
var href = $t.attr('id');
|
||
|
var $a = $('a#_' + href); // does it already exist?
|
||
|
if($a.length > 0) {
|
||
|
$a.on('click', tabClick);
|
||
|
} else {
|
||
|
$a = $("<a></a>")
|
||
|
.attr('href', '#' + href)
|
||
|
.attr('id', '_' + href) // ID equal to tab content ID, but preceded with underscore
|
||
|
.html(title)
|
||
|
.on('click', tabClick);
|
||
|
$tabList.append($("<li></li>").append($a));
|
||
|
}
|
||
|
var tip = $t.attr('data-tooltip');
|
||
|
if($t.hasClass('WireTabTip') || tip) {
|
||
|
// if the tab being added has the class 'WireTabTip' or has a data-tooltip attribute
|
||
|
// then display a tooltip with the tab
|
||
|
if(!tip) tip = title;
|
||
|
for(var key in cfg.tooltipAttr) {
|
||
|
var val = cfg.tooltipAttr[key];
|
||
|
if(val.indexOf('{tip}') > -1) val = val.replace('{tip}', tip);
|
||
|
if(key === 'class') {
|
||
|
$a.addClass(val);
|
||
|
} else {
|
||
|
$a.attr(key, val);
|
||
|
}
|
||
|
}
|
||
|
// $a.addClass('tooltip');
|
||
|
// $a.attr('title', tip ? tip : title);
|
||
|
}
|
||
|
$t.hide();
|
||
|
// the following removed to prevent DOM manipulation if the tab content:
|
||
|
// if(options.itemsParent === null) options.itemsParent = $t.parent();
|
||
|
//if($t.parent() != options.itemsParent) options.itemsParent.prepend($t);
|
||
|
//$target.prepend($t.hide());
|
||
|
}
|
||
|
|
||
|
function tabClick() {
|
||
|
|
||
|
var aActiveClass = options.aActiveClass;
|
||
|
var liActiveClass = options.liActiveClass;
|
||
|
|
||
|
var $oldTab = $tabList.find("a." + aActiveClass);
|
||
|
var $newTab = $(this);
|
||
|
|
||
|
if(!$oldTab.length) $oldTab = $tabList.find("a").eq(0);
|
||
|
|
||
|
|
||
|
var oldTabHref = $oldTab.attr('href');
|
||
|
var newTabHref = $newTab.attr('href');
|
||
|
|
||
|
var $oldTabContent = oldTabHref && oldTabHref.indexOf('#') === 0 ? $(oldTabHref) : null;
|
||
|
var $newTabContent = newTabHref && newTabHref.indexOf('#') === 0 ? $(newTabHref) : null;
|
||
|
|
||
|
var newTabID = $newTab.attr('id');
|
||
|
var oldTabID = $oldTab.attr('id');
|
||
|
|
||
|
$oldTab.removeClass(aActiveClass);
|
||
|
$newTab.addClass(aActiveClass);
|
||
|
|
||
|
if(liActiveClass.length) {
|
||
|
$tabList.find('li.' + liActiveClass).removeClass(liActiveClass);
|
||
|
$newTab.closest('li').addClass(liActiveClass);
|
||
|
}
|
||
|
|
||
|
if($oldTabContent) $oldTabContent.hide();
|
||
|
if($newTabContent) {
|
||
|
$newTabContent.show();
|
||
|
} else if(newTabHref && newTabHref.length) {
|
||
|
window.location.href = newTabHref;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// add a target classname equal to the ID of the selected tab
|
||
|
// so there is opportunity for 3rd party CSS adjustments outside this plugin
|
||
|
if(oldTabID) $target.removeClass($oldTabContent.attr('id'));
|
||
|
$target.addClass(newTabID);
|
||
|
if(options.rememberTabs > -1) {
|
||
|
if(jQuery.inArray(newTabID, options.skipRememberTabIDs) != -1) newTabID = '';
|
||
|
if(options.rememberTabs == 1) setTabCookie(newTabID);
|
||
|
lastTabID = newTabID;
|
||
|
}
|
||
|
if(queueTabClick === false) {
|
||
|
$(document).trigger('wiretabclick', [ $newTabContent, $oldTabContent ]);
|
||
|
} else {
|
||
|
queueTabClick = [ $newTabContent, $oldTabContent ];
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function setTabCookie(value) {
|
||
|
jQuery.cookie(options.cookieName, options.requestID + '-' + value);
|
||
|
}
|
||
|
|
||
|
function getTabCookie() {
|
||
|
var value = jQuery.cookie(options.cookieName);
|
||
|
if(!value || value.indexOf(options.requestID + '-') !== 0) return '';
|
||
|
return value.substring(options.requestID.length + 1);
|
||
|
}
|
||
|
|
||
|
init();
|
||
|
})
|
||
|
}
|
||
|
})(jQuery);
|