1/* 2 Version: 2.1.1 3 Author: Gopal Raju 4 Website: http://www.productivedreams.com 5 Docs: https://gopalraju.github.io/gridtab 6 Repo: https://gopalraju.github.io/gridtab 7 Issues: https://gopalraju.github.io/gridtab/issues 8*/ 9; 10(function($, window, document, undefined) { 11 12 // Check instance count 13 var instanceCount = 0, 14 gridtab = 'gridtab', 15 defaults = { 16 grid: 4, 17 borderWidth: 0, 18 tabBorderColor: "#ddd", 19 tabPadding: 25, 20 contentBorderColor: "#ddd", 21 contentPadding: 35, 22 contentBackground: "#fff", 23 activeTabBackground: "#fff", 24 responsive: null, 25 selectors: { 26 tab: '>dt', 27 closeButton: '.gridtab__close', 28 nextArrow: '.gridtab__next.gridtab__arrow', 29 prevArrow: '.gridtab__prev.gridtab__arrow', 30 disabledArrow: '.is-disabled' 31 }, 32 config: { 33 layout: 'grid', 34 keepOpen: false, 35 speed: 500, 36 activeTab: 0, 37 showClose: false, 38 showArrows: false, 39 scrollToTab:false, 40 rtl:false 41 }, 42 callbacks: { 43 open: false, 44 close: false 45 } 46 }; 47 48 // The Gridtab constructor 49 function Gridtab(element, options) { 50 var _ = this; 51 _.element = element; 52 _.options = $.extend(true, {}, defaults, options); 53 _.defaults = defaults; 54 _.name = gridtab; 55 _.cssRules = ''; 56 _.breakpoints = []; 57 _.grids = []; 58 _.activeTab = _.options.config.activeTab - 1; 59 _.tabs = $(_.element).find('> dt'); 60 _.contents = $(_.element).find('> dd'); 61 _.init(); 62 _.generateStylesheet(_.cssRules); 63 instanceCount++; 64 } 65 /** 66 * Initializes Gridtab plugin 67 */ 68 Gridtab.prototype.init = function() { 69 var _ = this; 70 $(_.element).addClass('gridtab gridtab--' + instanceCount); 71 (_.options.config.rtl) && ($(_.element).attr('dir','rtl')); 72 _.setTabOrder(); 73 _.showControls(); 74 _.addCssRules(_.options.grid, _.options.borderWidth, _.options.tabPadding, _.options.tabBorderColor, _.options.contentPadding, _.options.contentBorderColor, _.options.contentBackground, _.options.activeTabBackgroun
74d, null); 75 (_.options.responsive !== null) ? _.responsiveBreakpoints() : _.setContentOrder(_.options.grid); 76 77 78 //If activeTab value exists and is less than total number of tabs 79 if (_.activeTab > -1 && _.activeTab < _.tabs.length) { 80 _.slideContent(_.tabs[_.activeTab], false, false); 81 } 82 83 $(_.element).on('click', _.options.selectors.tab, function(e) { 84 //if selector has href, prevent jump 85 ($(this).attr('href')) && (e.preventDefault()); 86 e.stopPropagation(); 87 e.stopImmediatePropagation(); 88 _.slideContent($(this).closest('dt'), false, _.options.config.scrollToTab); 89 }); 90 91 }; 92 93 /** 94 * Show Controls (prev,next and close) 95 */ 96 Gridtab.prototype.showControls = function() { 97 var _ = this; 98 99 if (_.options.config.showClose || _.options.config.showArrows) { 100 101 var controlsGroup = $('<div class="gridtab__controls"></div>').appendTo(_.contents); 102 //If showClose is set to true 103 if (_.options.config.showClose) { 104 $('<a class="' + _.options.selectors.closeButton.replace(/\./g, ' ') + '" href="#">Close</a>').appendTo(controlsGroup); 105 } 106 107 //If showArrows is set to true 108 if (_.options.config.showArrows) { 109 //If items exist and the count is greater than or equal to 2 110 if (_.contents.length && _.contents.length >= 2) { 111 var nextArrow = _.options.selectors.nextArrow.replace(/\./g, ' '), 112 prevArrow = _.options.selectors.prevArrow.replace(/\./g, ' '), 113 disabledArrow = _.options.selectors.disabledArrow.replace(/\./g, ' '), 114 prevElem = '<a class="' + prevArrow + '" title="previous" href="#">Prev</a>', 115 nextElem = '<a class="' + nextArrow + '" title="next" href="#">Next</a>', 116 prevDisabled = '<span class="' + prevArrow + ' ' + disabledArrow + '">Prev</span>', 117 nextDisabled = '<span class="' + nextArrow + ' ' + disabledArrow + '">Next</span>'; 118 //If there are more than 2 items add both (prev and next) arrows to all items from second to second last 119 if (_.contents.length > 2) { 120 $(prevElem + nextElem).appendTo(_.contents.slice(1, -1).find(controlsGroup)); 121 } 122 //For the last item add prev and next arrows, but keep next disabled 123 $(prevElem + nextDisabled).appendTo($(_.contents[_.contents.length - 1]).find(controlsGroup)); 124 //For the first item add prev and next arrows, but keep prev disabled 125 $(prevDisabled + nextElem).appendTo($(_.contents[0]).find(controlsGroup)); 126 } 127 } 128 129 $(controlsGroup).on('click', 'a', function(e) { 130 e.preventDefault(); 131 var currIndex = _.contents.index($(this).parent().parent()); 132 //If clicked item is prev arrow, slide the prev content 133 if ($(this).hasClass(prevArrow)) { 134 _.slideContent(_.tabs[currIndex - 1], false, _.options.config.scrollToTab); 135 } 136 //else if next arrow, slide the next 137 else if ($(this).hasClass(nextArrow)) { 138 _.slideContent(_.tabs[currIndex + 1], false, _.options.config.scrollToTab); 139 } 140 //else it's a close button 141 else { 142 _.slideContent(_.tabs[currIndex], true, false); 143 } 144 }); 145 146 147 } 148 }; 149 150 /** 151 * Sets the order of the content based on grid count 152 */ 153 Gridtab.prototype.setContentOrder = function(grid) { 154 var _ = this, 155 //Container width divided by first element width 156 rowCount = Math.ceil(_.contents.length / grid); 157 for (var i = 0; i < rowCount; i++) { 158 //Select first n elements, second n elements etc and set order 159 var j = i + 1; 160 _.contents.slice(i * grid, grid * j).css({'order': '' + (j * grid), 'flex-order': '' + (j * grid)}); 161 } 162 }; 163 /** 164 * Sets the order of each tab 165 */ 166 Gridtab.prototype.setTabOrder = function() { 167 var _ = this; 168 //Iterate through each tab and set flex order for each tab 169 _.tabs.each(function(i) { 170 $(this).css({'order': '' + i, 'flex-order':'' + i}); 171 }); 172 }; 173 /** 174 * Generate CSS rules 175 */ 176 Gridtab.prototype.addCssRules = function(grid, borderWidth, tabPadding, tabBorderColor, contentPadding, contentBorderColor, contentBackgroun
176d, activeTabBackground, breakpoint) { 177 var _ = this; 178 if (grid !== null || borderWidth !== null || tabPadding !== null || tabBorderColor !== null || contentBorderColor !== null || contentPadding !== null || contentBackground !== null || activeTabBackground !== null) { 179 var cssRules = ''; 180 var tabWidth = ''; 181 (grid !== null) && (tabWidth = Math.floor((100 / grid) * 100) / 100); 182 if (grid !== null || borderWidth !== null || tabBorderColor !== null || tabPadding !== null) { 183 //Container Styles 184 (borderWidth !== null) && (cssRules += '.gridtab--' + instanceCount + '{padding:' + borderWidth + 'px 0 0 ' + borderWidth + 'px;}'); 185 //Tab Styles 186 cssRules += '.gridtab--' + instanceCount + ' > dt{'; 187 (borderWidth !== null) && (cssRules += 'margin:-' + borderWidth + 'px 0 0 -' + borderWidth + 'px;'); 188 (grid !== null) && (cssRules += 'min-width:calc(' + tabWidth + '% + ' + borderWidth + 'px);width:calc(' + tabWidth + '% + ' + borderWidth + 'px);'); 189 (borderWidth !== null) && (cssRules += 'border-width:' + borderWidth + 'px;'); 190 (tabPadding !== null) && (cssRules += 'padding:' + tabPadding + 'px;'); 191 (tabBorderColor !== null) && (cssRules += 'border-color:' + tabBorderColor + ';'); 192 cssRules += '}'; 193 } 194 //active Tab Styles
195 (activeTabBackground !== null) && (cssRules += '.gridtab--' + instanceCount + ' >dt.is-active{background:' + activeTabBackground + ';}'); 196 (_.options.config.layout == 'tab' && activeTabBackground !== null && borderWidth !== null) && (cssRules += '.gridtab--' + instanceCount + ' >dt.is-active:after{background:' + activeTabBackground + ';height:' + borderWidth + 'px;bottom:-' + borderWidth + 'px;}'); 197 //Content Styles 198 if (contentBorderColor !== null || borderWidth !== null || contentBackground !== null || contentPadding !== null) { 199 cssRules += '.gridtab--' + instanceCount + '>dd{'; 200 cssRules += 'min-width:calc(' + (tabWidth * grid) + '% + ' + borderWidth + 'px);max-width:calc(' + (tabWidth * grid) + '% + ' + borderWidth + 'px);'; 201 (borderWidth !== null) && (cssRules += 'margin:-' + borderWidth + 'px 0 0 -' + borderWidth + 'px !important;border-width:' + borderWidth + 'px;'); 202 (contentBorderColor !== null) && (cssRules += 'border-color:' + contentBorderColor + ';'); 203 (contentPadding !== null) && (cssRules += 'padding:' + contentPadding + 'px;'); 204 (contentBackground !== null) && (cssRules += 'background:' + contentBackground + ';'); 205 cssRules += '}'; 206 } 207 //If has breakpoints generate mediaquery 208 _.cssRules += (breakpoint !== null) ? ('@media (max-width:' + breakpoint + 'px){' + cssRules + '}') : cssRules; 209 } 210 }; 211 /** 212 * Generate Stylesheet and append CSS rules 213 */ 214 Gridtab.prototype.generateStylesheet = function(cssRules) { 215 var style = $('head').append('<style>' + cssRules + '</style>'); 216 }; 217 218 /** 219 * For each breakpoint add CSS rules and set content order 220 */ 221 Gridtab.prototype.responsiveBreakpoints = function() { 222 var _ = this; 223 if (_.options.responsive && _.options.responsive.length) { 224 //Sort Responsive Options by MediaQuery in descending order 225 _.options.responsive.sort(function(a, b) { 226 return parseFloat(b.breakpoint) - parseFloat(a.breakpoint); 227 }); 228 var mqls = []; 229 230 function getBreakpoint() { 231 var bpArray = []; 232 mqls.filter(function(el) { 233 234 //If breakpoint matches convert it to number and push the breakpoint to bpArray 235 if (el.matches) { 236 bpArray.push(parseInt(el.media.replace(/[^\d.]/g, ''))); 237 } 238 239 240 }); 241 242 243 //If bpArray exists, find the smallest breakpoint and its index in -.breakpoints 244 //else use the default grid value from options 245 var grid = (bpArray.length ? _.grids[_.breakpoints.indexOf(Math.min.apply(null, bpArray))] : _.options.grid); 246 247 _.setContentOrder(grid); 248 } 249 250 for (var i in _.options.responsive) { 251 var responsiveSettings = _.options.responsive[i].settings, 252 grid = responsiveSettings.grid || _.options.grid, 253 borderWidth = responsiveSettings.borderWidth || _.options.borderWidth, 254 tabBorderColor = responsiveSettings.tabBorderColor || null, 255 tabPadding = responsiveSettings.tabPadding || null,
256 activeTabBackground = responsiveSettings.activeTabBackground || null, 257 contentPadding = responsiveSettings.contentPadding || null, 258 contentBorderColor = responsiveSettings.contentBorderColor || null, 259 contentBackground = responsiveSettings.contentBackground || null, 260 breakpoint = _.options.responsive[i].breakpoint || null; 261 _.addCssRules(grid, borderWidth, tabPadding, tabBorderColor, contentPadding, contentBorderColor, contentBackground, activeTabBackground, breakpoint); 262 _.breakpoints.push(breakpoint); 263 _.grids.push(grid); 264 mqls.push(window.matchMedia("(max-width:" + _.breakpoints[i] + "px)")); 265 getBreakpoint(window.matchMedia("(max-width:" + _.breakpoints[i] + "px)")); 266 } 267 268 //For each MedaiQuery 269 for (var i = 0; i < mqls.length; i++) { // loop through queries 270 mqls[i].addListener(getBreakpoint) // call handler function whenever the media query is triggered; 271 } 272 273 } 274 }; 275 /** 276 * Scroll to active tab 277 */ 278 Gridtab.prototype.scrollToTab = function() { 279 var _ = this; 280 var page = $('html, body'); 281 page.on("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove", function() { 282 page.stop(); 283 }); 284 page.animate({ 285 scrollTop: $(_.element).find('.is-active').offset().top 286 }, 1000, function() { 287 page.off("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove"); 288 }); 289 }; 290 /** 291 * Slide up and slide down contents based on tab clicked 292 */ 293 Gridtab.prototype.slideContent = function(currTab, closeBtnClick, scrollToTab) { 294 var _ = this, 295 $currTab = $(currTab), 296 $prevTab = $(_.element).find('>dt.is-active').not(currTab); 297 if (!$currTab.hasClass('is-disabled')) { 298 //If an active tab already exists 299 if ($prevTab.length) { 300 //Keep all tabs disabled while the transition happens 301 _.tabs.addClass('is-disabled'); 302 $prevTab.next().stop(true).slideUp(_.options.config.speed, function() { 303 $prevTab.removeClass('is-active'); 304 _.tabs.next().stop(true); 305 (_.options.callbacks.close) && (_.options.callbacks.close.call(this)); 306 $currTab.addClass('is-active').next().stop(true).slideDown(_.options.config.speed, function() { 307 (_.options.callbacks.open) && (_.options.callbacks.open.call(this)); 308 (scrollToTab) && (_.scrollToTab()); 309 //Remove disabled after transition is complete 310 _.tabs.removeClass('is-disabled'); 311 return false; 312 }); 313 return false; 314 315 }); 316 317 } else { 318 //If keepOpen is true and close button is not clicked 319 if (_.options.config.keepOpen && !closeBtnClick) { 320 if (!$currTab.hasClass('is-active')) { 321 $currTab.addClass('is-active').next().stop(true).slideDown(_.options.config.speed, function() { 322 (_.options.callbacks.open) && (_.options.callbacks.open.call(this)); 323 (scrollToTab) && (_.scrollToTab()); 324 }); 325 return false; 326 } 327 } else { 328 //Keep all tabs disabled while the transition happens 329 _.tabs.addClass('is-disabled'); 330 $currTab.toggleClass('is-active').next().stop(true).slideToggle(_.options.config.speed, function() { 331 332 if ($(this).is(':hidden')) { 333 (_.options.callbacks.close) && (_.options.callbacks.close.call(this)); 334 335 } else { 336 (_.options.callbacks.open) && (_.options.callbacks.open.call(this)); 337 (scrollToTab) && (_.scrollToTab()); 338 } 339 //Remove disabled after transition is complete 340 _.tabs.removeClass('is-disabled'); 341 return false; 342 }); 343 } 344 345 } 346 347 return false; 348 } 349 }; 350 351 $.fn[gridtab] = function(options) { 352 return this.each(function() { 353 354 if (!$.data(this, 'plugin_' + gridtab)) { 355 $.data(this, 'plugin_' + gridtab, 356 new Gridtab(this, options)); 357 } 358 }); 359 360 }; 361 362})(jQuery, window, document);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.