You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

500 lines
20 KiB

2 years ago
  1. ;(function ( $, window, document, undefined ){
  2. $.navigation = function(element, options){
  3. var defaults = {
  4. responsive: true,
  5. mobileBreakpoint: 1000,
  6. showDuration: 300,
  7. hideDuration: 300,
  8. showDelayDuration: 0,
  9. hideDelayDuration: 0,
  10. submenuTrigger: "hover",
  11. effect: "fade",
  12. submenuIndicator: true,
  13. submenuIndicatorTrigger: false,
  14. hideSubWhenGoOut: true,
  15. visibleSubmenusOnMobile: false,
  16. overlay: true,
  17. overlayColor: "rgba(0, 0, 0, 0.7)",
  18. hidden: false,
  19. hiddenOnMobile: false,
  20. offCanvasSide: "left",
  21. offCanvasCloseButton: true,
  22. animationOnShow: "",
  23. animationOnHide: "",
  24. hideScrollBar: true,
  25. onInit: function() {},
  26. onLandscape: function() {},
  27. onPortrait: function() {},
  28. onShowOffCanvas: function() {},
  29. onHideOffCanvas: function() {}
  30. };
  31. var plugin = this,
  32. bigScreenFlag = Number.MAX_VALUE,
  33. smallScreenFlag = 1,
  34. clickTouchEvents = "click.nav touchstart.nav",
  35. hoverShowEvents = "mouseenter focusin",
  36. hoverHideEvents = "mouseleave focusout";
  37. plugin.settings = {};
  38. var $element = $(element), element = element;
  39. if($(element).find(".nav-search").length > 0){
  40. $(element).find(".nav-search").find("form").prepend("<span class='nav-search-close-button' tabindex='0'>&#10005;</span>");
  41. }
  42. plugin.init = function(){
  43. plugin.settings = $.extend({}, defaults, options);
  44. if(plugin.settings.offCanvasCloseButton){
  45. $(element).find(".nav-menus-wrapper").prepend("<span class='nav-menus-wrapper-close-button'>&#10005;</span>");
  46. }
  47. if(plugin.settings.offCanvasSide == "right"){
  48. $(element).find(".nav-menus-wrapper").addClass("nav-menus-wrapper-right");
  49. }
  50. if(plugin.settings.hidden){
  51. $(element).addClass("navigation-hidden");
  52. plugin.settings.mobileBreakpoint = 99999;
  53. }
  54. checkSubmenus();
  55. $(element).find(".nav-toggle").on("click touchstart", function(e){
  56. e.stopPropagation();
  57. e.preventDefault();
  58. plugin.showOffcanvas();
  59. if(options !== undefined){
  60. plugin.callback("onShowOffCanvas");
  61. }
  62. });
  63. $(element).find(".nav-menus-wrapper-close-button").on("click touchstart", function(){
  64. plugin.hideOffcanvas();
  65. if(options !== undefined){
  66. plugin.callback("onHideOffCanvas");
  67. }
  68. });
  69. $(element).find(".nav-search-button, .nav-search-close-button").on("click touchstart keydown", function(e){
  70. e.stopPropagation();
  71. e.preventDefault();
  72. var code = e.keyCode || e.which;
  73. if(e.type === "click" || e.type === "touchstart" || (e.type === "keydown" && code == 13)){
  74. plugin.toggleSearch();
  75. }
  76. else{
  77. if(code == 9){
  78. $(e.target).blur();
  79. }
  80. }
  81. });
  82. $(window).resize(function(){
  83. plugin.initNavigationMode(windowWidth());
  84. fixSubmenuRightPosition();
  85. if(plugin.settings.hiddenOnMobile){
  86. hideNavbarPortrait();
  87. }
  88. });
  89. plugin.initNavigationMode(windowWidth());
  90. if(plugin.settings.hiddenOnMobile){
  91. hideNavbarPortrait();
  92. }
  93. if(plugin.settings.overlay){
  94. $(element).append("<div class='nav-overlay-panel'></div>");
  95. }
  96. if($(element).find(".megamenu-tabs").length > 0){
  97. activateTabs();
  98. }
  99. if(options !== undefined){
  100. plugin.callback("onInit");
  101. }
  102. };
  103. // reset submenus
  104. var resetSubmenus = function(){
  105. $(element).find(".nav-submenu").hide(0);
  106. $(element).find("li").removeClass("focus");
  107. };
  108. // check the existence of submenus/add indicators to them
  109. var checkSubmenus = function(){
  110. $(element).find("li").each(function(){
  111. if($(this).children(".nav-dropdown,.megamenu-panel").length > 0){
  112. $(this).children(".nav-dropdown,.megamenu-panel").addClass("nav-submenu");
  113. if(plugin.settings.submenuIndicator){
  114. $(this).children("a").append(
  115. "<span class='submenu-indicator'>" +
  116. "<span class='submenu-indicator-chevron'></span>" +
  117. "</span>"
  118. );
  119. }
  120. }
  121. });
  122. };
  123. //hide navbar on portrait mode
  124. var hideNavbarPortrait = function(){
  125. if($(element).hasClass("navigation-portrait")){
  126. $(element).addClass("navigation-hidden");
  127. }
  128. else{
  129. $(element).removeClass("navigation-hidden");
  130. }
  131. };
  132. // show a submenu
  133. plugin.showSubmenu = function(parentItem, submenuEffect){
  134. if(windowWidth() > plugin.settings.mobileBreakpoint){
  135. $(element).find(".nav-search").find("form").fadeOut();
  136. }
  137. if(submenuEffect == "fade"){
  138. $(parentItem).children(".nav-submenu")
  139. .stop(true, true)
  140. .delay(plugin.settings.showDelayDuration)
  141. .fadeIn(plugin.settings.showDuration)
  142. .removeClass(plugin.settings.animationOnHide)
  143. .addClass(plugin.settings.animationOnShow);
  144. }
  145. else{
  146. $(parentItem).children(".nav-submenu")
  147. .stop(true, true)
  148. .delay(plugin.settings.showDelayDuration)
  149. .slideDown(plugin.settings.showDuration)
  150. .removeClass(plugin.settings.animationOnHide)
  151. .addClass(plugin.settings.animationOnShow);
  152. }
  153. $(parentItem).addClass("focus");
  154. };
  155. // hide a submenu
  156. plugin.hideSubmenu = function(parentItem, submenuEffect){
  157. if(submenuEffect == "fade"){
  158. $(parentItem).find(".nav-submenu")
  159. .stop(true, true)
  160. .delay(plugin.settings.hideDelayDuration)
  161. .fadeOut(plugin.settings.hideDuration)
  162. .removeClass(plugin.settings.animationOnShow)
  163. .addClass(plugin.settings.animationOnHide);
  164. }
  165. else{
  166. $(parentItem).find(".nav-submenu")
  167. .stop(true, true)
  168. .delay(plugin.settings.hideDelayDuration)
  169. .slideUp(plugin.settings.hideDuration)
  170. .removeClass(plugin.settings.animationOnShow)
  171. .addClass(plugin.settings.animationOnHide);
  172. }
  173. $(parentItem).removeClass("focus").find(".focus").removeClass("focus");
  174. };
  175. // show the overlay panel
  176. var showOverlay = function(){
  177. if(plugin.settings.hideScrollBar){
  178. $("body").addClass("no-scroll");
  179. }
  180. if(plugin.settings.overlay){
  181. $(element).find(".nav-overlay-panel")
  182. .css("background-color", plugin.settings.overlayColor)
  183. .fadeIn(300)
  184. .on("click touchstart", function(){
  185. plugin.hideOffcanvas();
  186. });
  187. }
  188. };
  189. // hide the overlay panel
  190. var hideOverlay = function(){
  191. if(plugin.settings.hideScrollBar){
  192. $("body").removeClass("no-scroll");
  193. }
  194. if(plugin.settings.overlay){
  195. $(element).find(".nav-overlay-panel").fadeOut(400);
  196. }
  197. };
  198. // show offcanvas
  199. plugin.showOffcanvas = function(){
  200. showOverlay();
  201. if(plugin.settings.offCanvasSide == "left"){
  202. $(element).find(".nav-menus-wrapper").css("transition-property", "left").addClass("nav-menus-wrapper-open");
  203. }
  204. else{
  205. $(element).find(".nav-menus-wrapper").css("transition-property", "right").addClass("nav-menus-wrapper-open");
  206. }
  207. };
  208. // hide offcanvas
  209. plugin.hideOffcanvas = function(){
  210. $(element).find(".nav-menus-wrapper").removeClass("nav-menus-wrapper-open")
  211. .on("webkitTransitionEnd moztransitionend transitionend oTransitionEnd", function(){
  212. $(element).find(".nav-menus-wrapper")
  213. .css("transition-property", "none")
  214. .off();
  215. });
  216. hideOverlay();
  217. };
  218. // toggle offcanvas
  219. plugin.toggleOffcanvas = function(){
  220. if(windowWidth() <= plugin.settings.mobileBreakpoint){
  221. if($(element).find(".nav-menus-wrapper").hasClass("nav-menus-wrapper-open")){
  222. plugin.hideOffcanvas();
  223. if(options !== undefined){
  224. plugin.callback("onHideOffCanvas");
  225. }
  226. }
  227. else{
  228. plugin.showOffcanvas();
  229. if(options !== undefined){
  230. plugin.callback("onShowOffCanvas");
  231. }
  232. }
  233. }
  234. };
  235. // show/hide the search form
  236. plugin.toggleSearch = function(){
  237. if($(element).find(".nav-search").find("form").css("display") == "none"){
  238. $(element).find(".nav-search").find("form").fadeIn(200);
  239. $(element).find(".nav-search").find("input").focus();
  240. }
  241. else{
  242. $(element).find(".nav-search").find("form").fadeOut(200);
  243. $(element).find(".nav-search").find("input").blur();
  244. }
  245. };
  246. // set the navigation mode and others configs
  247. plugin.initNavigationMode = function(screenWidth){
  248. if(plugin.settings.responsive){
  249. if(screenWidth <= plugin.settings.mobileBreakpoint && bigScreenFlag > plugin.settings.mobileBreakpoint){
  250. $(element).addClass("navigation-portrait").removeClass("navigation-landscape");
  251. portraitMode();
  252. if(options !== undefined){
  253. plugin.callback("onPortrait");
  254. }
  255. }
  256. if(screenWidth > plugin.settings.mobileBreakpoint && smallScreenFlag <= plugin.settings.mobileBreakpoint){
  257. $(element).addClass("navigation-landscape").removeClass("navigation-portrait");
  258. landscapeMode();
  259. hideOverlay();
  260. plugin.hideOffcanvas();
  261. if(options !== undefined){
  262. plugin.callback("onLandscape");
  263. }
  264. }
  265. bigScreenFlag = screenWidth;
  266. smallScreenFlag = screenWidth;
  267. }
  268. else{
  269. $(element).addClass("navigation-landscape");
  270. landscapeMode();
  271. if(options !== undefined){
  272. plugin.callback("onLandscape");
  273. }
  274. }
  275. };
  276. // hide submenus/form when click/touch outside
  277. var goOut = function(){
  278. $("html").on("click.body touchstart.body", function(e){
  279. if($(e.target).closest(".navigation").length === 0){
  280. $(element).find(".nav-submenu").fadeOut();
  281. $(element).find(".focus").removeClass("focus");
  282. $(element).find(".nav-search").find("form").fadeOut();
  283. }
  284. });
  285. };
  286. // return the window's width
  287. var windowWidth = function(){
  288. return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
  289. };
  290. // unbind events
  291. var unbindEvents = function(mode){
  292. if(mode == "landscape")
  293. $(element).find(".nav-menu").find("li, a").off(clickTouchEvents)
  294. else
  295. $(element).find(".nav-menu").find("li, a").off(hoverShowEvents).off(hoverHideEvents);
  296. };
  297. // fix submenu right position
  298. var fixSubmenuRightPosition = function(){
  299. if(windowWidth() > plugin.settings.mobileBreakpoint){
  300. var navWidth = $(element).outerWidth();
  301. $(element).find(".nav-menu").children("li").children(".nav-submenu").each(function(){
  302. if($(this).parent().position().left + $(this).outerWidth() > navWidth){
  303. $(this).css("right", 0);
  304. }
  305. else{
  306. $(this).css("right", "auto");
  307. }
  308. });
  309. }
  310. };
  311. // activate the tabs
  312. var activateTabs = function(){
  313. function initTabs(tabs){
  314. var navs = $(tabs).children(".megamenu-tabs-nav").children("li");
  315. var panes = $(tabs).children(".megamenu-tabs-pane");
  316. $(navs).on("mouseenter.tabs click.tabs touchstart.tabs", function(e){
  317. e.stopPropagation();
  318. e.preventDefault();
  319. $(navs).removeClass("active");
  320. $(this).addClass("active");
  321. $(panes).hide(0).removeClass("active");
  322. $(panes[$(this).index()]).show(0).addClass("active");
  323. });
  324. }
  325. if($(element).find(".megamenu-tabs").length > 0){
  326. var navigationTabs = $(element).find(".megamenu-tabs");
  327. for(var i = 0; i < navigationTabs.length; i++){
  328. initTabs(navigationTabs[i]);
  329. }
  330. }
  331. };
  332. // set the landscape mode
  333. var landscapeMode = function(){
  334. unbindEvents("landscape");
  335. resetSubmenus();
  336. if(navigator.userAgent.match(/Mobi/i) || navigator.maxTouchPoints > 0 || plugin.settings.submenuTrigger == "click"){
  337. $(element).find(".nav-menu, .nav-dropdown").children("li").children("a").on(clickTouchEvents, function(e){
  338. plugin.hideSubmenu($(this).parent("li").siblings("li"), plugin.settings.effect);
  339. $(this).closest(".nav-menu").siblings(".nav-menu").find(".nav-submenu").fadeOut(plugin.settings.hideDuration);
  340. if($(this).siblings(".nav-submenu").length > 0){
  341. e.stopPropagation();
  342. e.preventDefault();
  343. if($(this).siblings(".nav-submenu").css("display") == "none"){
  344. plugin.showSubmenu($(this).parent("li"), plugin.settings.effect);
  345. fixSubmenuRightPosition();
  346. return false;
  347. }
  348. else{
  349. plugin.hideSubmenu($(this).parent("li"), plugin.settings.effect);
  350. }
  351. if($(this).attr("target") === "_blank" || $(this).attr("target") === "blank"){
  352. window.open($(this).attr("href"));
  353. }
  354. else{
  355. if($(this).attr("href") === "#" || $(this).attr("href") === "" || $(this).attr("href") === "javascript:void(0)"){
  356. return false;
  357. }
  358. else{
  359. window.location.href = $(this).attr("href");
  360. }
  361. }
  362. }
  363. });
  364. }
  365. else{
  366. $(element).find(".nav-menu").find("li").on(hoverShowEvents, function(){
  367. plugin.showSubmenu(this, plugin.settings.effect);
  368. fixSubmenuRightPosition();
  369. }).on(hoverHideEvents, function(){
  370. plugin.hideSubmenu(this, plugin.settings.effect);
  371. });
  372. }
  373. if(plugin.settings.hideSubWhenGoOut){
  374. goOut();
  375. }
  376. };
  377. // set the portrait mode
  378. var portraitMode = function(){
  379. unbindEvents("portrait");
  380. resetSubmenus();
  381. if(plugin.settings.visibleSubmenusOnMobile){
  382. $(element).find(".nav-submenu").show(0);
  383. }
  384. else{
  385. $(element).find(".submenu-indicator").removeClass("submenu-indicator-up");
  386. if(plugin.settings.submenuIndicator && plugin.settings.submenuIndicatorTrigger){
  387. $(element).find(".submenu-indicator").on(clickTouchEvents, function(e){
  388. e.stopPropagation();
  389. e.preventDefault();
  390. plugin.hideSubmenu($(this).parent("a").parent("li").siblings("li"), "slide");
  391. plugin.hideSubmenu($(this).closest(".nav-menu").siblings(".nav-menu").children("li"), "slide");
  392. if($(this).parent("a").siblings(".nav-submenu").css("display") == "none"){
  393. $(this).addClass("submenu-indicator-up");
  394. $(this).parent("a").parent("li").siblings("li").find(".submenu-indicator").removeClass("submenu-indicator-up");
  395. $(this).closest(".nav-menu").siblings(".nav-menu").find(".submenu-indicator").removeClass("submenu-indicator-up");
  396. plugin.showSubmenu($(this).parent("a").parent("li"), "slide");
  397. return false;
  398. }
  399. else{
  400. $(this).parent("a").parent("li").find(".submenu-indicator").removeClass("submenu-indicator-up");
  401. plugin.hideSubmenu($(this).parent("a").parent("li"), "slide");
  402. }
  403. });
  404. }
  405. else{
  406. $(element).find(".nav-menu, .nav-dropdown").children("li").children("a").each(function(){
  407. if($(this).siblings(".nav-submenu").length > 0){
  408. $(this).on(clickTouchEvents, function(e){
  409. e.stopPropagation();
  410. e.preventDefault();
  411. plugin.hideSubmenu($(this).parent("li").siblings("li"), plugin.settings.effect);
  412. plugin.hideSubmenu($(this).closest(".nav-menu").siblings(".nav-menu").children("li"), "slide");
  413. if($(this).siblings(".nav-submenu").css("display") == "none"){
  414. $(this).children(".submenu-indicator").addClass("submenu-indicator-up");
  415. $(this).parent("li").siblings("li").find(".submenu-indicator").removeClass("submenu-indicator-up");
  416. $(this).closest(".nav-menu").siblings(".nav-menu").find(".submenu-indicator").removeClass("submenu-indicator-up");
  417. plugin.showSubmenu($(this).parent("li"), "slide");
  418. return false;
  419. }
  420. else{
  421. $(this).parent("li").find(".submenu-indicator").removeClass("submenu-indicator-up");
  422. plugin.hideSubmenu($(this).parent("li"), "slide");
  423. }
  424. if($(this).attr("target") === "_blank" || $(this).attr("target") === "blank"){
  425. window.open($(this).attr("href"));
  426. }
  427. else{
  428. if($(this).attr("href") === "#" || $(this).attr("href") === "" || $(this).attr("href") === "javascript:void(0)"){
  429. return false;
  430. }
  431. else{
  432. window.location.href = $(this).attr("href");
  433. }
  434. }
  435. });
  436. }
  437. });
  438. }
  439. }
  440. };
  441. plugin.callback = function(func) {
  442. if (options[func] !== undefined) {
  443. options[func].call(element);
  444. }
  445. };
  446. plugin.init();
  447. };
  448. $.fn.navigation = function(options){
  449. return this.each(function(){
  450. if (undefined === $(this).data("navigation")){
  451. var plugin = new $.navigation(this, options);
  452. $(this).data("navigation", plugin);
  453. }
  454. });
  455. };
  456. })( jQuery, window, document );