1/*------------------------------------------------------------------------- 2# mod_vertical_menu - Vertical Menu 3# ------------------------------------------------------------------------- 4# @ author Balint Polgarfi 5# @ copyright Copyright (C) 2015 Offlajn.com All Rights Reserved. 6# @ license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL 7# @ website http://www.offlajn.com 8-------------------------------------------------------------------------*/ 9 10;(function($, undefined) { 11 12var Hlpr = { 13 preventDefault: function(e) { 14 e.preventDefault(); 15 }, 16 stopPropagation: function(e) { 17 e.stopPropagation(); 18 }, 19 cancelTransitionEnd: function(e) { 20 if(e.target.tagName != "NAV") e.stopPropagation(); 21 }, 22 loadImage: function(src) { 23 new Image().src = src; 24 }, 25 calcOrigin: function(origin, w, dir) { 26 var o = origin.split(/\s+/); 27 if (o[2] && o[2].indexOf("%") > 0) // convert originZ to px 28 o[2] = parseFloat(o[2]) / 100 * w + "px"; 29 if (dir < 0) { // invert 30 if (o[0].indexOf("%") < 0) 31 o[0] = (parseInt(o[0]) / w * 100).toPrecision(3); 32 o[0] = (parseInt(o[0]) - 50) * dir + 50 + "%"; 33 } 34 return o.join(" "); 35 } 36}; 37 38var Target = { 39 hide: function() { 40 this.target.style.display = "none"; 41 }, 42 remove: function() { 43 this.target.parentNode.removeChild(this.target); 44 }, 45 scrollUp: function() { 46 $(this.target.children[0]).scrollTop(0); 47 this.target.style.display = "none"; 48 }, 49 autoMaxWidth: function() { 50 this.target.attributes["class"].value = "sm-title"; 51 this.target.style.maxWidth = ""; 52 }, 53 autoHeight: function() { 54 this.target.style.height = ""; 55 } 56}; 57 58// calc scrollWidth 59$(function() { 60 var outer = document.createElement("div"); 61 outer.style.visibility = "hidden"; 62 outer.style.width = "100px"; 63 document.body.appendChild(outer); 64 var widthNoScroll = outer.offsetWidth; 65 outer.style.overflow = "scroll"; 66 var inner = document.createElement("div"); 67 inner.style.width = "100%"; 68 outer.appendChild(inner); 69 var widthWithScroll = inner.offsetWidth; 70 outer.parentNode.removeChild(outer); 71 72 Hlpr.scrollWidth = widthNoScroll - widthWithScroll; 73}); 74 75smTransform = (function() { 76 var tr, trs = {'transform':0, 'WebkitTransform':0, 'MozTransform':0, 'msTransform':0, 'OTransform':0}; 77 for (tr in trs) if (tr in document.documentElement.style) return tr; 78})(); 79 80smTransition = (function() { 81 var tr, trs = {'transition':0, 'WebkitTransition':0, 'MozTransition':0, 'OTransition':0}; 82 for (tr in trs) if (tr in document.documentElement.style) return tr; 83})(); 84 85smTransitionEnd = smTransition && smTransition + (smTransition[0] == 't' ? 'end' : 'End'); 86 87var $body, 88 $win = $(window), 89 $html = $(document.documentElement), 90 oldIE = navigator.userAgent.match(/MSIE ([6-9])/), 91 backScale = 0.75; 92if (smMobile) $html.addClass('sm-mobile'); 93 94$.fn._center = function(bi) { 95 var x, w, prev; 96 if (bi) 97 prev = this[0].parentNode.children[1] == this[0] ? 0 : $(this[0].parentNode.children[0]).outerWidth(); 98 else 99 prev = this.prev().outerWidth() * backScale || 0; 100 w = this.css("maxWidth", "none").width() + 30; 101 this[0].style.maxWidth = ""; 102 x = Math.floor((this.parent().outerWidth() - w) / 2); 103 return prev > x ? prev : x; 104}; 105 106$.fn.VerticalMenu = function(args) { return args ? new VerticalSlideMenu(args) : this.eq(0).data("VerticalMenu") }; 107 108( VerticalSlideMenu = function(o) {this.init(o)} ).prototype = { 109 $drop: $(), 110 minSwipe: 2, 111 titleWidth: "66%", 112 fullClass: "sm-full-", 113 openClass: "sm-open-", 114 closeClass: "sm-close", 115 effect: 1, // [1 - 14] 116 effectEx: [1, 6, 9, 11, 12], 117 popupDur: 0.6, 118 baseCSS: { 119 x: 0, y: 0, 120 opacity: 1, 121 rotationX: 0, 122 rotationY: 0, 123 rotationZ: 0, 124 skewX: 0, scaleX: 1, 125 skewY: 0, scaleY: 1 126 }, 127 128 init: function(obj) { 129 $.extend(this, obj); 130 $body = $body || $(document.body); 131 this.$node = $('#off-menu_'+this.id).data("VerticalMenu", this); 132 this.$parent = this.$node.parent().addClass("sm-parent"); 133 this.$head = this.$node.find(".sm-head"); 134 this.$back = this.$head.find(".sm-back"); 135 this.$title = this.$head.children(":last");
136 this.$lvls = this.$node.find(".sm-levels"); 137 this.$filter = this.$node.find(".sm-filter").attr("value", ""); 138 this.$dt = this.$lvls.find("dt.parent, dt.notparent"); 139 this.fullClass += this.id; 140 this.openClass += this.id; 141 this.menuPadding = parseInt(this.$lvls.children(':first').css('paddingLeft')); 142 this.bindUpdateScrollbar = smMobile ? undefined : this.updateScrollbar.bind(this, 0); 143 144 this.dropmenu = this.navtype == 'drop'; 145 this.accordion = this.navtype == 'accordion'; 146 this.treemenu = this.navtype == 'tree' || this.accordion; 147 this.expand = this.navtype == 'expand' || this.treemenu; 148 149 if (this.overlay && !this.expand) { // override menu type 150 this.dropmenu = 0; 151 this.expand = 1; 152 this.treemenu = this.navtype != 'expand'; 153 } 154 if ((this.treemenu || this.expand) && !this.$filter.length) this.backItem = ''; 155 if (this.popup || this.overlay) this.sidebarUnder = 0; 156 if (this.treemenu) 157 this.$node.addClass("sm-tree").on("click.sm touchend.sm", "dt.parent", $.proxy(this, "onClickTree")); 158 this.build(); 159 this.onResize(); 160 if (!this.sidebar && this.winWidth >= this.sidebarUnder) this.$lvls.height(''); // height fix for webkit 161 if (this.filterMinChar < 1) this.filterMinChar = 1; 162 163 this.bg = this[this.overlay ? "$overlay" : "$node"].css("backgroundImage").match(/url\(['"]?(.+?)['"]?\)/i); 164 165 if (this.popup || this.sidebar || this.overlay || this.winWidth < this.sidebarUnder) { 166 // only make the autoopen work if the menu is not in module position 167 var w = $(window).width(), ok = true; 168 if (!+this.visibility[4]) { // basic 169 if (w < 768 && !+this.visibility[0]) ok = false; 170 if (w >= 768 && w < 992 && !+this.visibility[1]) ok = false; 171 if (w >= 992 && w < 1200 && !+this.visibility[2]) ok = false; 172 if (w >= 1200 && !+this.visibility[3]) ok = false; 173 } else { // advanced 174 if (this.visibility[5][0] > w || this.visibility[6][0] < w) ok = false; 175 } 176 if (ok) 177 if (this.autoOpen == 1 && window.sessionStorage && !sessionStorage.smAutoOpen) { 178 sessionStorage.smAutoOpen = 1; 179 $win.load($.proxy(this, this.popup ? "openPopup" : "openMenu")); 180 } else if (this.autoOpen > 1) { 181 $win.load($.proxy(this, this.popup ? "openPopup" : "openMenu")); 182 } 183 } 184 185 // add events 186 if (this.parentHref) // don't slide to submenu 187 this.$node.on("click.sm touchend.sm", "dt.parent a", $.proxy(this, "onRedirect")); 188 else // disable redirection when pointer-events:none isn't supported 189 this.$node.on("click.sm", "dl:not(.sm-result) dt.parent a", Hlpr.preventDefault); 190 this.$node 191 .on("click.sm touchend.sm", this.expand && !this.treemenu ? "dt" : ".notparent", $.proxy(this, "onRedirect")) 192 .on("click.sm touchend.sm", ".sm-back, .sm-back-item", $.proxy(this, "onBack")) 193 .on("click.sm touchend.sm", ".sm-reset", $.proxy(this, "onResetFilter")) 194 .on("click.sm", Hlpr.stopPropagation); 195 if (!this.expand) this.$node.on("click.sm touchend.sm", "dt.parent", $.proxy(this, "onOpen")); 196 this.$filter 197 .on("keydown.sm", function disableTab(e) {if (e.keyCode == 9) e.currentTarget.blur()}) 198 .on("keyup.sm", $.proxy(this, "onFilter")); 199 this.$button.on("click.sm touchstart.sm", $.proxy(this, "onClickButton")); // touchend causes problems on scroll 200 this.$lvls 201 .on("touchmove.sm", $.proxy(this, "onTouchMove")) 202 .on("touchend.sm touchcancel.sm", $.proxy(this, "onTouchEnd")) 203 .on("mousedown.sm", $.proxy(this, "onMouseDown")); 204 $win 205 .on("resize.sm", $.proxy(this, "onResize")) 206 .on("keyup.sm", $.proxy(this, "onEsc")); 207 if (this.bg) $win.on("load.sm", Hlpr.loadImage.bind(0, this.bg[1])); 208 $body.one("touchend.sm", $.proxy(this, "touchOptimize")); 209 }, 210 211 touchOptimize: function() { 212 this.$node 213 .off("click.sm", "dt.parent") 214 .off("click.sm", "dt") 215 .off("click.sm", ".notparent") 216 .off("click.sm", ".sm-back, .sm-back-item"); 217 if (this.dropmenu) 218 this.$drop.off("click.sm", "dt"); 219 }, 220 221 build: function() { 222 // build menu icon 223 this.$button = $('<div class="menu-icon-cont sm-btn-'+this.id+'">') 224 .html('<div class="menu-icon3"><span></span><span></span><span></span></div>'); 225 226 if (this.dropmenu) { 227 this.anim.inRotationY = this.anim.inCSS.rotationY; 228 this.anim.outRotationY = this.anim.outCSS.rotationY;
229 this.miRotationY = this.miCSS.rotationY; 230 this.$drop = $('<nav>').css({ 231 position: 'absolute', 232 left: 0, right: 0, 233 top: 0, zIndex: 999 234 }).addClass("sm-drop off-menu_"+this.id) 235 .appendTo($body) 236 .on("click.sm touchend.sm", "dt", $.proxy(this, "onRedirect")) 237 } 238 239 //add logo link 240 var link = this.logoUrl; 241 if (link) $(".sm-logo img").css("cursor", "pointer").click(function() { 242 document.location.href = link; 243 }); 244 245 if (this.popup) { // POPUP 246 this.initPopup(); 247 } else if (this.sidebar || this.sidebarUnder) { // SIDEBAR 248 this.initContainer(); 249 this.initSidebar(); 250 } else if (this.overlay) { // OVERLAY 251 this.initContainer(); 252 this.initOverlay(); 253 } 254 255 // build submenus 256 var $div = this.$lvls.find(".sm-level"); 257 $div.push( // add level for search results 258 $('<div class="sm-level level2"><dl class="sm-result level2">') 259 .css('display', 'none').appendTo(this.$lvls)[0]); 260 this.opened = $div[0]; 261 this.mainmenu = this.opened; 262 if (this.treemenu) this.$lvls.find('dd.opened').css('display', 'block'); // init tree/accordion animation 263 if (this.backItem) { 264 var $backItem = $("dt:first", $div[0]).clone().removeClass("parent notparent active").addClass("sm-back-item"); 265 $backItem.find("a").removeAttr("href").html(this.backItem); 266 $backItem.find(".desc, .sm-icon, .productnum").remove(); 267 } 268 if (!this.expand) { 269 var level, div, i; 270 for (i = 1; i < $div.length; i++) { 271 if (this.backItem && (!this.dropmenu || i == $div.length - 1)) // if drop, add only for search results 272 $backItem.clone().prependTo($div[i].children[0]); // add back menu-item to sublevels 273 div = $div[i]; 274 div.style.display = "none"; 275 div.parent = $(div).parents(".sm-level")[0]; 276 div.parentItem = $(div.parentNode).prev()[0]; 277 if (div.parentNode.tagName == "DD") 278 $(div.parentNode).prev()[0].menu = div; 279 } 280 } 281 this.$result = this.$lvls.children(":last"); 282 if (this.expand && this.backItem) $backItem.clone().prependTo(this.$result[0].children[0]); // add back to search result 283 }, 284 285 initPopup: function() { 286 var $clone = this.$button.clone() 287 .css(smTransform, "translateX(-100%)") 288 .css("zIndex", -1).appendTo(this.$node); 289 this.$node.css({ 290 display: "block", position: "absolute", 291 visibility: "hidden", opacity: 0, 292 left: 0, top: 0, 293 width: this.width, 294 margin: 0, zIndex: 99999, 295 WebkitTransition: "none", MozTransition: "none", msTransition: "none", transition: "none" 296 }).addClass("sm-popup"); 297 if (this.menuIconCorner) { // button in corner 298 this.$node.appendTo(this.$button); 299 this.$button.appendTo($body); 300 } else { // button in module position 301 this.$node.appendTo($body); 302 this.$button.appendTo(this.$parent); 303 } 304 this.$button.push($clone[0]); 305 }, 306 307 initContainer: function() { 308 this.htmlCSS = { 309 background: $html.css("backgroundColor")+" "+$html.css("backgroundImage")+" "+$html.css("backgroundRepeat")+" "+ 310 $html.css("backgroundAttachment")+" "+$html.css("backgroundPosition")+" / "+$html.css("backgroundSize") 311 }; 312 this.bodyCSS = { 313 overflowY : $body.css("overflowY"), 314 borderTop: $body.css("borderTopWidth")+" "+$body.css("borderTopStyle")+" "+$body.css("borderTopColor"), 315 borderBottom: $body.css("borderBottomWidth")+" "+$body.css("borderBottomStyle")+" "+$body.css("borderBottomColor"), 316 borderLeft: $body.css("borderLeftWidth")+" "+$body.css("borderLeftStyle")+" "+$body.css("borderLeftColor"), 317 borderRight: $body.css("borderRightWidth")+" "+$body.css("borderRightStyle")+" "+$body.css("borderRightColor"), 318 padding: $body.css("paddingTop")+" "+$body.css("paddingRight")+" "+$body.css("paddingBottom")+" "+$body.css("paddingLeft"), 319 background: $body.css("backgroundColor")+" "+$body.css("backgroundImage")+" "+$body.css("backgroundRepeat")+" "+ 320 $body.css("backgroundAttachment")+" "+$body.css("backgroundPosition")+" / "+$body.css("backgroundSize") 321 }; 322 323 this.$cont = $body.addClass("sm-container"); 324 this.$pusher = $(".sm-pusher"); 325 this.$content = this.$pusher.children();
326 this.$inner = this.$content.children(".sm-content-inner"); 327 328 $html.css('overflow-y', 'auto'); 329 }, 330 331 initSidebar: function() { 332 if (this.sidebar) { 333 this.$button.css("display", ""); 334 this.$node.appendTo(this.$cont); 335 } 336 this.$cont.on("click.sm touchstart.sm", $.proxy(this, "closeMenu")); 337 // disable page scrolling when sidebar is open 338 this.$lvls.on("touchstart.sm", $.proxy(this, "scrollFixStart")); 339 this.$cont.on("touchmove.sm", $.proxy(this, "scrollFixMove")); 340 341 // TransitionEnd fix 342 this.$node.on(smTransitionEnd, Hlpr.cancelTransitionEnd); 343 this.$inner.on(smTransitionEnd, Hlpr.cancelTransitionEnd); 344 345 if (this.menuIconCorner) { 346 this.$button.appendTo(this.$inner); 347 } else { 348 this.$button.appendTo(this.$parent); 349 this.$button.push(this.$button.clone().css("opacity", 0).appendTo(this.$node)[0]); 350 } 351 if (!this.sidebar) this.$button.css("display", "none"); 352 }, 353 354 initOverlay: function() { 355 var $overlay = $('<div>').addClass("sm-overlay-"+this.id).appendTo($body); 356 this.$overlay = $('<div>').addClass("sm-overlay-win").appendTo($overlay) 357 .on("click.sm "+smTransitionEnd, Hlpr.stopPropagation) // don't close overlay on click & TransitionEnd fix 358 this.$node.appendTo(this.$overlay); 359 this.$cont.on("click.sm touchstart.sm", $.proxy(this, "closeMenu")); 360 // disable touch-scrolling when sidebar is open 361 this.$lvls.on("touchstart.sm", $.proxy(this, "scrollFixStart")); 362 this.$cont.on("touchmove.sm", $.proxy(this, "scrollFixMove")); 363 364 if (this.menuIconCorner) { 365 this.$button.appendTo($body); 366 } else { 367 this.$button.appendTo(this.$parent); 368 this.$button.push(this.$button.clone().css("opacity", 0).insertBefore(this.$node)[0]); 369 } 370 }, 371 372 scrollFixStart: function(e) { 373 this.touchstartY = e.originalEvent.touches[0].clientY; 374 }, 375 376 scrollFixMove: function(e) { 377 if (!this.$cont.hasClass(this.openClass)) return; 378 else if (!$(e.target).closest('.sm-levels').length) return e.preventDefault(); 379 380 var node = this.opened.children[0]; 381 if (this.touchstartY < e.originalEvent.touches[0].clientY) { // on scroll up 382 if (node.scrollTop == 0) e.preventDefault(); 383 } else { // on scroll down 384 if (node.scrollTop == node.scrollHeight - node.offsetHeight) e.preventDefault(); 385 } 386 }, 387 388 onMouseDown: function(e) { 389 if (e.button == 0) { 390 if (e.target.tagName == "A") e.preventDefault(); 391 $body 392 .on("mousemove.sm", $.proxy(this, "onTouchMove")) 393 .on("mouseup.sm", $.proxy(this, "onMouseUp")); 394 } 395 }, 396 397 onMouseUp: function(e) { 398 if (e.button == 0) { 399 $body.off("mousemove.sm mouseup.sm"); 400 this.onTouchEnd(e); 401 } 402 }, 403 404 onTouchMove: function(e) { 405 if (this.touchEvent == "scroll") return; 406 if (smMobile && smMobile[0] == "Windows Phone") e.preventDefault(); // disable scrolling or swipe back 407 var x = 'pageX' in e ? e.pageX : e.originalEvent.touches[0].pageX, 408 y = 'pageY' in e ? e.pageY : e.originalEvent.touches[0].pageY; 409 if (this.touchStartX === undefined) { 410 // touchstart 411 this.touchTarget = e.target; 412 this.touchStartX = this.touchPrevX = x; 413 this.touchStartY = this.touchPrevY = y; 414 if (!this.opened.parent) this.touchEvent = "scroll"; 415 return; 416 } 417 var diffX = x - this.touchStartX, 418 diffY = y - this.touchStartY; 419 if (this.touchEvent === undefined) { 420 if (Math.abs(diffY) > this.minSwipe) { // vertical swipe 421 this.touchEvent = "scroll"; 422 $body.addClass("sm-scroll"); 423 } else if (diffX > this.minSwipe) { // horizontal swipe 424 if (this.openTL && this.openTL.isActive()) { 425 if (this.openTL.time() < this.dur) return; 426 else this.openTL.pause(); 427 } 428 this.touchEvent = "back"; 429 if (!smMobile) $(this.opened.children).perfectScrollbar("destroy"); 430 this.opened.parent.style.display = "block"; 431 this.initBackTimeline(); 432 TweenLite.set(this.$lvls[0], {perspective: this.perspective}); // blur fix for retina 433 this.nodeW = this.$lvls.outerWidth(); 434 } 435 } 436 if (this.touchEvent == "back") { 437 e.preventDefault(); // disable scrolling 438 diffX -= this.minSwipe; 439 440 if (diffX <= 1) diffX = 0.1; 441 if (diffX >= this.nodeW) diffX = this.nodeW - 0.1; 442 this.backTL.seek(this.dur * diffX / this.nodeW); 443 444 this.touchDirLeft = this.touchPrevX < x; 445 this.touchDirTop = this.touchPrevY < y; 446 if (this.touchPrevX != x) this.touchPrevX = x;
447 if (this.touchPrevY != y) this.touchPrevY = y; 448 } 449 }, 450 451 onTouchEnd: function(e) { 452 var touchEvent = this.touchEvent; 453 delete this.touchEvent; 454 delete this.touchStartX; 455 456 if (!touchEvent) return; 457 e.preventDefault(); 458 e.stopPropagation(); 459 460 if (touchEvent == "scroll") { 461 $body.removeClass("sm-scroll"); 462 } else if (touchEvent == "back") { 463 // disable click when swipe finished on the same menu-item where it started 464 if (this.touchTarget == e.target) this.disableClick = true; 465 if (this.touchDirLeft) { 466 this.back(); 467 } else { 468 if (!smMobile) $(this.opened.children).perfectScrollbar(); 469 this.backTL.reverse(); 470 } 471 } 472 }, 473 474 onEsc: function(e) { 475 if (e.keyCode == 27 && !this.$button.eq(1).hasClass("sm-hide")) { 476 if (!this.popup) 477 e.stopPropagation(), this.closeMenu(); 478 else if (this.$node.css("visibility") == "visible") 479 e.stopPropagation(), this.closePopup(); 480 } 481 }, 482 483 onClickButton: function(e) { 484 e.stopPropagation(); 485 e.preventDefault(); 486 if (this.$button.hasClass("sm-hide")) { 487 this.$button[0]._gsTransform.x = this.menuIconX; 488 this.$button.css(smTransform, '').removeClass("sm-hide"); 489 return; 490 } 491 if (this.popup) { // POPUP 492 if (this.$node.css("visibility") == "hidden") { 493 this.openPopup(); 494 } else { 495 if (e.currentTarget == this.$button[0]) return; // don't close menu for any click 496 this.closePopup(); 497 } 498 } else { // SIDEBAR || OVERLAY 499 if ($(e.currentTarget).hasClass(this.closeClass)) this.closeMenu(); 500 else this.openMenu(); 501 } 502 }, 503 504 openPopup: function() { 505 var bw = this.$button.width(), 506 bh = this.$button.height(), 507 w = this.$node.width(), 508 h = this.$node.height(); 509 this.$node.css("visibility", "visible"); 510 if (this.menuIconCorner) { // fixed position 511 TweenLite.set(this.$node[0], {transformOrigin: "0% 0% 0"}); 512 } else { // module position 513 this.onResize(); 514 } 515 var tl = new TimelineLite({paused: true, autoRemoveChildren: true}); 516 tl.add(TweenLite.fromTo(this.$node[0], 1, {scaleX: bw/w, scaleY: bh/h}, {css: {scaleX: 1, scaleY: 1}, ease: Back.easeOut}), 0); 517 tl.add(TweenLite.to(this.$node[0], 1, {css: {opacity: 1}, onComplete: $.proxy(this.$button.eq(1), "addClass", this.closeClass)}), 0); 518 tl.add(TweenLite.fromTo(this.$button[1], 0.75, {x: -bw, opacity: 1}, {css: {x: 0}}), -0.5); 519 tl.duration(this.popupDur); 520 tl.play(); 521 this.$node.trigger("openMenu", this); 522 }, 523 524 closePopup: function() { 525 var bw = this.$button.width(), 526 bh = this.$button.height(), 527 w = this.$node.width(), 528 h = this.$node.height(); 529 this.$button.removeClass(this.closeClass); 530 var tl = new TimelineLite({paused: true, autoRemoveChildren: true}); 531 tl.add(TweenLite.to(this.$button[1], 0.3, {css: {x: -bw}}), -0.15); 532 tl.add(TweenLite.to(this.$node[0], 0.3, {css: {opacity: 0}, ease: Quad.easeIn}), 0.3); 533 tl.add(TweenLite.to(this.$node[0], 0.3, {css: {scaleX: bw/w, scaleY: bh/h}, onComplete: $.proxy(this.$node, "css", "visibility", "hidden")}), 0.3); 534 tl.play(); 535 this.$node.trigger("closeMenu", this); 536 }, 537 538 openMenu: function(e, effect) { 539 if (this.$cont.hasClass(this.openClass)) return; 540 if (e) e.stopPropagation(); 541 $body.off(smTransitionEnd+".tr").one(smTransitionEnd+".tr", this.overlay ? ".sm-overlay-"+this.id : "", $.proxy(this, "onEndOpenMenu")); 542 543 this.effect = effect || this.effect; 544 this.$cont.addClass("sm-effect-" + this.effect); 545 546 var btn = this.$button.length && (!this.menuIconCorner || this.overlay || $.inArray(this.effect, this.effectEx) >= 0); 547 if (btn && this.menuIconCorner) this.$button.appendTo(this.overlay ? this.$overlay : this.$node); 548 549 this.scroll = $win.scrollTop(); 550 if (smMobile) $win.scrollTop(0).off("resize.sm"); // don't resize during animation on mobile 551 552 this.$cont.css({ position: 'fixed', top: 0, bottom: 0 }); 553 $html.addClass(this.fullClass); 554 this.$inner.css(this.bodyCSS); 555 this.$content.css(this.htmlCSS).scrollTop(this.scroll); 556 557 if (!smMobile) { 558 if (btn && !this.menuIconCorner) { 559 if (!this.overlay) this.$button.eq(1).appendTo($.inArray(this.effect, this.effectEx) >= 0 ? this.$node : this.$inner); 560 this.$button[1].style.display = "inline-block"; 561 } 562 } else { // mobile 563 if (this.$button[1]) this.$button[1].style.display = "block"; 564 } 565 566 if (this.overlay) { 567 this.$lvls.css('maxHeight', ''); 568 } else if (this.sidebar || this.winWidth < this.sidebarUnder) { 569 var vh = this.$cont.outerHeight(); 570 this.$lvls.css('maxHeight', this.effect == 8 ? vh : vh - this.$lvls.position().top);
570 // fix for sidebar effect 8 571 } 572 this.$cont.css("background", this.siteBg).addClass(this.openClass); 573 this.$node.trigger("openMenu", this); 574 if (oldIE) this.onEndOpenMenu(); 575 }, 576 577 onEndOpenMenu: function(e) { 578 if (smMobile) { 579 $win.on("resize.sm", $.proxy(this, "onResize")); // allow resize after animation on mobile 580 if (this.sidebar || this.winWidth < this.sidebarUnder) // fix for sidebar bottom can't be see 581 this.$lvls.css('maxHeight', this.$cont.outerHeight() - this.$lvls.position().top); 582 } 583 if (this.menuIconCorner) 584 setTimeout($.proxy(this.$button, "addClass", this.closeClass), 1); 585 else { 586 this.$button[0].style.opacity = 0; 587 this.$button[1].style.opacity = 1; 588 this.$button.eq(1).addClass(this.closeClass); 589 } 590 if (this.overlay) // calculate overlay max-height after transition 591 this.$lvls.css("maxHeight", this.$overlay.outerHeight() - this.$lvls.position().top); 592 else if (this.effect == 8) // fix for sidebar effect 8 593 this.$lvls.css('maxHeight', this.$cont.outerHeight() - this.$lvls.position().top); 594 this.$node.css("zIndex", 99); 595 this.updateScrollbar(); 596 }, 597 598 closeMenu: function(e) { 599 if (e && $(e.target).parents(".sm-menu").length) return; 600 if (!this.$cont) return; 601 if (!this.$cont.hasClass(this.openClass)) return; 602 $body.off(smTransitionEnd+".tr").one(smTransitionEnd+".tr", this.overlay ? ".sm-overlay-"+this.id : "", $.proxy(this, "onEndCloseMenu")); 603 if (!this.menuIconCorner) { 604 this.$button[1].style.display = "none"; 605 this.$button[1].style.opacity = 0; 606 } 607 if (smMobile) this.$filter.blur(); 608 this.$cont.removeClass(this.openClass); 609 this.$node.css("zIndex", "").trigger("closeMenu", this); 610 if (oldIE) this.onEndCloseMenu(); 611 }, 612 613 onEndCloseMenu: function(e) { 614 var s = this.$inner[0].style; 615 s.position = s.background = s.border = s.padding = s.margin = ""; 616 $body[0].style.background = $body[0].style.position = $body[0].style.top = $body[0].style.bottom = ""; 617 this.$content.css({height: '', background: ''}); 618 $html.removeClass(this.fullClass); 619 //$html.css("overflowY", ""); 620 if (smMobile) this.$node.css({top: "", position: ""}); 621 $win.scrollTop(this.scroll); 622 this.$cont.removeClass("sm-effect-" + this.effect); 623 624 if (this.$button.length) { 625 if ((!this.menuIconCorner || this.overlay || $.inArray(this.effect, this.effectEx) >= 0)) { 626 if (this.menuIconCorner) this.$button.appendTo(this.$inner); 627 else this.$button[0].style.opacity = 1; 628 setTimeout($.proxy(this.$button, "removeClass", this.closeClass), 1); 629 } 630 else this.$button.removeClass(this.closeClass); 631 } 632 }, 633 634 onResize: function(e) { 635 var isInCont = this.$node[0].parentNode != this.$parent[0], 636 $title = this.$title.last(); 637 this.winWidth = $win.width(); 638 this.winHeight = $win.height(); 639 // update button 640 if (!this.sidebar && this.winWidth < this.sidebarUnder && !isInCont) { 641 this.$button.css("display", ""); 642 this.$node 643 .appendTo(this.$cont) 644 .trigger("moveToSidebar", this); 645 } 646 647 // update title position (don't update on init) 648 if (e && $title[0]) TweenLite.set($title[0], {x: $title._center(this.$back.length)}); 649 650 // update dropmenu 651 var drop = this.drop; 652 this.drop = this.dropmenu && !smMobile && this.winWidth >= this.sidebarUnder; 653 if (drop != this.drop) { 654 if (this.drop) { 655 if (this.$head.length) { 656 this.$title.filter(":not(:first)").remove(); 657 this.$title.length = 1; 658 TweenLite.set(this.$title[0], {css: {scale:1, x:this.$title.attr("class", "sm-title")._center(this.$back.length)}}); 659 } 660 this.$lvls.children().attr("style", "display: none;"); 661 this.opened = this.$lvls.children(":first").attr("style", "position: static;")[0]; 662 this.prev = undefined; 663 this.$node 664 .on(this.dropEvent+".dm", "dt.parent", $.proxy(this, "onOpenDrop")) 665 .on(this.dropEvent+".dm", ">.sm-level", $.proxy(this, "onMouseEnterDrop")); 666 this.$drop 667 .on(this.dropEvent+".dm", "dt.parent", $.proxy(this, "onOpenDrop")) 668 .on(this.dropEvent+".dm", ".sm-level", $.proxy(this, "onMouseEnterDrop")); 669 if (this.dropEvent == "click") { 670 $body.on("click.dm", $.proxy(this, "closeAllDrops")); 671 } else { 672 this.$node 673 .on("mouseleave.dm", "dt.parent", $.proxy(this, "onCloseDrop")) 674 .on("mouseleave.dm", ">.sm-level", $.proxy(this, "onMouseLeaveDrop")); 675 this.$drop 676 .on("mouseleave.dm", "dt.parent", $.proxy(this, "onCloseDrop")) 677 .on("mouseleave.dm", ".sm-level", $.proxy(this, "onMouseLeaveDrop")); 678 } 679 } else { 680 this.$node.off(".dm"); 681 this.$drop.off(".dm");
682 $body.off("click.dm"); 683 } 684 } 685 // update background img pos 686 if (this.bg && this.bgX) { 687 var level = this.opened.children[0].attributes['class'].value.match(/level(\d)/)[1]; 688 this.$node[0].backgroundPosition = this.bgX * (level - 1) + "% 0"; 689 } 690 691 if (this.popup) { 692 var maxH, mb = navigator.userAgent.match(/iPad/i) ? 25 : 5; 693 if (this.menuIconCorner) { // fixed position 694 var off = this.$lvls.offset(); 695 maxH = (this.winHeight - (off.top - $win.scrollTop()) - mb); 696 this.opened.children[0].style.maxHeight = maxH - 2 * this.menuPadding + "px"; 697 this.$lvls.css("maxHeight", maxH); 698 this.$node.css("maxWidth", this.winWidth - off.left - this.$button.width()); 699 } else if (this.$node.css("visibility") != "hidden") { // module position 700 var btn = this.$button.offset(), 701 top = $win.scrollTop(), 702 originX = "0%"; 703 if (this.winWidth/2 > btn.left || this.popup == 2) { // left 704 this.$node.css({ 705 maxWidth: this.winWidth - btn.left - this.$button.width(), 706 left: btn.left, 707 right: "" 708 }); 709 } else { // right 710 originX = "100%"; 711 this.$node.css({ 712 maxWidth: btn.left, 713 left: "", 714 right: this.winWidth - btn.left - this.$button.width() 715 }); 716 } 717 if (top + this.winHeight/2 > btn.top) { // top 718 TweenLite.set(this.$node[0], {transformOrigin: originX + " 0% 0", scaleX: 1, scaleY: 1}); 719 maxH = this.winHeight - (btn.top - top) - this.$lvls.position().top - mb; 720 this.$node.css({top: btn.top, bottom: ""}); 721 } else { // bottom 722 TweenLite.set(this.$node[0], {transformOrigin: originX + " 100% 0", scaleX: 1, scaleY: 1}); 723 maxH = btn.top - top + this.$button.height() - this.$lvls.position().top; 724 this.$node.css({top: "", bottom: this.winHeight - btn.top - this.$button.height()}); 725 } 726 this.opened.children[0].style.maxHeight = maxH - 2 * this.menuPadding + "px"; 727 this.$lvls.css({maxHeight: maxH, height: $(this.opened.children).height() + 2 * this.menuPadding}); 728 } 729 } else if (this.sidebar || this.sidebarUnder) { 730 // update button & sidebar 731 if (!this.sidebar && this.winWidth >= this.sidebarUnder && isInCont) { 732 this.$button.css("display", "none"); 733 this.$node 734 .css({top: "", position: ""}) // mobile fix 735 .appendTo(this.$parent); 736 if (this.$cont.hasClass(this.openClass)) { 737 this.closeMenu(); 738 this.onEndCloseMenu(); 739 } 740 this.$node.trigger("moveToModulepos", this); 741 } 742 if (this.$node.css("display") == "block") { 743 this.$pusher.addClass("no-trans"); // disable transitions during resize 744 if (this.$pusher[0]) this.$pusher[0].offsetHeight; // trigger a reflow, flushing the CSS changes 745 this.$pusher.removeClass("no-trans"); 746 // update menu height 747 if (this.sidebar || this.winWidth < this.sidebarUnder) 748 this.$lvls.css('maxHeight', this.$cont.outerHeight() - this.$lvls.position().top); 749 else if (!this.treemenu) 750 this.$lvls.height($(this.opened.children).outerHeight() + 2 * this.menuPadding); 751 else 752 this.$lvls[0].style.height = ""; 753 } 754 } else if (this.overlay && $body.hasClass(this.openClass)) { // OVERLAY 755 this.$lvls.css('maxHeight', '').css('maxHeight', this.$overlay.outerHeight() - this.$lvls.position().top); 756 } 757 758 this.updateScrollbar(); 759 }, 760 761 onFilter: function(e) { 762 this.$filter.attr('value', this.$filter.val()); 763 if (!e.target.value.length && $(this.opened.children).hasClass("sm-result")) this.onBack(); 764 if (this.filterTimeout) this.filterTimeout = clearTimeout(this.filterTimeout); 765 if (e.target.value.length < this.filterMinChar) return; 766 this.filterTimeout = setTimeout($.proxy(this, "filter", e.target.value), this.filterDelay); 767 }, 768 769 filter: function(keyword) { 770 keyword = keyword.trim().replace(/\s+/g, " ").replace(/([.?*+^$|{}()\\[\]])/g, "\\$1"); 771 if (this.keyword == keyword) return; 772 if (!this.keyword) this.filterParent = this.opened; 773 this.keyword = keyword; 774 this.$filter.trigger("filter", [this, keyword]); 775 var i, $dt, 776 $result = this.$result.clone().appendTo(this.$lvls).children(), 777 submenu = $result[0].parentNode; 778 for (i = 0; i < this.$dt.length; i++) { 779 $dt = $(this.$dt[i]); 780 if ($dt.text().match( new RegExp(this.keyword, "i") )) { 781 var $clone = $dt.clone().removeClass("parent").addClass("notparent"); 782 $clone[0].innerHTML = $clone[0].innerHTML.replace(new RegExp(">([^<]*)("+this.keyword+")([^>]*)<", "ig"), ">$1<strong>$2</strong>$3<"); 783 $clone.appendTo($result); 784 } 785 } 786 var res = $result[0].children.length; 787 if (this.backItem && res == 1 || !res) { 788 var $no = $(this.opened).find("dt:first").clone() 789 .removeClass("parent opened").addClass("notparent").css("pointerEvents", "none"); 790 $no.find("a").removeAttr("href").html(this.noResult); 791 $no.find(".desc, .sm-icon").remove(); 792 $no.appendTo($result); 793 } 794 submenu.parent = this.filterParent; 795 this.open(this.result, submenu); 796 }, 797 798 onRedirect: function(e) { 799 e.stopPropagation(); 800 if (this.disableClick) return e.preventDefault(); // disable click during swipe 801 var $a = e.currentTarget.tagName == "A" ? $(e.currentTarget) : $("a", e.currentTarget), 802 a = $a[0], $node, 803 event = $.Event("openMenuItem"); 804 $a.trigger(event, this); 805 if (event.isDefaultPrevented()) return e.preventDefault(); 806 try { 807 var s = $a.attr("href").replace(/\[(\d+)\]/, ":eq($1)");
808 $node = $(s.replace(/^\//, "").replace("#top", "body")); 809 } catch (ex) {} 810 if ($node && $node.length) { // scroll 811 e.preventDefault(); 812 var $cont, cont, t, b; 813 if (this.$cont && this.$cont.hasClass(this.openClass)) { // sidebar 814 $cont = this.$content; 815 cont = {scroll: $cont.scrollTop()}; 816 t = $node.offset().top + cont.scroll - $cont.offset().top; 817 b = this.$inner.outerHeight() - this.$content.height(); 818 } else { // not sidebar 819 $cont = $win; 820 cont = {scroll: $cont.scrollTop()}; 821 t = $node.offset().top; 822 b = $body.outerHeight() - this.winHeight; 823 } 824 this.scroll = t < b ? t : b; 825 var dur = 0.4 + Math.abs(cont.scroll - this.scroll) / 5000; 826 TweenLite.to(cont, dur, { 827 scroll: this.scroll, 828 onUpdate: function onUpdateScroll() { $cont.scrollTop(cont.scroll) }, 829 onComplete: this.popup && this.menuIconCorner && this.winWidth < this.hidePopupUnder ? function onEndScroll() { 830 if (!this.$button.eq(1).hasClass(this.closeClass)) return; 831 TweenLite.set(this.$button[0], { 832 x: this.menuIconX - this.$node.width(), 833 y: this.menuIconY 834 }); 835 this.$button.eq(1).addClass("sm-hide"); 836 if (!smMobile) this.$node.one("mouseenter", $.proxy(this, "onClickButton")); 837 }.bind(this) : undefined 838 }); 839 } else { // open url 840 if (!(smMobile && this.popup)) // fix for mobile popup menu-item opening 841 if (a == e.target.parentNode || a == e.target) return; 842 if (!a.click) { 843 var event = document.createEvent("HTMLEvents"); 844 event.initEvent("click", false, true); 845 a.dispatchEvent(event); 846 } else a.click(); 847 } 848 }, 849 850 onOpenDrop: function(e) { 851 if (this.sidebar && !$body.hasClass(this.openClass)) return; 852 var item = e.currentTarget, 853 openTween = item.parentNode.parentNode.openTween, 854 closeTween = item.parentNode.parentNode.closeTween, 855 items = item.parentNode.children, i; 856 for (i = 0; i < items.length; i++) 857 if (items[i] != item && items[i].menu && items[i].menu.style.display == "block") 858 { this.closeDrop(items[i].menu); break; } 859 item.menu.closeTimeout = clearTimeout(item.menu.closeTimeout); 860 if (openTween && openTween.isActive()) 861 openTween.vars.onComplete = $.proxy(this, "openDrop", item); 862 else if (closeTween && closeTween.isActive()) 863 closeTween.vars.onReverseComplete = $.proxy(this, "openDrop", item); 864 else 865 this.openDrop(item); 866 }, 867 868 onCloseDrop: function(e) { 869 var item = e.currentTarget, 870 openTween = item.parentNode.parentNode.openTween, 871 closeTween = item.parentNode.parentNode.closeTween; 872 if (openTween && openTween.vars.onComplete) 873 delete openTween.vars.onComplete; 874 else if (closeTween && closeTween.vars.onReverseComplete) 875 delete closeTween.vars.onReverseComplete; 876 else 877 item.menu.closeTimeout = setTimeout($.proxy(this, "closeDrop", item.menu), this.anim.outDur * 500 || 200); 878 }, 879 880 onMouseEnterDrop: function(e) { 881 if (this.sidebar && !$body.hasClass(this.openClass)) return; 882 var menu = e.currentTarget, 883 item = menu.parentItem; 884 menu.style.zIndex = 99; 885 do { 886 if (menu.closeTween && menu.closeTween.isActive()) menu.closeTween.reverse(); 887 menu.closeTimeout = clearTimeout(menu.closeTimeout); 888 menu = menu.parent; 889 $(item).addClass("hover"); 890 item = menu.parentItem; 891 } while ("closeTimeout" in menu); 892 }, 893 894 onMouseLeaveDrop: function(e) { 895 var menu = e.currentTarget, 896 item = menu.parentItem, 897 items = menu.children[0].children, 898 i = items.length, t = 1; 899 while (i--) 900 if (items[i].menu && items[i].menu.closeTimeout) {t++; break} 901 do { 902 menu.closeTimeout = setTimeout($.proxy(this, "closeDrop", menu), (this.anim.outDur * 500 || 200) * t++); 903 menu = menu.parent; 904 $(item).removeClass("hover"); 905 item = menu.parentItem; 906 } while ("closeTimeout" in menu); 907 }, 908 909 closeAllDrops: function() { 910 var $menu = this[this.sidebar ? "$node" : "$drop"].children(".sm-level[style*=block]:last"); 911 if ($menu.length) this.onMouseLeaveDrop({currentTarget: $menu[0]}); 912 }, 913 914 openDrop: function(item) { 915 var submenu = item.menu, 916 openTween = item.parentNode.parentNode.openTween, 917 closeTween = item.parentNode.parentNode.closeTween; 918 if (openTween) delete openTween.vars.onComplete; 919 if (closeTween) delete closeTween.vars.onReverseComplete; 920 // replace nodes to be on top (zIndex)
921 if (this.sidebar && submenu.parentNode != this.$node[0]) 922 $(submenu).appendTo(this.$node); 923 if (!this.sidebar && submenu.parentNode != this.$drop[0]) 924 $(submenu).appendTo(this.$drop); 925 926 var p = $(item).offset(), 927 w = $(item).outerWidth(), 928 h = $(submenu).outerHeight(), 929 t = $win.scrollTop(), 930 m = t + this.winHeight - p.top - h; 931 if (submenu.parent.parentNode == this.$lvls[0]) 932 this.dropdir = p.left + w/2 - this.winWidth/2 < 0 ? 1 : -1; 933 934 if (this.dropdir < 0) { 935 p.right = $win.width() - p.left; // don't use this.winWidth 936 if (this.sidebar && p.right < this.width) p.right = this.width - this.menuPadding; 937 submenu.style.right = p.right + this.menuPadding + this.dropspace + "px"; 938 submenu.style.left = ""; 939 } else { 940 if (p.left < 0) p.left = 0; 941 submenu.style.left = w + p.left + this.menuPadding + this.dropspace + "px"; 942 submenu.style.right = ""; 943 } 944 945 if (this.dropFullHeight) { 946 p.top = t; 947 submenu.style.height = "100vh"; 948 } else if (m < 0) { // out of screen 949 var ih = $(item).outerHeight(), y = p.top; 950 p.top += Math.floor(m / ih) * ih; 951 if (p.top + h <= y) p.top += ih; 952 if (p.top < t) p.top = t; 953 if (h >= this.winHeight) 954 submenu.children[0].style.height = "100vh"; 955 else 956 submenu.children[0].style.height = ""; 957 } 958 submenu.style.top = p.top - (this.dropFullHeight ? 0 : this.menuPadding) + "px"; 959 submenu.style.zIndex = 99; 960 961 this.anim.inCSS.x = this.anim.inUnitX == "%" ? this.anim.inX * this.dropwidth / 100 : this.anim.inX; 962 this.anim.inCSS.x *= this.dropdir; 963 this.anim.inCSS.rotationY = this.dropdir * this.anim.inRotationY; 964 TweenLite.set(submenu, { 965 transformPerspective: this.anim.perspective, 966 transformOrigin: Hlpr.calcOrigin(this.anim.inOrigin, this.dropwidth, this.dropdir) 967 }); 968 var animTo = { 969 overwrite: 1, 970 css: this.baseCSS, 971 ease: this.anim.inEase 972 }; 973 if (submenu.style.display == "none") { 974 submenu.openTween = TweenLite.fromTo(submenu, this.anim.inDur, {css: this.anim.inCSS}, animTo); 975 // menu-item anim 976 if (this.miAnim) { 977 this.miCSS.x = this.miUnitX == "%" ? this.miX * w / 100 : this.miX; 978 this.miCSS.x *= this.dropdir; 979 this.miCSS.rotationY = this.miRotationY * this.dropdir; 980 if (this.miShift) 981 TweenMax.staggerFromTo($(">dl>dt", submenu), this.miDur, {css: this.miCSS}, {overwrite: 1, css: this.baseCSS, ease: this.miEase}, this.miShift); 982 else 983 TweenLite.fromTo(submenu.children[0], this.miDur, {css: this.miCSS}, {overwrite: 1, css: this.baseCSS, ease: this.miEase}); 984 } 985 // icons anim 986 if (this.iconAnim && !smMobile) 987 TweenLite.fromTo($(".sm-icon img", submenu), 0.5, {scale: 0, opacity: 0}, {css: {scale: 1, opacity: 1}, ease: Back.easeOut, delay: 0.66*this.dur}); 988 } else { 989 submenu.openTween = TweenLite.to(submenu, this.anim.inDur, animTo); 990 } 991 992 submenu.style.display = "block"; 993 this.updateScrollbar(submenu); 994 $(item).trigger("openParentItem", this); 995 }, 996 997 closeDrop: function(submenu) { 998 if (submenu.style.display == 'none') return; 999 submenu.style.zIndex = ""; 1000 this.anim.outCSS.x = this.anim.outUnitX == "%" ? this.anim.outX * this.dropwidth / 100 : this.anim.outX; 1001 this.anim.outCSS.rotationY = this.dropdir * this.anim.outRotationY; 1002 TweenLite.set(submenu, {transformOrigin: Hlpr.calcOrigin(this.anim.outOrigin, this.dropwidth, this.dropdir)}); 1003 submenu.closeTween = TweenLite.to(submenu, this.anim.outDur, { 1004 overwrite: 1, 1005 css: this.anim.outCSS, 1006 ease: this.anim.outEase, 1007 onComplete: Target.hide 1008 }); 1009 }, 1010 1011 onClickTree: function(e) { 1012 e.stopPropagation(); 1013 e.preventDefault(); 1014 //if (smMobile && e.type == 'click') return; 1015 var $item = $(e.currentTarget); 1016 this[$item.hasClass("opened") ? "closeTree" : "openTree"]($item); 1017 }, 1018 1019 openTree: function($item) { 1020 var dur = this.dur; 1021 var $dd = $item.addClass("opened").next(); 1022 if (this.popup) this.$lvls.height("auto"); 1023 if (this.miAnim) { 1024 this.miCSS.x = this.miUnitX == "%" ? this.miX * this.$lvls.outerWidth() / 100 : this.miX; 1025 if (this.miShift) 1026 dur = new TimelineLite() 1027 .staggerFromTo($dd.find("dt").not("dd:not(.opened) dt"), this.miDur, {css: this.miCSS}, {overwrite: 1, css: this.baseCSS, ease: this.miEase}, this.miShift) 1028 .totalDuration(); 1029 else 1030 TweenLite.fromTo($dd.find("dl").not("dd:not(.opened) dl"), this.miDur, {css: this.miCSS}, {overwrite: 1, css: this.baseCSS, ease: this.miEase}); 1031 } 1032 if (this.accordion) {
1033 $item.siblings("dt.opened").removeClass("opened"); 1034 $dd.siblings("dd.opened").removeClass("opened").slideUp({ easing: this.outEase, duration: dur * 1000 }); 1035 } 1036 $dd.slideDown({ 1037 queue: false, 1038 easing: this.inEase, 1039 duration: dur * 1000, 1040 progress: this.bindUpdateScrollbar, 1041 complete: function() { $dd.attr('style', 'display: block;') } 1042 }).addClass('opened'); 1043 1044 $item.trigger("openParentItem", this); 1045 }, 1046 1047 closeTree: function($item) { 1048 var $dd = $item.removeClass("opened").next(); 1049 $dd.removeClass('opened').slideUp({ 1050 queue: false, 1051 easing: this.outEase, 1052 duration: this.dur * 1000, 1053 progress: this.bindUpdateScrollbar, 1054 complete: function() { $dd.attr('style', '') } 1055 }); 1056 }, 1057 1058 onOpen: function(e) { 1059 if (this.drop) return; 1060 if (e.type == "touchend") e.preventDefault(); 1061 if (e.currentTarget.parentNode.parentNode == this.prev) return; 1062 if (this.disableClick) return; // disable click during swipe 1063 var title = $(e.currentTarget).find("a").html().replace(/<.*>/, ""); 1064 this.open(title, e.currentTarget.menu); 1065 }, 1066 1067 open: function(title, submenu) { 1068 if (submenu.parentNode != this.$lvls[0]) 1069 $(submenu).css({top:'', left:'', right:''}).appendTo(this.$lvls); 1070 var w = this.$lvls.outerWidth(), 1071 tl = new TimelineLite({paused: true, autoRemoveChildren: true, onComplete: $.proxy(this, "onEndSlide")}); 1072 TweenLite.set(this.opened, {transformOrigin: Hlpr.calcOrigin(this.outOrigin, w)}); 1073 TweenLite.set(submenu, {transformOrigin: Hlpr.calcOrigin(this.inOrigin, w)}); 1074 1075 this.inCSS.x = this.inUnitX == "%" ? this.inX * w / 100 : this.inX; 1076 this.outCSS.x = this.outUnitX == "%" ? this.outX * w / 100 : this.outX; 1077 1078 // submenu anims 1079 tl.add(TweenLite.to(this.opened, this.dur, {css: this.outCSS, ease: this.outEase, onComplete: Target.scrollUp}), 0); 1080 tl.add(TweenLite.fromTo(submenu, this.dur, {css: this.inCSS}, {css: this.baseCSS, ease: this.inEase}), 0); 1081 1082 this.opened.style.zIndex = ""; 1083 submenu.style.zIndex = 99; 1084 submenu.style.display = "block"; 1085 if (!this.sidebar && this.winWidth >= this.sidebarUnder) { 1086 if (this.popup) submenu.children[0].style.maxHeight = this.$lvls[0].style.maxHeight; 1087 var h = $(submenu.children[0]).outerHeight() + 2 * this.menuPadding; 1088 tl.add(TweenLite.to(this.$lvls[0], this.dur, {css: {height: h}}), 0); 1089 } 1090 1091 if (!$(this.opened.children).hasClass("sm-result")) { // if filtering was started at search result, don't run it 1092 // header anims 1093 if (this.$head.length) { 1094 var $title = $('<span class="sm-title" title="'+title+'">'+title+'</span>').appendTo(this.$head), 1095 i = this.$title.length; 1096 if (!this.$title[0].style.position) // init title position 1097 TweenLite.set(this.$title[0], {css: {position: "absolute", x: this.$title._center(this.$back.length)}}); 1098 if (this.$back.length) { // clean theme 1099 if (i == 1) 1100 tl.add(TweenLite.to(this.$back[0], this.dur, {css: {opacity: 1, display: 'block'}}), 0); 1101 if (this.$title[--i]) this.$title[i].style.position = "absolute", 1102 tl.add(TweenLite.to(this.$title[i], 2*this.dur, {css: {x: -w*0.6, opacity: -1, scale: 0}}), 0); 1103 } else { // flat theme 1104 this.$title.attr("class", "sm-back"); 1105 if (this.$title[--i]) this.$title[i].style.position = "absolute", 1106 tl.add(TweenLite.to(this.$title[i], this.dur, {css: {x: 0, scale: backScale}}), 0); 1107 if (this.$title[--i]) 1108 tl.add(TweenLite.to(this.$title[i], this.dur, {css: {x: -w*0.6}, ease: Linear.easeNone}), 0); 1109 } 1110 tl.add(TweenLite.fromTo($title, this.dur, {x: w}, {css: {x: $title._center(this.$back.length)}}), 0); 1111 this.$title.push($title[0]); 1112 } 1113 1114 // bg anim 1115 if (this.bg && this.bgX) { 1116 var level = this.opened.children[0].attributes['class'].value.match(/level(\d)/)[1]; 1117 tl.add(TweenLite.to(this.$node[0], this.dur, {css: {backgroundPosition: this.bgX * level + "% 0"}}), 0); 1118 } 1119 } 1120 // menu-item anim 1121 if (this.miAnim) { 1122 this.miCSS.x = this.miUnitX == "%" ? this.miX * w / 100 : this.miX; 1123 if (this.miShift) 1124 tl.staggerFromTo($(">dl>dt", submenu), this.miDur, {css: this.miCSS}, {css: this.baseCSS, ease: this.miEase}
1124, this.miShift, 0); 1125 else 1126 tl.fromTo(submenu.children[0], this.miDur, {css: this.miCSS}, {css: this.baseCSS, ease: this.miEase}, 0); 1127 } 1128 // icons anim 1129 if (this.iconAnim && !smMobile) 1130 tl.add(TweenLite.fromTo($(".sm-icon img", submenu), 0.5, {scale: 0, opacity: 0}, {css: {scale: 1, opacity: 1}, ease: Back.easeOut}), 0.66*this.dur); 1131 this.openTL = tl; 1132 1133 if (this.backTL && this.backTL._first) delete this.backTL._first.vars.onComplete; // don't run Target.scrollUp 1134 TweenLite.set(this.$lvls[0], {perspective: this.perspective}); // blur fix for retina 1135 this.openTL.play(); 1136 this.prev = this.opened; 1137 this.opened = submenu; 1138 this.updateScrollbar(); 1139 1140 // don't trigger event when submenu is search result 1141 if (!$(submenu.children[0]).hasClass("sm-result")) $(submenu.parentItem).trigger("openParentItem", [this, title]); 1142 }, 1143 1144 onResetFilter: function() { 1145 this.$filter.attr("value", ""); 1146 if ($(this.opened.children).hasClass("sm-result")) this.onBack(); 1147 this.$filter[0].focus(); 1148 }, 1149 1150 onBack: function(e) { 1151 if (e && e.type == "touchend") e.preventDefault(); 1152 if (!this.opened.parent) return; 1153 this.initBackTimeline(); 1154 this.back(); 1155 }, 1156 1157 back: function() { 1158 if (this.openTL && this.openTL._first) delete this.openTL._first.vars.onComplete; // don't run Target.scrollUp 1159 TweenLite.set(this.$lvls[0], {perspective: this.perspective}); // blur fix for retina 1160 this.backTL.resume(); 1161 this.prev = this.opened; 1162 this.opened = this.opened.parent; 1163 this.updateScrollbar(); 1164 1165 this.$title.length--; 1166 this.$filter.attr("value", ""); 1167 this.keyword = ""; 1168 $(this.opened).trigger("back", this); 1169 }, 1170 1171 initBackTimeline: function() { 1172 var w = this.$lvls.addClass("sm-swipe").outerWidth(), 1173 tl = new TimelineLite({ 1174 paused: true, 1175 autoRemoveChildren: true, 1176 onComplete: $.proxy(this, "onEndSlide"), 1177 onReverseComplete: function() { this.onEndSlide(), this.opened.parent.style.display = "none" }.bind(this) 1178 }); 1179 1180 this.inCSS.x = this.inUnitX == "%" ? this.inX * w / 100 : this.inX; 1181 1182 TweenLite.set(this.opened, {transformOrigin: Hlpr.calcOrigin(this.inOrigin, w)}); 1183 TweenLite.set(this.opened.parent, {transformOrigin: Hlpr.calcOrigin(this.outOrigin, w)}); 1184 1185 // submenu anims 1186 tl.add(TweenLite.to(this.opened, this.dur, {css: this.inCSS, onComplete: Target.scrollUp}), 0); 1187 tl.add(TweenLite.to(this.opened.parent, this.dur, {css: this.baseCSS, ease: this.inEase}), 0); 1188 1189 this.opened.parent.style.display = "block"; 1190 if (!this.sidebar && this.winWidth >= this.sidebarUnder) { 1191 if (this.popup) this.opened.parent.children[0].style.maxHeight = this.$lvls[0].style.maxHeight; 1192 tl.add(TweenLite.to(this.$lvls[0], this.dur, { 1193 css: {height: $(this.opened.parent.children[0]).outerHeight() + 2 * this.menuPadding}, 1194 onComplete: this.prev.parentNode.children[0] == this.prev ? Target.autoHeight : undefined // auto height first level 1195 }), 0); 1196 } 1197 1198 // header anims 1199 if (this.$head.length) { 1200 var i = this.$title.length; 1201 tl.add(TweenLite.to(this.$title[--i], this.dur, {css: {x: w, opacity: 0}, onComplete: Target.remove}), 0); 1202 if (this.$back.length) { // clean theme 1203 if (i == 1) tl.add(TweenLite.to(this.$back[0], this.dur, {css: {opacity: 0, display: 'none'}}), 0); 1204 tl.add(TweenLite.to(this.$title[--i], this.dur, {css: {x: $(this.$title[i])._center(true), opacity: 1, scale: 1}}), 0); 1205 } else { // flat theme 1206 tl.add(TweenLite.to(this.$title[--i], this.dur, { 1207 css: {x: $(this.$title[i])._center(), scale: 1, maxWidth: i ? this.titleWidth : "100%"}, 1208 onComplete: Target.autoMaxWidth 1209 }), 0); 1210 if (this.$title[--i]) tl.add(TweenLite.to(this.$title[i], this.dur, {css: {x: 0}}), 0); 1211 } 1212 } 1213 1214 // bg anim 1215 if (this.bg && this.bgX) { 1216 var level = this.opened.children[0].attributes['class'].value.match(/level(\d)/); 1217 level = level ? level[1] - 2 : 0; 1218 tl.add(TweenLite.to(this.$node[0], this.dur, {css: {backgroundPosition: this.bgX * level + "% 0"}}), 0); 1219 } 1220 1221 this.backTL = tl; 1222 }, 1223 1224 onEndSlide: function() { 1225 // blur fix for retina 1226 $(this.opened).css({WebkitTransform: "", MozTransform: "", msTransform: "", transform: ""}); 1227 this.$lvls.css({WebkitPerspective: "", MozPerspective: "", perspective: ""}).removeClass("sm-swipe"); 1228 this.disableClick = false; // enable click after swipe 1229 }, 1230 1231 updateScrollbar: function(menu) { 1232 if (smMobile) return; 1233 var $dl = $( (menu || this.opened).children[0] ); 1234 $dl.perfectScrollbar($dl.data("perfectScrollbar") ? "update" : undefined); 1235 } 1236 1237}; 1238 1239// depreciated functions 1240VerticalSlideMenu.prototype.openSidebar = VerticalSlideMenu.prototype.openMenu; 1241VerticalSlideMenu.prototype.closeSidebar = VerticalSlideMenu.prototype.closeMenu; 1242 1243})(window.jq183||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.