From 81d974f543b8996fa9d715506a66d7b20cc5faf4 Mon Sep 17 00:00:00 2001 From: Lars-Olof Krause Date: Thu, 12 Oct 2017 08:43:04 +0200 Subject: [PATCH 1/4] Adds contentElement selector in order to allow other elements in content container Adds additional state-hidden class for hidden content elements --- src/tabbedcontent.js | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/tabbedcontent.js b/src/tabbedcontent.js index 2a97a0a..0395eaf 100644 --- a/src/tabbedcontent.js +++ b/src/tabbedcontent.js @@ -10,19 +10,20 @@ var Tabbedcontent = function(tabcontent, options) { var defaults = { - links : tabcontent.prev().find('a').length ? tabcontent.prev().find('a') : '.tabs a', // the tabs itself. By default it selects the links contained in the previous wrapper or the links inside ".tabs a" if there's no previous item - errorSelector : '.error-message', // false to disable - speed : false, // speed of the show effect. Set to null or false to disable - onSwitch : false, // onSwitch callback - onInit : false, // onInit callback - currentClass : 'active', // current selected tab class (is set to the element) - tabErrorClass : 'has-errors', // a class to be added to the tab where errorSelector is detected - history : true, // set to false to disable HTML5 history - historyOnInit : true, // allows to deactivate the history for the intial autmatically tab switch on load - loop : false // if set to true will loop between tabs when using the next() and prev() api methods + contentElements : false, // can be used to define content elements in container (either $ object containing the element or selector string) + links : tabcontent.prev().find('a').length ? tabcontent.prev().find('a') : '.tabs a', // the tabs itself. By default it selects the links contained in the previous wrapper or the links inside ".tabs a" if there's no previous item + errorSelector : '.error-message', // false to disable + speed : false, // speed of the show effect. Set to null or false to disable + onSwitch : false, // onSwitch callback + onInit : false, // onInit callback + currentClass : 'active', // current selected tab class (is set to the element) + tabErrorClass : 'has-errors', // a class to be added to the tab where errorSelector is detected + history : true, // set to false to disable HTML5 history + historyOnInit : true, // allows to deactivate the history for the intial autmatically tab switch on load + loop : false // if set to true will loop between tabs when using the next() and prev() api methods }, firstTime = false, - children = tabcontent.children(), + children, history = window.history, loc = document.location, current = null @@ -34,6 +35,16 @@ options.links = $(options.links); } + if (options.contentElements instanceof $) { + children = options.contentElements; + } else { + if (!options.contentElements) { + children = tabcontent.children(); + } else { + children = tabcontent.find(options.contentElements); + } + } + /** * Checks if the specified tab id exists. * @@ -204,7 +215,7 @@ return filterTab.apply(this, [tab]); }).attr('aria-selected','true').parent().addClass(options.currentClass); // Hide tabs - children.hide(); + children.hide().addClass('state-hidden'); // We need to force the change of the hash if we're using the API if (options.history && api) { @@ -221,7 +232,7 @@ if (options.speed) { onSwitch(tab); } - }).attr('aria-hidden','false'); + }).removeClass('state-hidden').attr('aria-hidden','false'); if (!options.speed) { onSwitch(tab); } @@ -283,7 +294,7 @@ } // Open first tab else { - switchTab("#" + children.filter(":first-child").attr("id")); + switchTab("#" + children.eq(0).attr("id")); } // Add a class to every tab containing errors if (options.errorSelector) { From 5d2f4350797f4e7c6422f331696a90bb5e27966f Mon Sep 17 00:00:00 2001 From: Lars-Olof Krause Date: Mon, 16 Oct 2017 08:24:55 +0200 Subject: [PATCH 2/4] add doc for contentSelector --- readme.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/readme.md b/readme.md index 24f728a..7cbeffa 100644 --- a/readme.md +++ b/readme.md @@ -92,6 +92,34 @@ $('.tabscontent').tabbedContent({ }) ``` +It is possible to limit/define the tab-content elements in the main-container by defining the `contentElements` attribute: + +```javascript +$('.tabscontent').tabbedContent({ + contentElements: '.tab-content' // you can also pass a jquery/zepto object containing the content elements +}) +``` +This is usefull if you need to mix the different tab contents with other html elements to use in different breakpoints. You could display the tabs as accordion in mobile viewport by adding additional trigger links before each content container for example. +```html + + +
+ + Tab 1 Accordion +
+ +
+ + Tab 2 Accordion +
+ +
+
+``` + ### Using with Zepto.js You'll need the [`data`](https://github.com/madrobby/zepto/blob/master/src/data.js) From c0774bb09f2461947956f08d45159eb4ef052017 Mon Sep 17 00:00:00 2001 From: Travis Date: Mon, 16 Oct 2017 10:29:08 +0200 Subject: [PATCH 3/4] Update dist files [skip ci] --- dist/tabbedcontent.min.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/tabbedcontent.min.js b/dist/tabbedcontent.min.js index 90cbcc4..5746512 100644 --- a/dist/tabbedcontent.min.js +++ b/dist/tabbedcontent.min.js @@ -5,4 +5,4 @@ * @license MIT * @author Òscar Casajuana Alonso */ -!function(t,n,e,r){"use strict";var i=function(i,a){function o(t){return Boolean(I.filter(t).length)}function s(){return 0===q}function l(t){return t%1===0}function c(){return q===I.length-1}function h(n){return t(this).attr("href").match(new RegExp(n+"$"))}function u(n){return n instanceof t?{tab:n,link:a.links.eq(n.index())}:l(n)?{tab:I.eq(n),link:a.links.eq(n)}:I.filter(n).length?{tab:I.filter(n),link:a.links.filter(function(){return h.apply(this,[n])})}:{tab:I.filter("#"+n),link:a.links.filter(function(){return h.apply(this,["#"+n])})}}function f(){return a.links.parent().filter("."+a.currentClass).index()}function d(t){return++q,t===r&&(t=a.loop),q=I.length?k(0,!0):!1}function p(t){return--q,t===r&&(t=a.loop),q>=0?k(q,!0):t&&0>q?k(I.length-1,!0):!1}function g(t){a.history&&a.historyOnInit&&C&&m!==r&&"pushState"in m&&(C=!1,e.setTimeout(function(){m.replaceState(null,"",t)},100)),q=f(),a.onSwitch&&"function"==typeof a.onSwitch&&a.onSwitch(t,b()),i.trigger("onSwitch",[t,b()])}function k(t,n){return t.toString().match(/^#/)||(t="#"+u(t).tab.attr("id")),o(t)?(a.links.attr("aria-selected","false").parent().removeClass(a.currentClass),a.links.filter(function(){return h.apply(this,[t])}).attr("aria-selected","true").parent().addClass(a.currentClass),I.hide(),a.history&&n&&(m!==r&&"pushState"in m?m.pushState(null,"",t):e.location.hash=t),I.attr("aria-hidden","true").filter(t).show(a.speed,function(){a.speed&&g(t)}).attr("aria-hidden","false"),a.speed||g(t),!0):!1}function w(t){return k(t,!0)}function S(t){k(x.hash)}function v(){if(o(x.hash)?k(x.hash):a.links.parent().filter("."+a.currentClass).length?k(a.links.parent().filter("."+a.currentClass).index()):a.errorSelector&&I.find(a.errorSelector).length?I.each(function(){return t(this).find(a.errorSelector).length?(k("#"+t(this).attr("id")),!1):void 0}):k("#"+I.filter(":first-child").attr("id")),a.errorSelector&&I.find(a.errorSelector).each(function(){var n=u(t(this).parent());n.link.parent().addClass(a.tabErrorClass)}),"onhashchange"in e)t(e).bind("hashchange",S);else{var n=x.href;e.setInterval(function(){n!==x.href&&(S.call(e.event),n=x.href)},100)}t(a.links).on("click",function(n){k(t(this).attr("href").replace(/^[^#]+/,""),a.history),n.preventDefault()}),a.onInit&&"function"==typeof a.onInit&&a.onInit(b()),i.trigger("onInit",[b()])}function b(){return{"switch":w,switchTab:w,getCurrent:f,getTab:u,next:d,prev:p,isFirst:s,isLast:c}}var y={links:i.prev().find("a").length?i.prev().find("a"):".tabs a",errorSelector:".error-message",speed:!1,onSwitch:!1,onInit:!1,currentClass:"active",tabErrorClass:"has-errors",history:!0,historyOnInit:!0,loop:!1},C=!0,I=i.children(),m=e.history,x=n.location,q=null;return a=t.extend(y,a),a.links instanceof t||(a.links=t(a.links)),v(),b()};t.fn.tabbedContent=function(n){return this.each(function(){var e=new i(t(this),n);t(this).data("api",e)})}}(window.jQuery||window.Zepto||window.$,document,window); \ No newline at end of file +!function(t,n,e,r){"use strict";var i=function(i,a){function s(t){return Boolean(S.filter(t).length)}function o(){return 0===x}function l(t){return t%1===0}function c(){return x===S.length-1}function h(n){return t(this).attr("href").match(new RegExp(n+"$"))}function u(n){return n instanceof t?{tab:n,link:a.links.eq(n.index())}:l(n)?{tab:S.eq(n),link:a.links.eq(n)}:S.filter(n).length?{tab:S.filter(n),link:a.links.filter(function(){return h.apply(this,[n])})}:{tab:S.filter("#"+n),link:a.links.filter(function(){return h.apply(this,["#"+n])})}}function f(){return a.links.parent().filter("."+a.currentClass).index()}function d(t){return++x,t===r&&(t=a.loop),x=S.length?k(0,!0):!1}function p(t){return--x,t===r&&(t=a.loop),x>=0?k(x,!0):t&&0>x?k(S.length-1,!0):!1}function g(t){a.history&&a.historyOnInit&&m&&E!==r&&"pushState"in E&&(m=!1,e.setTimeout(function(){E.replaceState(null,"",t)},100)),x=f(),a.onSwitch&&"function"==typeof a.onSwitch&&a.onSwitch(t,C()),i.trigger("tabcontent.switch",[t,C()])}function k(t,n){return t.toString().match(/^#/)||(t="#"+u(t).tab.attr("id")),s(t)?(a.links.attr("aria-selected","false").parent().removeClass(a.currentClass),a.links.filter(function(){return h.apply(this,[t])}).attr("aria-selected","true").parent().addClass(a.currentClass),S.hide().addClass("state-hidden"),a.history&&n&&(E!==r&&"pushState"in E?E.pushState(null,"",t):e.location.hash=t),S.attr("aria-hidden","true").filter(t).show(a.speed,function(){a.speed&&g(t)}).removeClass("state-hidden").attr("aria-hidden","false"),a.speed||g(t),!0):!1}function w(t){return k(t,!0)}function b(t){k(I.hash)}function v(){if(s(I.hash)?k(I.hash):a.links.parent().filter("."+a.currentClass).length?k(a.links.parent().filter("."+a.currentClass).index()):a.errorSelector&&S.find(a.errorSelector).length?S.each(function(){return t(this).find(a.errorSelector).length?(k("#"+t(this).attr("id")),!1):void 0}):k("#"+S.eq(0).attr("id")),a.errorSelector&&S.find(a.errorSelector).each(function(){var n=u(t(this).parent());n.link.parent().addClass(a.tabErrorClass)}),"onhashchange"in e)t(e).bind("hashchange",b);else{var n=I.href;e.setInterval(function(){n!==I.href&&(b.call(e.event),n=I.href)},100)}t(a.links).on("click",function(n){k(t(this).attr("href").replace(/^[^#]+/,""),a.history),n.preventDefault()}),a.onInit&&"function"==typeof a.onInit&&a.onInit(C()),i.trigger("tabcontent.init",[C()])}function C(){return{"switch":w,switchTab:w,getCurrent:f,getTab:u,next:d,prev:p,isFirst:o,isLast:c}}var S,y={contentElements:!1,links:i.prev().find("a").length?i.prev().find("a"):".tabs a",errorSelector:".error-message",speed:!1,onSwitch:!1,onInit:!1,currentClass:"active",tabErrorClass:"has-errors",history:!0,historyOnInit:!0,loop:!1},m=!1,E=e.history,I=n.location,x=null;return a=t.extend(y,a),a.links instanceof t||(a.links=t(a.links)),S=a.contentElements instanceof t?a.contentElements:a.contentElements?i.find(a.contentElements):i.children(),v(),C()};t.fn.tabbedContent=function(n){return this.each(function(){var e=new i(t(this),n);t(this).data("api",e)})}}(window.jQuery||window.Zepto||window.$,document,window); \ No newline at end of file From fa362e1fe515c7b83b2988d602fd5834b2b73945 Mon Sep 17 00:00:00 2001 From: Travis Date: Mon, 16 Oct 2017 16:19:48 +0200 Subject: [PATCH 4/4] add contentElements test --- test/fixture2.html | 30 ++++++++++++++++++++++++++++++ test/tabbedcontent.spec.js | 15 +++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 test/fixture2.html diff --git a/test/fixture2.html b/test/fixture2.html new file mode 100644 index 0000000..d5013f2 --- /dev/null +++ b/test/fixture2.html @@ -0,0 +1,30 @@ + + + + + +
+ Tab 1 +
+ First tab content +
+ Tab 2 +
+ Second tab content +
+ Tab 3 +
+ Third tab content +
+ Tab 4 +
+ Fourth tab content +
+
+ + diff --git a/test/tabbedcontent.spec.js b/test/tabbedcontent.spec.js index 6020db4..9e1a737 100644 --- a/test/tabbedcontent.spec.js +++ b/test/tabbedcontent.spec.js @@ -27,6 +27,21 @@ describe('$.fn.tabbedContent', () => { done() }) + + it('hides all contents except for the first tab and non content elements', (done) => { + loadFixtures('fixture2.html'); + $('.tabscontent').tabbedContent({"contentElements": ".tabcontent-element"}); + + expect($('#tab-1')).toBeVisible() + expect($('#tab-2')).not.toBeVisible() + expect($('#tab-3')).not.toBeVisible() + expect($('#tab-n')).not.toBeVisible() + expect($('.tabscontent a:eq(0)')).toBeVisible() + expect($('.tabscontent a:eq(1)')).toBeVisible() + expect($('.tabscontent a:eq(2)')).toBeVisible() + expect($('.tabscontent a:eq(3)')).toBeVisible() + done(); + }) }) describe('events', () => {