PageRenderTime 4344ms CodeModel.GetById 49ms RepoModel.GetById 5ms app.codeStats 0ms

/jquery-spot_menu.js

https://github.com/brokenseal/jquery-spot_menu
JavaScript | 236 lines | 134 code | 52 blank | 50 comment | 21 complexity | 0cf3d34b3174c554fba65390ec4e5711 MD5 | raw file
  1. /*
  2. A brand new jquery menu plugin like you've never seen before!
  3. Author: Davide Callegari - http://www.brokenseal.it/
  4. Home page: http://github.com/brokenseal/jquery-spot_menu/
  5. License: MIT
  6. */
  7. ;(function($){
  8. var
  9. defaultOptions= {
  10. addFilter: true // wether you want to add the filter or not
  11. ,filterText: true // wether you want to filter the list by text or not
  12. ,filterAttributes: [ 'rel' ] // a list of attributes that the filter will search against the filter term
  13. ,maxHeight: 500 // a max height to apply to the list
  14. ,filterPlaceHolderText: 'Filter...' // text placeholder for the input (for localization/customization purposes)
  15. ,preventDefault: true // wether to prevent default actions on the spot element
  16. }
  17. ,closeButton= {
  18. klass: 'ui-spotmenu-closebutton'
  19. // cloning is faster than creating
  20. ,element: $('<a href="#" class="ui-spotmenu-closebutton" style="display:none;">close</a>')
  21. }
  22. // cloning is faster than creating
  23. ,filterField= $('<li class="ui-spotmenu-filterspot"><input type="text" name="ui-spotmenu-filterspot" value="" class="ui-spotmenu-activeplaceholder"/></li>')
  24. // private methods
  25. ,openSpot= function(options, spot, spotted){
  26. // add open class to the spot
  27. spot.addClass('ui-spotmenu-open');
  28. // show the spotted list
  29. spotted.slideDown();
  30. // show the close button
  31. spot.children('.'+closeButton.klass).show();
  32. // hide the siblings elements
  33. spot.parent().siblings('li').slideUp();
  34. }
  35. ,closeSpot= function(options, spot, spotted){
  36. // remove the open class
  37. spot.removeClass('ui-spotmenu-open');
  38. // hide the spotted list
  39. spotted.slideUp();
  40. // hide the close button
  41. spot.children('.'+closeButton.klass).hide();
  42. // show the siblings elements
  43. spot.parent().siblings('li').slideDown();
  44. // trigger a click event on the close button of any sub element
  45. // of the siblings elements
  46. spot.siblings().find('.'+closeButton.klass).click();
  47. // unfilter the spot
  48. unFilterSpot(options, spot, spotted);
  49. // and empty the filter inside the spotted element
  50. emptyFilter(options, spotted.children('.ui-spotmenu-filterspot').children('input'));
  51. }
  52. ,filterSpot= function(options, filterTerm, spot, spotted){
  53. var
  54. elementsToFilter= spotted.children().not('.ui-spotmenu-filterspot')
  55. ,filterAttributes= options.filterAttributes
  56. ;
  57. if(!filterTerm) {
  58. unFilterSpot(options, spot, spotted);
  59. return;
  60. }
  61. elementsToFilter.each(function(){
  62. var
  63. element= $(this)
  64. ,len= filterAttributes.length
  65. ,valueToFilter= ''
  66. ;
  67. if(options.filterText) {
  68. valueToFilter= element.text() + ' '
  69. }
  70. while(len--) {
  71. valueToFilter+= element.attr(filterAttributes[len]) || '';
  72. if(valueToFilter && valueToFilter.search(filterTerm) < 0) {
  73. element.hide();
  74. } else {
  75. element.show();
  76. }
  77. }
  78. });
  79. }
  80. ,unFilterSpot= function(options, spot, spotted){
  81. spotted.children().show();
  82. }
  83. ,emptyFilter= function(options, filterField){
  84. filterField.addClass('ui-spotmenu-activeplaceholder');
  85. filterField.val(options.filterPlaceHolderText);
  86. }
  87. ;
  88. // the main plugin function
  89. $.fn.spotMenu= function(options){
  90. // merge provided options with default options
  91. options= $.fn.extend(defaultOptions, options);
  92. return this.each(function(){
  93. var
  94. spotMenu= $(this)
  95. ,spots= spotMenu.find('.spot')
  96. ;
  97. // manage every single spot
  98. spots.each(function(e){
  99. var
  100. newCloseButton= closeButton.element.clone() // cloning is faster than creating
  101. ,newFilterField
  102. ,spot= $(this)
  103. ;
  104. // append the close button to the spot
  105. spot.append(newCloseButton);
  106. // bind the click on the close button so that it could actually
  107. // close the spotted list
  108. newCloseButton.click(function(e){
  109. var
  110. _this= $(this)
  111. ;
  112. // stop any kind of event propagation and default action from the browser
  113. e.preventDefault();
  114. e.stopPropagation();
  115. closeSpot(options, _this.parent(), _this.parent().siblings('ul'));
  116. });
  117. if(spot.hasClass('last') && options.addFilter) {
  118. // create a new filter field
  119. newFilterField= filterField.clone(); // cloning is faster than creating
  120. // append it to the spotted ul
  121. spot.siblings('ul').prepend(newFilterField);
  122. // add the placeholder text
  123. newFilterField.children('input').val(options.filterPlaceHolderText);
  124. // bind any key press inside the field
  125. newFilterField.children('input').bind('keypress, keydown, keyup', function(e){
  126. var filterField= $(this);
  127. if(e.keyCode == 13) {
  128. // in case of an enter key press, do nothing
  129. // if the menu is placed inside a form, it could involuntarily submit it
  130. e.preventDefault();
  131. } else if(e.keyCode == 27) {
  132. // in case of an esc key press, erase the current filter term
  133. filterField.val('');
  134. }
  135. filterSpot(options, filterField.val(), spot, spot.siblings('ul'));
  136. if(e.keyCode == 27) {
  137. // in case of an esc key press, blur the field
  138. // after having filtered/cleaned the spot
  139. filterField.blur();
  140. }
  141. }).focus(function(){
  142. // hide the place holder, if necessary
  143. var filterField= $(this);
  144. if(filterField.hasClass('ui-spotmenu-activeplaceholder')) {
  145. filterField.removeClass('ui-spotmenu-activeplaceholder');
  146. filterField.val('');
  147. }
  148. }).blur(function(){
  149. // show the place holder, if necessary
  150. var filterField= $(this);
  151. if(filterField.val() == '' && !filterField.hasClass('ui-spotmenu-activeplaceholder')) {
  152. emptyFilter(options, filterField);
  153. }
  154. });
  155. }
  156. });
  157. // open the spot on click, if it's not already open
  158. spots.click(function(e){
  159. var
  160. spot= $(this)
  161. ;
  162. // wether to prevent default actions on the spot element
  163. if(options.preventDefault) {
  164. e.preventDefault();
  165. }
  166. // if the spot is already open, do nothing
  167. // the only way to close a spot is by clicking the close button
  168. if(spot.hasClass('open')) {
  169. return;
  170. }
  171. // open the spot
  172. openSpot(options, spot, spot.siblings('ul'));
  173. });
  174. });
  175. };
  176. $.fn.destroySpotMenu= function(){
  177. // TODO
  178. // remove the search field
  179. // remove the close button
  180. // remove any class specific of the plugin, applied to the menu
  181. };
  182. })(jQuery);