portal html css js resource

jquery.mmenu.js 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. /*
  2. * jQuery mmenu 1.3.1
  3. *
  4. * Copyright (c) 2013 Fred Heusschen
  5. * www.frebsite.nl
  6. *
  7. * Dual licensed under the MIT and GPL licenses.
  8. * http://en.wikipedia.org/wiki/MIT_License
  9. * http://en.wikipedia.org/wiki/GNU_General_Public_License
  10. */
  11. (function( $ ) {
  12. // Global nodes
  13. var $wndw = null,
  14. $html = null,
  15. $body = null,
  16. $page = null,
  17. $blck = null;
  18. var $scrollTopNode = null;
  19. // Global vars
  20. var _serialnr = 0;
  21. $.fn.mmenu = function( opts )
  22. {
  23. if ( !$wndw )
  24. {
  25. $wndw = $(window);
  26. $html = $('html');
  27. $body = $('body');
  28. }
  29. opts = extendOptions( opts );
  30. opts = $.extend( true, {}, $.fn.mmenu.defaultOptions, opts );
  31. opts = complementOptions( opts );
  32. $html[ opts.configuration.hardwareAcceleration ? 'addClass' : 'removeClass' ]( cls( 'accelerated' ) );
  33. return this.each(
  34. function()
  35. {
  36. // STORE VARIABLES
  37. var $menu = $(this),
  38. _opened = false,
  39. _direction = ( opts.slidingSubmenus ) ? 'horizontal' : 'vertical';
  40. _serialnr++;
  41. // INIT PAGE, MENU, LINKS & LABELS
  42. $page = _initPage( $page, opts.configuration );
  43. $blck = _initBlocker( $blck, $menu, opts.configuration );
  44. $menu = _initMenu( $menu, opts.configuration );
  45. _initSubmenus( $menu, _direction, _serialnr );
  46. _initLinks( $menu, opts.onClick, opts.configuration );
  47. _initCounters( $menu, opts.counters, opts.configuration );
  48. _initSearch( $menu, opts.searchfield );
  49. _initOpenClose( $menu, $page );
  50. // BIND EVENTS
  51. var $subs = $menu.find( 'ul' );
  52. $menu.add( $subs )
  53. .bind(
  54. evt( 'toggle' ) + ' ' + evt( 'open' ) + ' ' + evt( 'close' ),
  55. function( e )
  56. {
  57. e.preventDefault();
  58. e.stopPropagation();
  59. }
  60. );
  61. // menu-events
  62. $menu
  63. .bind(
  64. evt( 'toggle' ),
  65. function( e )
  66. {
  67. return $menu.triggerHandler( evt( _opened ? 'close' : 'open' ) );
  68. }
  69. )
  70. .bind(
  71. evt( 'open' ),
  72. function( e )
  73. {
  74. if ( _opened )
  75. {
  76. return false;
  77. }
  78. _opened = true;
  79. return openMenu( $menu, opts.position );
  80. }
  81. )
  82. .bind(
  83. evt( 'close' ),
  84. function( e )
  85. {
  86. if ( !_opened )
  87. {
  88. return false;
  89. }
  90. _opened = false;
  91. return closeMenu( $menu, opts );
  92. }
  93. );
  94. // submenu-events
  95. if ( _direction == 'horizontal' )
  96. {
  97. $subs
  98. .bind(
  99. evt( 'toggle' ),
  100. function( e )
  101. {
  102. return $(this).triggerHandler( evt( 'open' ) );
  103. }
  104. )
  105. .bind(
  106. evt( 'open' ),
  107. function( e )
  108. {
  109. return openSubmenuHorizontal( $(this), opts );
  110. }
  111. )
  112. .bind(
  113. evt( 'close' ),
  114. function( e )
  115. {
  116. return closeSubmenuHorizontal( $(this), opts );
  117. }
  118. );
  119. }
  120. else
  121. {
  122. $subs
  123. .bind(
  124. evt( 'toggle' ),
  125. function( e )
  126. {
  127. var $t = $(this);
  128. return $t.triggerHandler( evt( ( $t.parent().hasClass( cls( 'opened' ) ) ) ? 'close' : 'open' ) );
  129. }
  130. )
  131. .bind(
  132. evt( 'open' ),
  133. function( e )
  134. {
  135. $(this).parent().addClass( cls( 'opened' ) );
  136. return 'open';
  137. }
  138. )
  139. .bind(
  140. evt( 'close' ),
  141. function( e )
  142. {
  143. $(this).parent().removeClass( cls( 'opened' ) );
  144. return 'close';
  145. }
  146. );
  147. }
  148. }
  149. );
  150. };
  151. $.fn.mmenu.defaultOptions = {
  152. position : 'right',
  153. slidingSubmenus : true,
  154. counters : {
  155. add : false,
  156. count : true
  157. },
  158. searchfield : {
  159. add : false,
  160. search : true,
  161. showLinksOnly : true,
  162. placeholder : 'Search',
  163. noResults : 'No results found.'
  164. },
  165. onClick : {
  166. close : true,
  167. delayPageload : true,
  168. blockUI : false
  169. },
  170. configuration : {
  171. hardwareAcceleration: true,
  172. selectedClass : 'Selected',
  173. labelClass : 'Label',
  174. counterClass : 'Counter',
  175. pageNodetype : 'div',
  176. menuNodetype : 'nav',
  177. slideDuration : 500
  178. }
  179. };
  180. $.fn.mmenu.debug = function( msg )
  181. {
  182. if ( typeof console != 'undefined' && typeof console.log != 'undefined' )
  183. {
  184. console.log( 'MMENU: ' + msg );
  185. }
  186. };
  187. $.fn.mmenu.deprecated = function( depr, repl )
  188. {
  189. if ( typeof console != 'undefined' && typeof console.warn != 'undefined' )
  190. {
  191. console.warn( 'MMENU: ' + depr + ' is deprecated, use ' + repl + ' instead.' );
  192. }
  193. };
  194. function extendOptions( o )
  195. {
  196. if ( typeof o == 'string' )
  197. {
  198. if ( o == 'left' || o == 'right' )
  199. {
  200. o = {
  201. position: o
  202. };
  203. }
  204. }
  205. else if ( typeof o != 'object' )
  206. {
  207. o = {};
  208. }
  209. // DEPRECATED
  210. if ( typeof o.addCounters != 'undefined' )
  211. {
  212. $.fn.mmenu.deprecated( 'addCounters-option', 'counters.add-option' );
  213. o.counters = {
  214. add: o.addCounters
  215. };
  216. }
  217. if ( typeof o.closeOnClick != 'undefined' )
  218. {
  219. $.fn.mmenu.deprecated( 'closeOnClick-option', 'onClick.close-option' );
  220. o.onClick = {
  221. close: o.closeOnClick
  222. };
  223. }
  224. // /DEPRECATED
  225. // Counters
  226. if ( typeof o.counters == 'boolean' )
  227. {
  228. o.counters = {
  229. add : o.counters,
  230. count : o.counters
  231. };
  232. }
  233. else if ( typeof o.counters != 'object' )
  234. {
  235. o.counters = {};
  236. }
  237. // OnClick
  238. if ( typeof o.onClick == 'boolean' )
  239. {
  240. o.onClick = {
  241. close : o.onClick
  242. };
  243. }
  244. else if ( typeof o.onClick != 'object' )
  245. {
  246. o.onClick = {};
  247. }
  248. // Search
  249. if ( typeof o.searchfield == 'boolean' )
  250. {
  251. o.searchfield = {
  252. add : o.searchfield,
  253. search : o.searchfield
  254. };
  255. }
  256. else if ( typeof o.searchfield == 'string' )
  257. {
  258. o.searchfield = {
  259. add : true,
  260. search : true,
  261. placeholder : o.searchfield
  262. };
  263. }
  264. else if ( typeof o.searchfield != 'object' )
  265. {
  266. o.searchfield = {};
  267. }
  268. return o;
  269. }
  270. function complementOptions( o )
  271. {
  272. if ( typeof o.onClick.delayPageload == 'boolean' )
  273. {
  274. o.onClick.delayPageload = ( o.onClick.delayPageload ) ? o.configuration.slideDuration : 0;
  275. }
  276. return o;
  277. }
  278. function _initPage( $p, conf )
  279. {
  280. if ( !$p )
  281. {
  282. $p = $('> ' + conf.pageNodetype, $body);
  283. if ( $p.length > 1 )
  284. {
  285. $p = $p.wrapAll( '<' + conf.pageNodetype + ' />' ).parent();
  286. }
  287. $p.addClass( cls( 'page' ) );
  288. }
  289. return $p;
  290. }
  291. function _initMenu( $m, conf )
  292. {
  293. if ( !$m.is( conf.menuNodetype ) )
  294. {
  295. $m = $( '<' + conf.menuNodetype + ' />' ).append( $m );
  296. }
  297. // $_dummy = $( '<div class="mmenu-dummy" />' ).insertAfter( $m ).hide();
  298. $m.addClass( cls( '' ).slice( 0, -1 ) ).prependTo( 'body' );
  299. // Refactor selected class
  300. $('li.' + conf.selectedClass, $m).removeClass( conf.selectedClass ).addClass( cls( 'selected' ) );
  301. // Refactor label class
  302. $('li.' + conf.labelClass, $m).removeClass( conf.labelClass ).addClass( cls( 'label' ) );
  303. return $m;
  304. }
  305. function _initSubmenus( $m, direction, serial )
  306. {
  307. $m.addClass( cls( direction ) );
  308. $( 'ul ul', $m )
  309. .addClass( cls( 'submenu' ) )
  310. .each(
  311. function( i )
  312. {
  313. var $t = $(this)
  314. $a = $t.parent().find( '> a, > span' ),
  315. id = $t.attr( 'id' ) || cls( 's' + serial + '-' + i );
  316. $t.attr( 'id', id );
  317. var $btn = $( '<a class="' + cls( 'subopen' ) + '" href="#' + id + '" />' ).insertBefore( $a );
  318. if ( !$a.is( 'a' ) )
  319. {
  320. $btn.addClass( cls( 'fullsubopen' ) );
  321. }
  322. if ( direction == 'horizontal' )
  323. {
  324. var $p = $t.parent().parent(),
  325. id = $p.attr( 'id' ) || cls( 'p' + serial + '-' + i );
  326. $p.attr( 'id', id );
  327. $t.prepend( '<li class="' + cls( 'subtitle' ) + '"><a class="' + cls( 'subclose' ) + '" href="#' + id + '">' + $a.text() + '</a></li>' );
  328. }
  329. }
  330. );
  331. if ( direction == 'horizontal' )
  332. {
  333. // Add opened-classes
  334. $('li.' + cls( 'selected' ), $m)
  335. .parents( 'li.' + cls( 'selected' ) ).removeClass( cls( 'selected' ) )
  336. .end().each(
  337. function()
  338. {
  339. var $t = $(this),
  340. $u = $t.find( '> ul' );
  341. if ( $u.length )
  342. {
  343. $t.parent().addClass( cls( 'subopened' ) );
  344. $u.addClass( cls( 'opened' ) );
  345. }
  346. }
  347. )
  348. .parent().addClass( cls( 'opened' ) )
  349. .parents( 'ul' ).addClass( cls( 'subopened' ) );
  350. if ( !$('ul.' + cls( 'opened' ), $m).length )
  351. {
  352. $('ul', $m).not( '.' + cls( 'submenu' ) ).addClass( cls( 'opened' ) );
  353. }
  354. // Rearrange markup
  355. $('ul ul', $m).appendTo( $m );
  356. }
  357. else
  358. {
  359. // Replace Selected-class with opened-class in parents from .Selected
  360. $('li.' + cls( 'selected' ), $m)
  361. .addClass( cls( 'opened' ) )
  362. .parents( '.' + cls( 'selected' ) ).removeClass( cls( 'selected' ) );
  363. }
  364. }
  365. function _initBlocker( $b, $m, conf )
  366. {
  367. if ( !$b )
  368. {
  369. $b = $( '<div id="' + cls( 'blocker' ) + '" />' ).appendTo( $body );
  370. }
  371. click( $b,
  372. function()
  373. {
  374. $m.trigger( evt( 'close' ) );
  375. }
  376. );
  377. return $b;
  378. }
  379. function _initLinks( $m, onClick, conf )
  380. {
  381. if ( onClick.close )
  382. {
  383. var $a = $('a', $m)
  384. .not( '.' + cls( 'subopen' ) )
  385. .not( '.' + cls( 'subclose' ) );
  386. click( $a,
  387. function()
  388. {
  389. var $t = $(this),
  390. href = $t.attr( 'href' );
  391. $m.trigger( evt( 'close' ) );
  392. $a.parent().removeClass( cls( 'selected' ) );
  393. $t.parent().addClass( cls( 'selected' ) );
  394. if ( onClick.blockUI && href.slice( 0, 1 ) != '#' )
  395. {
  396. $html.addClass( cls( 'blocking' ) );
  397. }
  398. if ( href != '#' )
  399. {
  400. setTimeout(
  401. function()
  402. {
  403. window.location.href = href;
  404. }, onClick.delayPageload
  405. );
  406. }
  407. }
  408. );
  409. }
  410. }
  411. function _initCounters( $m, counters, conf )
  412. {
  413. // Refactor counter class
  414. $('em.' + conf.counterClass, $m).removeClass( conf.counterClass ).addClass( cls( 'counter' ) );
  415. // Add counters
  416. if ( counters.add )
  417. {
  418. $('.' + cls( 'submenu' ), $m).each(
  419. function()
  420. {
  421. var $s = $(this),
  422. id = $s.attr( 'id' );
  423. if ( id && id.length )
  424. {
  425. var $c = $( '<em class="' + cls( 'counter' ) + '" />' ),
  426. $a = $('a.' + cls( 'subopen' ), $m).filter( '[href="#' + id + '"]' );
  427. if ( !$a.parent().find( 'em.' + cls( 'counter' ) ).length )
  428. {
  429. $a.before( $c );
  430. }
  431. }
  432. }
  433. );
  434. }
  435. // Bind count event
  436. if ( counters.count )
  437. {
  438. $('em.' + cls( 'counter' ), $m).each(
  439. function()
  440. {
  441. var $c = $(this),
  442. $s = $('ul' + $c.next().attr( 'href' ), $m);
  443. $c.bind(
  444. evt( 'count' ),
  445. function( e )
  446. {
  447. e.preventDefault();
  448. e.stopPropagation();
  449. var $lis = $s.children()
  450. .not( '.' + cls( 'label' ) )
  451. .not( '.' + cls( 'subtitle' ) )
  452. .not( '.' + cls( 'noresult' ) )
  453. .not( '.' + cls( 'noresults' ) );
  454. $c.html( $lis.length );
  455. }
  456. );
  457. }
  458. ).trigger( evt( 'count' ) );
  459. }
  460. }
  461. function _initSearch( $m, search )
  462. {
  463. if ( search.add )
  464. {
  465. var $s = $( '<div class="' + cls( 'search' ) + '" />' ).prependTo( $m );
  466. $s.append( '<input placeholder="' + search.placeholder + '" type="text" autocomplete="off" />' );
  467. if ( search.noResults )
  468. {
  469. $('ul', $m).not( '.' + cls( 'submenu' ) ).append( '<li class="' + cls( 'noresults' ) + '">' + search.noResults + '</li>' );
  470. }
  471. }
  472. if ( search.search )
  473. {
  474. var $s = $('div.' + cls( 'search' ), $m),
  475. $i = $('input', $s);
  476. var $labels = $('li.' + cls( 'label' ), $m),
  477. $counters = $('em.' + cls( 'counter' ), $m),
  478. $items = $('li', $m)
  479. .not( '.' + cls( 'subtitle' ) )
  480. .not( '.' + cls( 'label' ) )
  481. .not( '.' + cls( 'noresults' ) );
  482. var _searchText = '> a';
  483. if ( !search.showLinksOnly )
  484. {
  485. _searchText += ', > span';
  486. }
  487. $i.bind(
  488. evt( 'keyup' ),
  489. function()
  490. {
  491. var query = $i.val().toLowerCase();
  492. // search through items
  493. $items.add( $labels ).addClass( cls( 'noresult' ) );
  494. $items.each(
  495. function()
  496. {
  497. var $t = $(this);
  498. if ( $(_searchText, $t).text().toLowerCase().indexOf( query ) > -1 )
  499. {
  500. $t.add( $t.prevAll( '.' + cls( 'label' ) ).first() ).removeClass( cls( 'noresult' ) );
  501. }
  502. }
  503. );
  504. // update parent for submenus
  505. $( $('ul.' + cls( 'submenu' ), $m).get().reverse() ).each(
  506. function()
  507. {
  508. var $t = $(this),
  509. $p = null,
  510. id = $t.attr( 'id' ),
  511. $i = $t.find( 'li' )
  512. .not( '.' + cls( 'subtitle' ) )
  513. .not( '.' + cls( 'label' ) )
  514. .not( '.' + cls( 'noresult' ) );
  515. if ( id && id.length )
  516. {
  517. var $p = $('a.' + cls( 'subopen' ), $m).filter( '[href="#' + id + '"]' ).parent();
  518. }
  519. if ( $i.length )
  520. {
  521. if ( $p )
  522. {
  523. $p.removeClass( cls( 'noresult' ) );
  524. $p.removeClass( cls( 'nosubresult' ) );
  525. }
  526. }
  527. else
  528. {
  529. $t.trigger( evt( 'close' ) );
  530. if ( $p )
  531. {
  532. $p.addClass( cls( 'nosubresult' ) );
  533. }
  534. }
  535. }
  536. );
  537. // show/hide no results message
  538. $m[ $items.not( '.' + cls( 'noresult' ) ).length ? 'removeClass' : 'addClass' ]( cls( 'noresults' ) );
  539. // update counters
  540. $counters.trigger( evt( 'count' ) );
  541. }
  542. );
  543. }
  544. }
  545. function _initOpenClose( $m, $p )
  546. {
  547. // toggle menu
  548. var id = $m.attr( 'id' );
  549. if ( id && id.length )
  550. {
  551. click( 'a[href="#' + id + '"]',
  552. function()
  553. {
  554. $m.trigger( evt( 'toggle' ) );
  555. }
  556. );
  557. }
  558. // close menu
  559. var id = $p.attr( 'id' );
  560. if ( id && id.length )
  561. {
  562. click( 'a[href="#' + id + '"]',
  563. function()
  564. {
  565. $m.trigger( evt( 'close' ) );
  566. }
  567. );
  568. }
  569. // open submenu
  570. click( $('a.' + cls( 'subopen' ) + ', ' + 'a.' + cls( 'subclose' ), $m),
  571. function()
  572. {
  573. $( $(this).attr( 'href' ) ).trigger( evt( 'toggle' ) );
  574. }
  575. );
  576. }
  577. function openMenu( $m, p )
  578. {
  579. var _scrollTop = findScrollTop();
  580. // resize page
  581. var _w = 0;
  582. $wndw.bind(
  583. evt( 'resize' ),
  584. function( e )
  585. {
  586. var nw = $wndw.width();
  587. if ( nw != _w )
  588. {
  589. _w = nw;
  590. $page
  591. .attr( 'style', $page.data( dta( 'style' ) ) )
  592. .width( nw );
  593. }
  594. }
  595. );
  596. // store style and position
  597. $page
  598. .data( dta( 'style' ), $page.attr( 'style' ) || '' )
  599. .data( dta( 'scrollTop' ), _scrollTop )
  600. .width( $page.outerWidth() )
  601. .css( 'top', -_scrollTop );
  602. // open
  603. $m.addClass( cls( 'opened' ) );
  604. $html.addClass( cls( 'opened' ) ).addClass( cls( p ) );
  605. setTimeout(
  606. function()
  607. {
  608. // opened
  609. $html.addClass( cls( 'opening' ) );
  610. }, 25
  611. );
  612. return 'open';
  613. }
  614. function closeMenu( $m, o )
  615. {
  616. // close
  617. $html.removeClass( cls( 'opening' ) );
  618. setTimeout(
  619. function()
  620. {
  621. // closed
  622. $html.removeClass( cls( 'opened' ) ).removeClass( cls( o.position ) );
  623. $m.removeClass( cls( 'opened' ) );
  624. // restore style and position
  625. $page.attr( 'style', $page.data( dta( 'style' ) ) );
  626. $wndw.unbind( evt( 'resize' ) );
  627. if ( $scrollTopNode )
  628. {
  629. $scrollTopNode.scrollTop( $page.data( dta( 'scrollTop' ) ) );
  630. }
  631. }, o.configuration.slideDuration + 25
  632. );
  633. return 'close';
  634. }
  635. function openSubmenuHorizontal( $t, o )
  636. {
  637. $t.prevAll( 'ul' ).addClass( cls( 'subopened' ) );
  638. $t.nextAll( 'ul' ).removeClass( cls( 'subopened' ) );
  639. $t.removeClass( cls( 'subopened' ) ).addClass( cls( 'opened' ) );
  640. setTimeout(
  641. function()
  642. {
  643. $t.nextAll( 'ul' ).removeClass( cls( 'opened' ) );
  644. }, o.configuration.slideDuration + 25
  645. );
  646. return 'open';
  647. }
  648. function closeSubmenuHorizontal( $t, o )
  649. {
  650. $t.prevAll( 'ul.' + cls( 'opened' ) ).first().trigger( evt( 'open' ) );
  651. return 'close';
  652. }
  653. function findScrollTop()
  654. {
  655. if ( !$scrollTopNode )
  656. {
  657. if ( $('html').scrollTop() != 0 )
  658. {
  659. $scrollTopNode = $('html');
  660. }
  661. else if ( $('body').scrollTop() != 0 )
  662. {
  663. $scrollTopNode = $('body');
  664. }
  665. }
  666. return ( $scrollTopNode ) ? $scrollTopNode.scrollTop() - 1 : 0;
  667. }
  668. function click( $b, fn )
  669. {
  670. if ( typeof $b == 'string' )
  671. {
  672. $b = $( $b );
  673. }
  674. $b.bind(
  675. evt( 'click' ),
  676. function( e )
  677. {
  678. e.preventDefault();
  679. e.stopPropagation();
  680. fn.call( this, e );
  681. }
  682. );
  683. }
  684. function cls( c )
  685. {
  686. return 'mmenu-' + c;
  687. }
  688. function dta( d )
  689. {
  690. return 'mmenu-' + d;
  691. }
  692. function evt( e )
  693. {
  694. return e + '.mmenu';
  695. }
  696. })( jQuery );