1/** 2 * DOCman Sidebar 3 * 4 * Customized wrapper for advanced layout logic and behavior for the sidebar. 5 * Uses Bootstrap Affix to make sure the sidebar never scrolls out of view (@TODO can't wait to use CSS4 position:sticky) 6 * Makes sure that the sidebar height matches viewport height. 7 * Allows advanced layout like locking page resize to only resize a mootree list, so that other parts of the sidebar is always visible. 8 * Specializes Affix plugin to work on pages that are responsive, where static top and bottom values would break the layout. 9 * Contains workarounds for Joomla! 3.0 responsive layout hacks that otherwise screws up the sidebar positioning is fixed. 10 * 11 * 12 * @copyright Copyright (C) 2007 Johan Janssens and Timble CVBA. (http://www.timble.net) 13 * @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> 14 * @requires Bootstrap Affix plugin 15 */ 16 17var Docman = Docman || {}; 18 19(function($){ 20 21 /* Defining the constructor (same as initialize in MooTools Class) */ 22 /** 23 * @param options 24 * @constructor 25 */ 26 Docman.Sidebar = function(options){ 27 28 //@TODO 'limit' option is automatically passed to php behavior 29 if(options.hasOwnProperty('offset') && !$.isPlainObject(options.offset)) delete options.offset; 30 31 this.setOptions(options); 32 33 this.sidebar = $(this.options.sidebar); 34 this.target = this.sidebar.find(this.options.target); 35 this.siblings = this.target.siblings(); 36 37 this.observe = this.options.observe ? $(this.options.observe) : this.sidebar.next(); 38 39 //Setup the inner container 40 this.target.css('overflow', 'auto'); 41 42 //Check if the height is sufficient 43 if(this.options.affix) this.options.affix = this.observe.outerHeight() > $(window).height(); 44 this.affix = this.options.affix; 45 46 this.setHeight(); 47 48 if(this.options.affix && this.observe.outerHeight()) { 49 this.sidebar.affix({ 50 offset: { 51 top: $.proxy(function(){ 52 if(this.affix) { 53 return this.sidebar.parent().offset().top - this.options.offset.top; 54 } else { 55 return $(document).height(); 56 } 57 }, this), 58 bottom: $.proxy(function(){ 59 return $(document).height() - (this.observe.offset().top + this.observe.outerHeight()) + this.options.offset.bottom; 60 }, this) 61 } 62 }); 63 } 64 65 $(window) 66 .on('resize', $.proxy(this.setHeight, this)) 67 .on('sidebar:setHeight', $.proxy(this.setHeight, this)) 68 .on('sidebar:resizeHeight', $.proxy(function(){ 69 //console.log(arguments, this); 70 this.resizeHeight(); 71 }, this)); 72 73 this.makeCollapsible(); 74 }; 75 76 Docman.Sidebar.prototype = { 77 78 /** 79 * @constructs DOCman.Sidebar 80 */ 81 constructor: Docman.Sidebar, 82 83 /** 84 * @method getDefaults 85 * @returns {{minHeight: number, sidebar: string, target: string, observe: boolean, affix: boolean, offset: {top: number, bottom: number, callback: Function}}} 86 */ 87 getDefaults: function(){ 88 89 /** @lends DOCman.Sidebar.options */ 90 var defaults = { 91 minHeight: 200, 92 sidebar: '.sidebar', 93 target: '.sidebar-inner', 94 padding: {bottom: 50}, 95 observe: false, //Pass a css selector if the content area isn't the sidebars next sibling DOM element 96 affix: false, //If Bootstrap's Affix plugin is loaded, this option will make the sidebar scroll with the view 97 offset: {top: 0, bottom: 0, callback: function(){}} 98 }; 99 100 if($('.navbar').length) { 101 /** 102 * @lends DOCman.Sidebar.options.offset.callback 103 * @this DOCman.Sidebar 104 */ 105 defaults.offset.callback = function(){ 106 this.options.offset.top = this.options.offset.bottom = 0; 107 /** 108 * Workarounds for possible fixed UI elements to calculate correct offsets 109 */ 110 if($('.navbar-fixed-top').css('position') == 'fixed') { 111 /** 112 * Top navbar is fixed on desktop layout, static on mobile and tablet 113 * @type {number} 114 */ 115 this.options.offset.top += $('.navbar.navbar-fixed-top').outerHeight(); 116 } 117 var mobile_layout = this._isMobileLayout(); 118 if(mobile_layout) { 119 if(mobile_layout === 1) { 120 //Mobile layout not enabled 121 this.options.offset.top += $('.subhead-collapse .subhead').outerHeight(); 122 this.affix = true; 123 } else { 124 //Mobile layout is being enabled 125 this.affix = false;
126 } 127 } 128 //Navbar at the bottom may exist in both desktop and tablet layout 129 if($('.navbar-fixed-bottom').is(':visible')) { 130 /** 131 * Bottom navbar is fixed on desktop layout and sometimes on tablet laout, always static on mobile 132 * @type {number} 133 */ 134 this.options.offset.bottom += $('.navbar-fixed-bottom').outerHeight(); 135 } 136 } 137 } 138 139 return defaults; 140 }, 141 142 setOptions: function(options){ 143 144 this.options = $.extend(true, {}, this.getDefaults(), options); 145 146 return this; 147 }, 148 149 makeCollapsible: function() { 150 var sidebar = $('#documents-sidebar'), storage = window.localStorage || {}, duration; 151 sidebar.find('h3').each(function(i, h3){ 152 var $h3 = $(h3), key = 'DOCman#documents-sidebar['+i+']', state = storage[key] != 'closed' ? 'open' : 'closed', panel = $h3.next(); 153 154 panel.addClass('sidebar-panel').data('height', panel.height()); 155 156 if(!duration) { 157 panel.addClass('transition-enabled'); 158 duration = parseFloat(panel.css('transition-duration'), 10)*1000; 159 panel.removeClass('transition-enabled'); 160 } 161 162 $h3.addClass(state).on('click', function(){ 163 $(this).toggleClass('open closed'); 164 165 /** trying to animate the height change 166 if(!$(this).is('.k-js-category-tree') && $('.k-js-category-tree').is(':visible')) { 167 if($(this).hasClass('open')) { 168 console.warn('ioenung!', '+='+$(this).outerHeight()+'px'); 169 $('.k-js-category-tree').animate({height: '+='+$(this).outerHeight()+'px'}, duration); 170 } else { 171 $('.k-js-category-tree').animate({height: '-='+$(this).outerHeight()+'px'}, duration); 172 console.log('-='+$(this).outerHeight()+'px'); 173 } 174 } 175 //*/ 176 177 if($(this).hasClass('closed')) { 178 panel.css('height', ''); 179 panel.data('height', panel.height()); 180 panel.css('height', panel.height()).addClass('transition-enabled'); 181 182 setTimeout(function(){ 183 panel.addClass('sidebar-panel-closed').css('height', '0px'); 184 }, 0); 185 186 setTimeout(function() { 187 panel.removeClass('transition-enabled'); 188 }, duration+100); 189 } else { 190 191 panel.addClass('transition-enabled'); 192 setTimeout(function(){ 193 panel.removeClass('sidebar-panel-closed').css('height', panel.data('height')); 194 }, 0); 195 196 setTimeout(function() { 197 panel.removeClass('transition-enabled').css('height', ''); 198 panel.data('height', panel.height()); 199 }, duration+100); 200 } 201 202 setTimeout(function() { 203 //Resets the height of the categories tree 204 //$(window).trigger('sidebar:resizeHeight', [to_height]); //@TODO animate height change to categories list 205 $(window).trigger('sidebar:setHeight'); 206 }, duration+100); 207 208 storage[key] = $h3.hasClass('open') ? 'open' : 'closed'; 209 }); 210 if(state == 'closed') { 211 panel.data('height', panel.height()); 212 panel.addClass('sidebar-panel-closed').css('height', '0px'); 213 } 214 }); 215 }, 216 217 /** 218 * @method setHeight 219 * 220 */ 221 setHeight: function(){ 222 223 if(this.options.offset.callback && this.options.offset.callback.call) this.options.offset.callback.call(this); 224 225 if(this.options.affix) { 226 //Making sure it's positioned correctly 227 $(window).trigger('scroll.affix.data-api'); 228 229 //Set the right horizontal offset, this changes as the sidebar collapses in responsive layouts 230 this.sidebar.css({left: this.sidebar.parent().offset().left+1, top: this.options.offset.top}); 231 } 232 233 // if mobile layout, remove extra height or reveal overflow 234 var mobile_layout = this._isMobileLayout(); 235 if(this.options.affix && mobile_layout > 1) { 236 237 this.target.css('max-height', ''); 238 239 } else { 240 241 this.affix = true; 242 243 var offset = 0; 244 if(this.siblings.length) { 245 this.siblings.each(function(){ 246 if($(this).is(':visible')) offset += $(this).outerHeight(); 247 }); 248 } 249 250 //Set the right vertical offset, this changes as the sidebar collapses in responsive layouts 251 offset += this.options.offset.top + this.options.offset.bottom + this.options.padding.bottom; 252 253 var height = $(window).height() - offset; 254 this.target.css('max-height', Math.max(height, this.options.minHeight)); 255 } 256 257 //To allow listening to height changes 258 this.target.triggerHandler('resize'); 259 }, 260 261 /** 262 * Used to update the height, allowing it to be animated 263 * @param height 264 */ 265 resizeHeight: function(height){ 266 267 }, 268 269 /** 270 * Checks if there's a responsive mobile layout available, and whether it's active 271 * @returns {number} 0 = unavailable, 1 = available but disabled, 2 = enabled 272 * @private 273 */ 274 _isMobileLayout: function(){ 275 276 var result = 0; 277 if($('.subhead-collapse .subhead').length) { 278 result = 1; 279 /** 280 * Top navbar is fixed on desktop layout, static on mobile and tablet 281 * NOTE: Hacky but thanks to how the subhead js logic in j!3.0 works we need to do it this way 282 */ 283 var test = $('<div/>', {'class': 'subhead subhead-fixed'}).appendTo(document.body); 284 if(test.css('position') != 'fixed') { 285 result = 2; 286 } 287 test.remove(); 288 } 289 290 return result; 291 } 292 }; 293}(window.kQuery));
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.