1"use strict"; 2(function ($) { 3 $.fn.tabSlideOut = function (callerSettings) { 4 5 /** 6 * @param node Element to get the height of. 7 * @return string e.g. '123px' 8 */ 9 function heightAsString(node) { 10 return parseInt(node.outerHeight() + 1, 10) + 'px'; 11 } 12 /** 13 * @param node Element to get the width of. 14 * @return string e.g. '123px' 15 */ 16 function widthAsString(node) { 17 return parseInt(node.outerWidth() + 1, 10) + 'px'; 18 } 19 20 /* 21 * Get the width of the given border, in pixels. 22 * 23 * @param node element 24 * @param string edge 25 * @returns int 26 */ 27 function borderWidth(element, edge) { 28 return parseInt(element.css('border-' + edge + '-width'), 10); 29 } 30 31 /** 32 * Return the desired height of the panel to maintain both offsets. 33 */ 34 function calculatePanelSize() { 35 var available = $(window).height(); 36 if (edge === 'top' || edge === 'bottom') { 37 available = $(window).width(); 38 } 39 return available - parseInt(settings.otherOffset) - parseInt(settings.offset); 40 } 41 42 var panel = this; 43 44 /** 45 * True if the tab is open. 46 * 47 * @returns boolean 48 */ 49 function isOpen() { 50 return panel.hasClass('ui-slideouttab-open'); 51 } 52 53 if (typeof callerSettings == 'string') 54 { 55 // param is a string, use command mode 56 switch (callerSettings) 57 { 58 case 'open': 59 this.trigger('open'); 60 return this; 61 case 'close': 62 this.trigger('close'); 63 return this; 64 case 'isOpen': 65 return isOpen(); 66 case 'toggle': 67 this.trigger('toggle'); 68 return this; 69 case 'bounce': 70 this.trigger('bounce'); 71 return this; 72 default: 73 throw "Invalid tabSlideOut command"; 74 } 75 } else 76 { 77 // param is an object, it's initialisation mode 78 var settings = $.extend({ 79 tabLocation: 'left', // left, right, top or bottom 80 tabHandle: '.handle', // JQuery selector for the tab, can use any JQuery selector 81 action: 'click', // action which will open the panel, e.g. 'hover' 82 hoverTimeout: 5000, // ms to keep tab open after no longer hovered - only if action = 'hover' 83 offset: '200px', // panel dist from top or left (bottom or right if offsetReverse is true) 84 offsetReverse: false, // if true, panel is offset from right or bottom of window instead of left or top 85 otherOffset: null, // if set, panel size is also set to maintain this dist from bottom or right of view port (top or left if offsetReverse) 86 handleOffset: null, // e.g. '10px'. If null, detects panel border to align handle nicely on edge 87 handleOffsetReverse: false, // if true, handle is offset from right or bottom of panel instead of left or top 88 bounceDistance: '50px', // how far bounce event will move everything 89 bounceTimes: 4, // how many bounces when 'bounce' is called 90 bounceSpeed: 300, // time to animate bounces 91 tabImage: null, // optional image to show in the tab 92 tabImageHeight: null, // optional IE8 and lower only, else autodetected size 93 tabImageWidth: null, // optional IE8 and lower only, else autodetected size 94 onLoadSlideOut: false, // slide out after DOM load 95 clickScreenToClose: true, // close tab when somewhere outside the tab is clicked 96 clickScreenToCloseFilters: ['.ui-slideouttab-panel'], // if click target or parents match any of these, click won't close this tab 97 onOpen: function () {}, // handler called after opening 98 onClose: function () {}, // handler called after closing 99 onSlide: function () {}, // handler called after opening or closing 100 onBeforeOpen: function () { 101 return true; 102 }, // handler called before opening, return false to cancel 103 onBeforeClose: function () { 104 return true; 105 }, // handler called before closing, return false to cancel 106 onBeforeSlide: function () { 107 return true; 108 } // handler called before opening or closing, return false to cancel 109 }, callerSettings || {}); 110 111 var edge = settings.tabLocation; 112 var handle = settings.tabHandle = $(settings.tabHandle, panel); 113 114 panel.addClass('ui-slideouttab-panel') 115 .addClass('ui-slideouttab-' + edge); 116 if (settings.offsetReverse) 117 panel.addClass('ui-slideouttab-panel-reverse'); 118 handle.addClass('ui-slideouttab-handle'); // need this to find it later 119 if (settings.handleOffsetReverse) 120 handle.addClass('ui-slideouttab-handle-reverse'); 121 settings.toggleButton = $(settings.toggleButton); 122 123 // apply an image to the tab if one is defined 124 if (settings.tabImage !== null) { 125 var imageHeight = 0; 126 var imageWidth = 0; 127 if (settings.tabImageHeight !== null && settings.tabImageWidth !== null) { 128 imageHeight = settings.tabImageHeight; 129 imageWidth = settings.tabImageWidth; 130 } else { 131 var img = new Image(); 132 img.src = settings.tabImage; 133 imageHeight = img.naturalHeight;
134 imageWidth = img.naturalWidth; 135 } 136 137 handle.addClass('ui-slideouttab-handle-image'); 138 handle.css({ 139 'background': 'url(' + settings.tabImage + ') no-repeat', 140 'width': imageWidth, 141 'height': imageHeight 142 }); 143 } 144 145 // determine whether panel and handle are positioned from top, bottom, left, or right 146 if (edge === 'top' || edge === 'bottom') { 147 settings.panelOffsetFrom = 148 settings.offsetReverse ? 'right' : 'left'; 149 settings.handleOffsetFrom = 150 settings.handleOffsetReverse ? 'right' : 'left'; 151 } else { 152 settings.panelOffsetFrom = 153 settings.offsetReverse ? 'bottom' : 'top'; 154 settings.handleOffsetFrom = 155 settings.handleOffsetReverse ? 'bottom' : 'top'; 156 } 157 158 /* autodetect the correct offset for the handle using appropriate panel border*/ 159 if (settings.handleOffset === null) { 160 settings.handleOffset = '-' + borderWidth(panel, settings.handleOffsetFrom) + 'px'; 161 } 162 163 if (edge === 'top' || edge === 'bottom') { 164 /* set left or right edges */ 165 panel.css(settings.panelOffsetFrom, settings.offset); 166 handle.css(settings.handleOffsetFrom, settings.handleOffset); 167 168 // possibly drive the panel size 169 if (settings.otherOffset !== null) { 170 panel.css('width', calculatePanelSize() + 'px'); 171 // install resize handler 172 $(window).resize(function () { 173 panel.css('width', calculatePanelSize() + 'px'); 174 }); 175 } 176 177 if (edge === 'top') { 178 handle.css({'bottom': '-' + heightAsString(handle)}); 179 } else { 180 handle.css({'top': '-' + heightAsString(handle)}); 181 } 182 } else { 183 /* set top or bottom edge */ 184 panel.css(settings.panelOffsetFrom, settings.offset); 185 handle.css(settings.handleOffsetFrom, settings.handleOffset); 186 187 // possibly drive the panel size 188 if (settings.otherOffset !== null) { 189 panel.css('height', calculatePanelSize() + 'px'); 190 // install resize handler 191 $(window).resize(function () { 192 panel.css('height', calculatePanelSize() + 'px'); 193 }); 194 } 195 196 if (edge === 'left') { 197 handle.css({'right': '0'}); 198 } else { 199 handle.css({'left': '0'}); 200 } 201 } 202 203 handle.on('click', function (event) { 204 event.preventDefault(); 205 }); 206 settings.toggleButton.on('click', function (event) { 207 event.preventDefault(); 208 }); 209 210 // now everything is set up, add the class which enables CSS tab animation 211 panel.addClass('ui-slideouttab-ready'); 212 213 var close = function () { 214 if (settings.onBeforeSlide() && settings.onBeforeClose()) { 215 panel.removeClass('ui-slideouttab-open').trigger('slideouttabclose'); 216 settings.onSlide(); 217 settings.onClose(); 218 } 219 }; 220 221 var open = function () { 222 if (settings.onBeforeSlide() && settings.onBeforeOpen()) { 223 panel.addClass('ui-slideouttab-open').trigger('slideouttabopen'); 224 settings.onSlide(); 225 settings.onOpen(); 226 } 227 }; 228 229 var toggle = function () { 230 if (isOpen()) { 231 close(); 232 } else { 233 open(); 234 } 235 }; 236 237 // animate the tab in and out when 'bounced' 238 var moveIn = []; 239 moveIn[edge] = '-=' + settings.bounceDistance; 240 var moveOut = []; 241 moveOut[edge] = '+=' + settings.bounceDistance; 242 243 var bounceIn = function () { 244 var temp = panel; 245 for (var i = 0; i < settings.bounceTimes; i++) 246 { 247 temp = temp.animate(moveIn, settings.bounceSpeed) 248 .animate(moveOut, settings.bounceSpeed); 249 } 250 panel.trigger('slideouttabbounce'); 251 }; 252 253 var bounceOut = function () { 254 var temp = panel; 255 for (var i = 0; i < settings.bounceTimes; i++) 256 { 257 temp = temp.animate(moveOut, settings.bounceSpeed) 258 .animate(moveIn, settings.bounceSpeed); 259 } 260 panel.trigger('slideouttabbounce'); 261 }; 262 263 // handle clicks in rest of document to close tabs if they're open 264 if (settings.clickScreenToClose) { 265 // install a click handler to close tab if anywhere outside the tab is clicked, 266 // that isn't filtered out by the configured filters 267 $(document).on('click', function (event) { 268 // first check the tab is open and the click isn't inside it 269 if (isOpen() && !panel[0].contains(event.target)) { 270 // something other than this panel was clicked 271 var clicked = $(event.target); 272 273 // check to see if any filters return true 274 for (var i = 0; i < settings.clickScreenToCloseFilters.length; i++) { 275 var filter = settings.clickScreenToCloseFilters[i]; 276 if (typeof filter === 'string') { 277 // checked clicked element itself, and all parents 278 if (clicked.is(filter) || clicked.parents().is(filter)) { 279 return; // don't close the tab 280 } 281 } else if (typeof filter === 'function') { 282 // call custom filter 283 if (filter.call(panel, event)) 284 return; // don't close the tab 285 } 286 } 287 288 // we haven't returned true from any filter, so close the tab 289 close(); 290 } 291 }); 292 } 293 ; 294 295 //choose which type of action to bind 296 if (settings.action === 'click') { 297 handle.on('click', function (event) { 298 toggle(); 299 }); 300 } else if (settings.action === 'hover') { 301 var timer = null; 302 panel.hover( 303 function () { 304 if (!isOpen()) { 305 open(); 306 } 307 timer = null; // eliminate the timer, ensure we don't close now 308 }, 309 function () { 310 if (isOpen() && timer === null) { 311 timer = setTimeout(function () { 312 if (timer) 313 close(); 314 timer = null; 315 }, settings.hoverTimeout); 316 } 317 }); 318 319 handle.on('click', function (event) { 320 if (isOpen()) { 321 close(); 322 } 323 }); 324 } 325 326 if (settings.onLoadSlideOut) { 327 open(); 328 setTimeout(open, 500); 329 } 330 331 // custom event handlers ------- 332 panel.on('open', function (event) { 333 if (!isOpen()) { 334 open(); 335 } 336 }); 337 panel.on('close', function (event) { 338 if (isOpen()) { 339 close(); 340 } 341 }); 342 panel.on('toggle', function (event) { 343 toggle(); 344 }); 345 panel.on('bounce', function (event) { 346 if (isOpen()) { 347 bounceIn(); 348 } else { 349 bounceOut(); 350 } 351 }); 352 353 } 354 return this; 355 }; 356})(jQuery);
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.