UNPKG

kist-tabify

Version:

Simple tabs and accordion interface.

728 lines (578 loc) 17.9 kB
/*! kist-tabify 0.3.1 - Simple tabs and accordion interface. | Author: Ivan Nikolić <niksy5@gmail.com> (http://ivannikolic.com/), 2017 | License: MIT */ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g=(g.jQuery||(g.jQuery = {}));g=(g.fn||(g.fn = {}));g.tabify = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ var Tabify = require(3); var meta = require(12); var emit = require(5)(meta.name); var Accordion = module.exports = Tabify.extend({ toggleItem: function ( item, state, type ) { Accordion._super.toggleItem.apply(this, arguments); if ( type === 'pane' ) { item .attr({ 'aria-expanded': state }); } }, select: function ( index ) { Accordion._super.select.apply(this, arguments); var isAlreadyActive = this.isAlreadyActive; var multiSelectMethod = this.options.multiSelect ? 'not' : 'filter'; this.toggleItem(this.$tab[multiSelectMethod](this.$activeTab), false, 'tab'); this.toggleItem(this.$pane[multiSelectMethod](this.$activePane), false, 'pane'); this.toggleItem(this.$newTab, !isAlreadyActive, 'tab'); this.toggleItem(this.$newPane, !isAlreadyActive, 'pane'); this.triggerAction(index); }, triggerAction: function () { Accordion._super.triggerAction.apply(this, arguments); if ( !this.setupDone ) { return; } if ( this.isAlreadyActive ) { emit(this, 'deselect', [this.$newTab, this.$newPane]); } } }); },{"12":12,"3":3,"5":5}],2:[function(require,module,exports){ (function (global){ var $ = (typeof window !== "undefined" ? window['$'] : typeof global !== "undefined" ? global['$'] : null); var meta = require(12); var htmlClasses = require(8); /** * @param {Object} options * * @return {String} */ function generateIds ( options ) { var self = options.self; if ( options.type === 'tab' && options.ns === '-pane' ) { options.id = self.$pane.eq(self.$tab.index(options.el)).attr('id'); } if ( options.type === 'pane' && options.ns === '-tab' ) { options.id = self.$tab.eq(self.$pane.index(options.el)).attr('id'); } return options.id ? options.id : options.ns + '-' + self.uid + '-' + options.index; } /** * @param {Tabify} instance */ var AriaGenerator = module.exports = function ( instance ) { this.instance = instance; }; /** * @param {String} type * * @return {Function} */ AriaGenerator.prototype.generateAttrs = function ( type ) { var instance = this.instance; var ariaAttr; if ( type === 'tab' ) { ariaAttr = ['aria-controls','pane']; } else { ariaAttr = ['aria-labelledby','tab']; } /** * @param {Integer} index * @param {Element} element */ return function ( index, element ) { var el = $(element); var id = el.attr('id'); var href = el.attr('href'); var options = { el: el, id: id, href: href, self: instance, index: index, type: type }; var elId; var ariaId; elId = generateIds($.extend({}, options, { ns: htmlClasses[type] })); ariaId = generateIds($.extend({}, options, { ns: htmlClasses[ariaAttr[1]] })); el.attr('id', elId); el.attr(ariaAttr[0], ariaId); }; }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"12":12,"8":8}],3:[function(require,module,exports){ (function (global){ var $ = (typeof window !== "undefined" ? window['$'] : typeof global !== "undefined" ? global['$'] : null); var Klass = require(14); var meta = require(12); var dom = require(4); var events = require(6); var instance = require(10); var htmlClasses = require(8); var getClassSelector = require(7); var emit = require(5)(meta.name); var hasPushState = (('Modernizr' in window) && window.Modernizr.history); /** * @this {Tabify} * * @param {String} direction */ function mover ( direction ) { var position = 0; if ( direction === 'next' ) { if ( this.current === this.$tab.length-1 || typeof(this.current) !== 'number' ) { position = 0; } else { position = this.current+1; } } if ( direction === 'prev' ) { if ( this.current === 0 || typeof(this.current) !== 'number' ) { position = this.$tab.length-1; } else { position = this.current-1; } } this.select(position); } /** * @this {Tabify#dom.[tab|pane]} * * @param {Integer} index * @param {Element} element * * @return {Boolean} */ function filterPane ( placement, index, element ) { var el = $(element); return el.attr('id') === placement || el.data('tab-id') === placement; } /** * @this {Tabify#dom.tab} * * @param {Integer} index * @param {Element} element * * @return {Boolean} */ function filterTab ( placement, index, element ) { var el = $(element); return filterPane.apply(null, arguments) || el.attr('href') === '#' + placement; } /** * @param {String} id * * @return {String} */ function constructId ( id ) { return id.replace(/^#/, ''); } var Tabify = module.exports = Klass.extend({ /** * @param {Element} element * @param {Object} options */ constructor: function ( element, options ) { this.element = element; this.options = $.extend(true, {}, this.defaults, options); instance.setup.call(this); dom.setup.call(this); events.setup.call(this); this.move(this.options.initial); this.setupDone = true; }, isAlreadyActiveState: function ( tab, pane ) { if ( tab.hasClass(this.options.classes.isActive) || pane.hasClass(this.options.classes.isActive) ) { return true; } return false; }, /** * @param {jQuery} item * @param {Boolean} state * @param {String} type */ toggleItem: function ( item, state, type ) { var ariaAttr; var method; if ( type === 'tab' ) { ariaAttr = 'aria-selected'; } else { ariaAttr = 'aria-hidden'; } if ( state ) { method = 'addClass'; } else { method = 'removeClass'; } if ( type === 'pane' ) { state = !state; } item [method](this.options.classes.isActive) .attr(ariaAttr, state); }, /** * @param {Integer} index */ select: function ( index ) { this.$activeTab = this.$tab.filter(getClassSelector(this.options.classes.isActive)); this.$activePane = this.$pane.filter(getClassSelector(this.options.classes.isActive)); this.$newTab = this.$tab.eq(index); this.$newPane = this.$pane.eq(index); this.isAlreadyActive = this.isAlreadyActiveState(this.$newTab, this.$newPane); if ( this.options.changeURL && this.$newTab.is('a') && hasPushState && this.setupDone ) { history.pushState({}, '', this.$newTab.attr('href')); } }, /** * @param {Integer} index */ triggerAction: function ( index ) { if ( !this.setupDone ) { emit(this, 'create', [this.$newTab, this.$newPane]); this.current = index; return; } if ( !this.isAlreadyActive ) { if ( (this.$activeTab.length || this.$activePane.length) && !this.isAlreadyActiveState(this.$activeTab, this.$activePane) ) { emit(this, 'deselect', [this.$activeTab, this.$activePane]); } emit(this, 'select', [this.$newTab, this.$newPane]); this.current = index; } }, prev: function () { mover.call(this, 'prev'); }, next: function () { mover.call(this, 'next'); }, /** * @param {Function|Number|String} placement */ move: function ( placement ) { var tab; var pane; if ( typeof(placement) === 'function' ) { placement = placement.call(this.element); } if ( typeof(placement) === 'number' ) { this.select(placement); } if ( typeof(placement) === 'string' ) { placement = constructId(placement); tab = this.$tab.filter($.proxy(filterTab, null, placement)); pane = this.$pane.filter($.proxy(filterPane, null, placement)); if ( tab.length ) { this.select(this.$tab.index(tab[0])); } else if ( pane.length ) { this.select(this.$pane.index(pane[0])); } } if ( typeof(placement) === 'boolean' ) { if ( placement ) { this.select(0); } else { emit(this, 'create', [$(), $()]); } } }, destroy: function () { dom.destroy.call(this); events.destroy.call(this); instance.destroy.call(this); }, current: null, setupDone: false, defaults: { type: 'tab', initial: 0, multiSelect: false, tab: '> ul > li > a, > ul > li > button', pane: '> div > div', changeURL: false, select: $.noop, deselect: $.noop, create: $.noop, classes: htmlClasses } }); }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"10":10,"12":12,"14":14,"4":4,"5":5,"6":6,"7":7,"8":8}],4:[function(require,module,exports){ (function (global){ // jscs:disable requireCapitalizedComments // jscs:disable disallowQuotedKeysInObjects var $ = (typeof window !== "undefined" ? window['$'] : typeof global !== "undefined" ? global['$'] : null); var meta = require(12); var htmlClasses = require(8); var AriaGenerator = require(2); var dom = module.exports = { $body: $('body'), setup: function () { var aria = new AriaGenerator(this); var generateAriaTab = aria.generateAttrs('tab'); var generateAriaPane = aria.generateAttrs('pane'); dom.$body = dom.$body.length ? dom.$body : $('body'); this.$el = $(this.element); this.$tab = this.$el.find(this.options.tab); this.$pane = this.$el.find(this.options.pane); this.$pane = this.$pane.length ? this.$pane : dom.$body.find(this.options.pane); this.$tabItem = this.$tab.closest('li'); this.$tabItem = this.$el.find(this.$tabItem).length ? this.$tabItem : $(); this.$tabList = this.$tab.closest('ul'); this.$tabList = this.$el.find(this.$tabList).length ? this.$tabList : $(); this.$el .addClass(this.options.classes.wrapper); this.$tab .addClass(this.options.classes.tab) .attr({ 'role': 'tab', 'aria-selected': false }) .each(generateAriaTab); this.$pane .addClass(this.options.classes.pane) .attr({ 'role': 'tabpanel', 'aria-hidden': true }) .each(generateAriaPane); this.$tabItem .attr({ 'role': 'presentation' }); this.$tabList .attr({ 'role': 'tablist' }); if ( this.options.type === 'accordion' ) { this.$pane .attr({ 'aria-expanded': false }); if ( this.options.multiSelect ) { this.$el .attr({ 'aria-multiselectable': true }); } } }, destroy: function () { this.$el .removeClass(this.options.classes.wrapper) .removeAttr('aria-multiselectable'); this.$tab .removeClass(this.options.classes.tab) .removeClass(this.options.classes.isActive) .removeAttr('role aria-selected aria-controls'); this.$pane .removeClass(this.options.classes.pane) .removeClass(this.options.classes.isActive) .removeAttr('role aria-hidden aria-labelledby aria-expanded'); this.$tabItem.add(this.$tabList) .removeAttr('role'); this.$tab.add(this.$pane) .each(function ( index, element ) { var el = $(this); if ( /^kist-/.test(el.attr('id')) ) { el.removeAttr('id'); } }); } }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"12":12,"2":2,"8":8}],5:[function(require,module,exports){ (function (global){ /* jshint maxparams:false */ var $ = (typeof window !== "undefined" ? window['$'] : typeof global !== "undefined" ? global['$'] : null); /** * @param {String} name * * @return {Function} */ module.exports = function ( name ) { /** * @param {Object} ctx * @param {String} eventName * @param {Array} data * @param {jQuery} triggerEl */ return function ( ctx, eventName, data, triggerEl ) { var el = (ctx.dom && ctx.dom.el) || ctx.$el || $({}); if ( ctx.options[eventName] ) { ctx.options[eventName].apply((el.length === 1 ? el[0] : el.toArray()), data); } (triggerEl || el).trigger(((name || '') + eventName).toLowerCase(), data); }; }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{}],6:[function(require,module,exports){ (function (global){ var $ = (typeof window !== "undefined" ? window['$'] : typeof global !== "undefined" ? global['$'] : null); var getClassSelector = require(7); module.exports = { setup: function () { this.$el.on('click' + this.ens, getClassSelector(this.options.classes.tab), $.proxy(function ( e ) { e.preventDefault(); this.select(this.$tab.index($(e.currentTarget))); }, this)); }, destroy: function () { this.$el.off(this.ens); } }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"7":7}],7:[function(require,module,exports){ /** * @param {String} className * * @return {String} */ module.exports = function ( className ) { return '.' + className.split(' ').join('.'); }; },{}],8:[function(require,module,exports){ var meta = require(12); var htmlClass = meta.ns.htmlClass; module.exports = { wrapper: htmlClass, tab: htmlClass + '-tab', pane: htmlClass + '-pane', isActive: 'is-active' }; },{"12":12}],9:[function(require,module,exports){ (function (global){ var $ = (typeof window !== "undefined" ? window['$'] : typeof global !== "undefined" ? global['$'] : null); var Ctor = require(3); var Tabs = require(13); var Accordion = require(1); var meta = require(12); var isPublicMethod = require(11)(meta.publicMethods); /** * @param {Object|String} options * @param {Mixed} placement * * @return {jQuery} */ var plugin = $.fn[meta.name] = module.exports = function ( options, placement ) { options = options || {}; return this.each(function () { var instance = $.data(this, meta.name); if ( isPublicMethod(options) && instance ) { instance[options](options === 'move' ? placement : undefined); } else if ( typeof(options) === 'object' && !instance ) { var Method = options.type === 'accordion' ? Accordion : Tabs; $.data(this, meta.name, new Method(this, options)); } }); }; plugin.defaults = Ctor.prototype.defaults; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"1":1,"11":11,"12":12,"13":13,"3":3}],10:[function(require,module,exports){ (function (global){ var $ = (typeof window !== "undefined" ? window['$'] : typeof global !== "undefined" ? global['$'] : null); var meta = require(12); var instance = 0; module.exports = { setup: function () { this.uid = instance++; this.ens = meta.ns.event + '.' + this.uid; }, destroy: function () { $.removeData(this.element, meta.name); } }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"12":12}],11:[function(require,module,exports){ (function (global){ var $ = (typeof window !== "undefined" ? window['$'] : typeof global !== "undefined" ? global['$'] : null); /** * @param {Array} methods * * @return {Function} */ module.exports = function ( methods ) { /** * @param {String} name * * @return {Boolean} */ return function ( name ) { return typeof(name) === 'string' && $.inArray(name, methods || []) !== -1; }; }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{}],12:[function(require,module,exports){ module.exports = { name: 'tabify', ns: { htmlClass: 'kist-Tabify', event: '.kist.tabify' }, publicMethods: ['destroy','prev','next','move'] }; },{}],13:[function(require,module,exports){ var Tabify = require(3); var Tabs = module.exports = Tabify.extend({ select: function ( index ) { Tabs._super.select.apply(this, arguments); this.toggleItem(this.$tab, false, 'tab'); this.toggleItem(this.$pane, false, 'pane'); this.toggleItem(this.$newTab, true, 'tab'); this.toggleItem(this.$newPane, true, 'pane'); this.triggerAction(index); } }); },{"3":3}],14:[function(require,module,exports){ var objExtend = require(15); /** * @param {Object} protoProps * @param {Object} staticProps * * @return {Function} */ function extend ( protoProps, staticProps ) { var self = this; var Child; if ( protoProps && protoProps.hasOwnProperty('constructor') ) { Child = protoProps.constructor; } else { Child = function () { Child._super.constructor.apply(this, arguments); }; } objExtend(Child, self, staticProps); function ChildTemp () {} ChildTemp.prototype = self.prototype; Child.prototype = new ChildTemp(); Child.prototype.constructor = Child; Child._super = self.prototype; if ( protoProps ) { objExtend(Child.prototype, protoProps); } return Child; } var Klass = module.exports = function () {}; Klass.extend = extend; },{"15":15}],15:[function(require,module,exports){ module.exports = extend var hasOwnProperty = Object.prototype.hasOwnProperty; function extend(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] for (var key in source) { if (hasOwnProperty.call(source, key)) { target[key] = source[key] } } } return target } },{}]},{},[9])(9) });