/wp-content/plugins/the-events-calendar/common/src/resources/js/bumpdown.js

https://github.com/livinglab/openlab · JavaScript · 293 lines · 207 code · 54 blank · 32 comment · 24 complexity · bbe7d6bf2a6436db13a37259b3fa026a MD5 · raw file

  1. (function( $, _ ) {
  2. 'use strict';
  3. // Configure on Document ready for the default trigger
  4. $( function() {
  5. $( '.tribe-bumpdown-trigger' ).bumpdown();
  6. } );
  7. $.fn.bumpdown = function() {
  8. var $document = $( document ),
  9. selectors = {
  10. // A template for the ID if we don't have one already
  11. ID: 'tribe-bumpdown-',
  12. data_trigger: function( ID ) {
  13. return '[data-trigger="' + ID + '"]';
  14. },
  15. bumpdown: '.tribe-bumpdown',
  16. content: '.tribe-bumpdown-content',
  17. trigger: '.tribe-bumpdown-trigger',
  18. hover_trigger: '.tribe-bumpdown-trigger:not(.tribe-bumpdown-nohover)',
  19. close: '.tribe-bumpdown-close',
  20. permanent: '.tribe-bumpdown-permanent',
  21. active: '.tribe-bumpdown-active',
  22. },
  23. methods = {
  24. open: function( $bumpdown ) {
  25. var data = $bumpdown.data( 'bumpdown' ),
  26. width_rule = data.$trigger.data( 'width-rule' );
  27. if ( $bumpdown.is( ':visible' ) ) {
  28. return;
  29. }
  30. // Adds a Class to signal it's active
  31. data.$trigger.addClass( selectors.active.replace( '.', '' ) );
  32. var $content = $bumpdown.find( selectors.content );
  33. if ( 'string' === typeof width_rule && 'all-triggers' === width_rule ) {
  34. var min_width = 600;
  35. var trigger_position = 0;
  36. $( selectors.trigger ).each( function() {
  37. var $el = $( this );
  38. // only attempt to align items with a width rule
  39. if ( ! $el.data( 'width-rule' ) ) {
  40. return;
  41. }
  42. var position = $el.position();
  43. if ( position.left > trigger_position ) {
  44. trigger_position = position.left;
  45. }
  46. } );
  47. if ( trigger_position ) {
  48. trigger_position = trigger_position > min_width ? trigger_position : min_width;
  49. $content.css( 'max-width', trigger_position + 'px' );
  50. }
  51. }
  52. $content.prepend( '<a class="tribe-bumpdown-close" title="Close"><i class="dashicons dashicons-no"></i></a>' ); // eslint-disable-line max-len
  53. $content.prepend( '<span class="tribe-bumpdown-arrow"></span>' );
  54. methods.arrow( $bumpdown );
  55. $bumpdown.data( 'preventClose', true );
  56. $bumpdown.slideDown( 'fast', function() {
  57. $bumpdown.data( 'preventClose', false );
  58. } );
  59. },
  60. close: function( $bumpdown ) {
  61. var data = $bumpdown.data( 'bumpdown' );
  62. if ( ! $bumpdown.is( ':visible' ) || $bumpdown.data( 'preventClose' ) ) {
  63. return;
  64. }
  65. // When we close we reset the flag about hoverintent
  66. $( this ).removeData( 'is_hoverintent_queued' );
  67. $bumpdown.find( '.tribe-bumpdown-close, .tribe-bumpdown-arrow' ).remove();
  68. $bumpdown.not( '.tribe-bumpdown-trigger' ).slideUp( 'fast' );
  69. data.$trigger.removeClass( selectors.active.replace( '.', '' ) );
  70. },
  71. arrow: function( $bumpdown ) {
  72. var data = $bumpdown.data( 'bumpdown' ),
  73. arrow;
  74. arrow = Math.ceil(
  75. data.$trigger.position().left - (
  76. 'block' === data.type
  77. ? data.$parent.offset().left
  78. : 0
  79. )
  80. );
  81. data.$bumpdown.find( '.tribe-bumpdown-arrow' ).css( 'left', arrow ); // eslint-disable-line es5/no-es6-methods,max-len
  82. }
  83. };
  84. $( window ).on( {
  85. 'resize.bumpdown': function() {
  86. $document.find( selectors.active ).each( function() {
  87. methods.arrow( $( this ) );
  88. } );
  89. }
  90. } );
  91. if ( 'function' === typeof $.fn.hoverIntent ) {
  92. $document
  93. // Use hoverIntent to make sure we are not opening Bumpdown on a fast hover
  94. .hoverIntent( {
  95. over: function() {
  96. var data = $( this ).data( 'bumpdown' );
  97. // Flags that it's open
  98. data.$trigger.data( 'is_hoverintent_queued', false );
  99. // Actually opens
  100. data.$bumpdown.trigger( 'open.bumpdown' );
  101. },
  102. out: function() {}, // Prevents Notice on JS
  103. selector: selectors.hover_trigger,
  104. interval: 200,
  105. } );
  106. }
  107. $document
  108. // Setup Events on Trigger
  109. .on( {
  110. mouseenter: function() {
  111. if ( $( this ).data( 'is_hoverintent_queued' ) === undefined ) {
  112. // Flags that hoverIntent will take care of the
  113. $( this ).data( 'is_hoverintent_queued', true );
  114. }
  115. },
  116. click: function( e ) {
  117. var data = $( this ).data( 'bumpdown' );
  118. e.preventDefault();
  119. e.stopPropagation();
  120. if ( data.$bumpdown.is( ':visible' ) ) {
  121. // Makes sure we are not dealing with the first enter of the mouse
  122. if ( data.$trigger.data( 'is_hoverintent_queued' ) ) {
  123. // On double click it will close, kinda like forcing the closing
  124. return data.$trigger.data( 'is_hoverintent_queued', false );
  125. }
  126. data.$bumpdown.trigger( 'close.bumpdown' );
  127. } else {
  128. data.$bumpdown.trigger( 'open.bumpdown' );
  129. }
  130. },
  131. 'open.bumpdown': function() { methods.open( $( this ) ); },
  132. 'close.bumpdown': function() { methods.close( $( this ) ); }
  133. }, selectors.trigger )
  134. // Setup Events on Trigger
  135. .on( {
  136. click: function( e ) {
  137. var data = $( this ).parents( selectors.bumpdown ).first().data( 'bumpdown' );
  138. e.preventDefault();
  139. e.stopPropagation();
  140. if ( 'undefined' === typeof data ) {
  141. return;
  142. }
  143. if ( 'undefined' === typeof data.$bumpdown ) {
  144. return;
  145. }
  146. data.$bumpdown.trigger( 'close.bumpdown' );
  147. },
  148. }, selectors.close )
  149. // Triggers closing when clicking on the document
  150. .on( 'click', function( e ) {
  151. var $target = $( e.target ),
  152. is_bumpdown = $target.is( selectors.bumpdown )
  153. || 0 !== $target.parents( selectors.bumpdown ).length;
  154. if ( is_bumpdown ) {
  155. return;
  156. }
  157. $( selectors.trigger ).not( selectors.permanent ).trigger( 'close.bumpdown' );
  158. } )
  159. // Creates actions on the actual bumpdown
  160. .on( {
  161. 'open.bumpdown': function() { methods.open( $( this ) ); },
  162. 'close.bumpdown': function() { methods.close( $( this ) ); }
  163. }, selectors.bumpdown );
  164. // Configure all the fields
  165. return this.each( function() {
  166. var data = {
  167. // Store the jQuery Elements
  168. $trigger: $( this ),
  169. $parent: null,
  170. $bumpdown: null,
  171. // Store other Variables
  172. ID: null,
  173. html: null,
  174. type: 'block',
  175. // Flags
  176. is_permanent: false,
  177. };
  178. // We need a ID for this Bumpdown
  179. data.ID = data.$trigger.attr( 'id' );
  180. // If we currently don't have the ID, set it up
  181. if ( ! data.ID ) {
  182. data.ID = _.uniqueId( selectors.ID );
  183. // Apply the given ID to
  184. data.$trigger.attr( 'id', data.ID );
  185. }
  186. // We fetch from `[data-bumpdown]` attr the possible HTML for this Bumpdown
  187. data.html = data.$trigger.attr( 'data-bumpdown' );
  188. data.html = '<div class="tribe-bumpdown-content">' + data.html + '</div>';
  189. // We fetch from `[data-bumpdown-class]` attr the possible class(es) for this Bumpdown
  190. data.class = data.$trigger.attr( 'data-bumpdown-class' );
  191. // Flags about if this bumpdown is permanent,
  192. // meaning it only closes when clicking on the close button or the trigger
  193. data.is_permanent = data.$trigger.is( selectors.permanent );
  194. // Fetch the first Block-Level parent
  195. data.$parent = data.$trigger.parents().filter( function() {
  196. return -1 < $.inArray(
  197. $( this ).css( 'display' ),
  198. [ 'block', 'table', 'table-cell', 'table-row' ]
  199. );
  200. } ).first();
  201. if ( ! data.html ) {
  202. data.$bumpdown = $( selectors.data_trigger( data.ID ) );
  203. data.type = 'block';
  204. } else {
  205. data.type = data.$parent.is( 'td, tr, td, table' ) ? 'table' : 'block';
  206. if ( 'table' === data.type ) {
  207. data.$bumpdown = $( '<td>' )
  208. .attr( { colspan: 2 } )
  209. .addClass( 'tribe-bumpdown-cell' )
  210. .html( data.html );
  211. var classes = data.class ? 'tribe-bumpdown-row ' + data.class : 'tribe-bumpdown-row',
  212. $row = $( '<tr>' ).append( data.$bumpdown ).addClass( classes );
  213. data.$parent = data.$trigger.parents( 'tr' ).first();
  214. data.$parent.after( $row );
  215. } else {
  216. data.$bumpdown = $( '<div>' ).addClass( 'tribe-bumpdown-block' ).html( data.html );
  217. data.$trigger.after( data.$bumpdown );
  218. }
  219. }
  220. // Setup data on trigger
  221. data.$trigger
  222. .data( 'bumpdown', data )
  223. // Mark this as the trigger
  224. .addClass( selectors.trigger.replace( '.', '' ) );
  225. // Setup data on actual bumpdown
  226. data.$bumpdown
  227. .data( 'bumpdown', data )
  228. // Mark it as the Bumpdown
  229. .addClass( selectors.bumpdown.replace( '.', '' ) );
  230. // support our dependency library
  231. if ( data.$trigger.data( 'depends' ) ) {
  232. var field_ids = data.$trigger.data( 'depends' );
  233. $( document ).on( 'change', field_ids, function() {
  234. methods.close( data.$bumpdown );
  235. } );
  236. }
  237. });
  238. };
  239. }( jQuery, window.underscore || window._ ) );