1"use strict"; 2 3/** 4 * Endnode-menu for mobile devices, only one open at a time 5 * 6 * Reads structure from a list and displays one layer at a time until user 7 * reaches an endnode or chooses to land on currently open inner node. 8 * 9 * Usage: 10 * -Call qui.qLeafMenu.init() in document load 11 * -any anchor with .qLeafMenuRoot that is clicked opens the ssociated menu with these parameters: 12 * data-qMenuSrc : jQuery selector for finding the menu list data 13 * 14 **/ 15 16var qui = qui || {}; 17 18qui.qLeafMenu = (function () { 19 var resizeTimer = null; 20 var resizeDelay = 100; 21 var wrapper = $('<div class="qLeafMenu"></div>'); 22 var srcAttr = "data-qLeafMenuSrc"; 23 var activeMenu = null; 24 25 var init = function () { 26 var bod = $("body"); 27 bod.on("click", "a.qLeafMenuRoot", toggleMenu); 28 bod.on("click", "div.qLeafMenu a.branch", branchClick); 29 bod.on("click", "div.qLeafMenu a.leaf", leafClick); 30 bod.on("click", "div.qLeafMenu a.back", backClick); 31 bod.on("transitionend", "div.qLeafMenu ul", transitionEnd); 32 33 // if click outside opened menu 34 bod.on("click", function (event) { 35 if (activeMenu === null) { 36 return; 37 } 38 if (!$(event.target).closest("div.qLeafMenu, a.menu.qLeafMenuRoot").length) { 39 $("div.qLeafMenu").removeClass("open"); 40 close(); 41 } 42 }); 43 44 // check for window size changes, with a delay to prevent overeager calculations 45 $(window).resize(function (event) { 46 clearTimeout(resizeTimer); 47 resizeTimer = setTimeout(update, resizeDelay); 48 }); 49 50 $(document).on('scroll', scroll); 51 }; 52 53 var update = function () { 54 if (!activeMenu) return; 55 var button = activeMenu.data("root"); 56 var offset = button.offset(); 57 58 var iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; 59 var newTop = Math.floor(offset.top + button.outerHeight(true)); 60 61 activeMenu.css('top', newTop + "px"); 62 }; 63 64 var scroll = function () { 65 if (!activeMenu) return; 66 // only update menu position on scroll if there is a gap between top of menu and bottom of button 67 var button = activeMenu.data("root"); 68 var buttonoffset = button.offset(); 69 var menuoffset = activeMenu.offset(); 70 71 if (buttonoffset.top + button.height() < menuoffset.top) { 72 update(); 73 } 74 } 75 76 var toggleMenu = function (evt) { 77 var button = $(this); 78 if (!!activeMenu) { 79 var activeMenuButton = activeMenu.data("root"); 80 button.removeClass("open"); 81 close(); 82 if (activeMenuButton.is(button)) { 83 return; 84 } 85 } 86 87 open.call(this, evt); 88 }; 89 90 var close = function () { 91 activeMenu.remove(); 92 activeMenu = null; 93 }; 94 95 var open = function (evt) { 96 var button = $(this); 97 var src = button.attr(srcAttr); 98 var inner = $(src).clone(); 99 100 activeMenu = wrapper.clone(); 101 activeMenu.append(inner); 102 activeMenu.data("root", button); 103 activeMenu.find("li > ul").hide(); 104 $("body").append(activeMenu); 105 inner.show(); 106 setTimeout(function () { 107 activeMenu.addClass("open"); 108 button.addClass("open"); 109 }, 0); 110 111 update(); 112 }; 113 114 var branchClick = function (evt) { 115 evt.preventDefault(); 116 var button = $(this); 117 var submenu = button.siblings("ul"); 118 var currentmenu = button.closest("ul"); 119 currentmenu.addClass("faded"); 120 submenu.addClass("closed") 121 submenu.show(); 122 setTimeout(function () { 123 submenu.removeClass("closed").addClass("open"); 124 if (submenu.height() > currentmenu.height()) { 125 activeMenu.css("min-height", submenu.height() + "px"); 126 } 127 }, 100); 128 }; 129 130 var leafClick = function (evt) { 131 /*evt.preventDefault(); 132 var button = $(this); 133 close();*/ 134 var button = $(this); 135 var currentmenu = button.closest("ul"); 136 toggleMenu.call(currentmenu, evt); 137 }; 138 139 var backClick = function (evt) { 140 evt.preventDefault(); 141 var button = $(this); 142 143 var currentmenu = button.closest("ul"); 144 var lastmenu = currentmenu.parent().closest("ul"); 145 lastmenu.removeClass("faded"); 146 var prevlevel = currentmenu.closest("ul"); 147 currentmenu.addClass("closed"); 148 if (prevlevel.height() < currentmenu.height()) { 149 activeMenu.css("min-height", prevlevel.height() + "px"); 150 } 151 }; 152 153 var transitionEnd = function (evt) { 154 var submenu = $(this); 155 if (submenu.hasClass("closed")) { 156 submenu.removeClass("open closed"); 157 } 158 } 159 160 return { 161 init: init, 162 update: update 163 }; 164})();
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.