search-widget-admin.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /* globals jetpack_search_filter_admin, jQuery, analytics */
  2. ( function( $, args ) {
  3. var defaultFilterCount = ( 'undefined' !== typeof args && args.defaultFilterCount ) ?
  4. args.defaultFilterCount :
  5. 5; // Just in case we couldn't find the defaultFiltercount arg
  6. $( document ).ready( function() {
  7. setListeners();
  8. window.JetpackSearch = window.JetpackSearch || {};
  9. window.JetpackSearch.addFilter = addFilter;
  10. // Initialize Tracks
  11. if ( 'undefined' !== typeof analytics && args.tracksUserData ) {
  12. analytics.initialize( args.tracksUserData.userid, args.tracksUserData.username );
  13. }
  14. } );
  15. function generateFilterTitlePlaceholder( container ) {
  16. var placeholder = null,
  17. isModified = null,
  18. isMonth = null,
  19. type = container.find( '.filter-select' ).val();
  20. if ( 'taxonomy' === type ) {
  21. placeholder = container.find('.taxonomy-select option:selected').text().trim();
  22. } else if ( 'date_histogram' === type && args && args.i18n ) {
  23. isModified = ( -1 !== container.find( '.date-field-select' ).val().indexOf( 'modified' ) );
  24. isMonth = ( 'month' === container.find( '.date-interval-select' ).val() );
  25. if ( isMonth ) {
  26. placeholder = isModified ?
  27. args.i18n.monthUpdated :
  28. args.i18n.month;
  29. } else {
  30. placeholder = isModified ?
  31. args.i18n.yearUpdated :
  32. args.i18n.year;
  33. }
  34. } else {
  35. placeholder = container.find('.filter-select option:selected').text().trim();
  36. }
  37. $( container ).find('.jetpack-search-filters-widget__title input').prop( 'placeholder', placeholder );
  38. }
  39. var addFilter = function( filtersContainer, args ) {
  40. var template = _.template(
  41. filtersContainer
  42. .closest( '.jetpack-search-filters-widget' )
  43. .find( '.jetpack-search-filters-widget__filter-template' )
  44. .html()
  45. );
  46. generateFilterTitlePlaceholder( filtersContainer.append( template( args ) ) );
  47. };
  48. var setListeners = function( widget ) {
  49. widget = ( 'undefined' === typeof widget ) ?
  50. $( '.jetpack-search-filters-widget' ):
  51. widget;
  52. var getContainer = function( el ) {
  53. return $( el ).closest('.jetpack-search-filters-widget__filter');
  54. };
  55. widget.on( 'change', '.filter-select', function() {
  56. var select = $( this ),
  57. selectVal = select.val(),
  58. eventArgs = {
  59. is_customizer: args.tracksEventData.is_customizer
  60. };
  61. eventArgs.type = selectVal;
  62. select
  63. .closest( '.jetpack-search-filters-widget__filter' )
  64. .attr( 'class', 'jetpack-search-filters-widget__filter' )
  65. .addClass( 'is-' + selectVal );
  66. generateFilterTitlePlaceholder( getContainer( this ) );
  67. trackAndBumpMCStats( 'changed_filter_type', eventArgs );
  68. } );
  69. // enable showing sort controls only if showing search box is enabled
  70. widget.on( 'change', '.jetpack-search-filters-widget__search-box-enabled', function() {
  71. var checkbox = $( this ),
  72. checkboxVal = checkbox.is(':checked'),
  73. filterParent = checkbox.closest( '.jetpack-search-filters-widget' ),
  74. sortControl = filterParent.find( '.jetpack-search-filters-widget__sort-controls-enabled' );
  75. filterParent.toggleClass( 'hide-post-types' );
  76. if ( checkboxVal ) {
  77. sortControl.removeAttr( 'disabled' );
  78. trackAndBumpMCStats( 'enabled_search_box', args.tracksEventData );
  79. } else {
  80. sortControl.prop( 'checked', false );
  81. sortControl.prop( 'disabled', true );
  82. trackAndBumpMCStats( 'disabled_search_box', args.tracksEventData );
  83. }
  84. } );
  85. widget.on( 'change', '.jetpack-search-filters-widget__sort-controls-enabled', function() {
  86. if ( $( this ).is( ':checked' ) ) {
  87. trackAndBumpMCStats( 'enabled_sort_controls', args.tracksEventData );
  88. } else {
  89. trackAndBumpMCStats( 'disabled_sort_controls', args.tracksEventData );
  90. }
  91. } );
  92. widget.on( 'click', '.jetpack-search-filters-widget__post-types-select input[type="checkbox"]', function( e ) {
  93. var t = $( this );
  94. var siblingsChecked = t.closest( '.jetpack-search-filters-widget' )
  95. .find( '.jetpack-search-filters-widget__post-types-select input[type="checkbox"]:checked' );
  96. if ( 0 === siblingsChecked.length ) {
  97. e.preventDefault();
  98. e.stopPropagation();
  99. trackAndBumpMCStats( 'attempted_no_post_types', args.tracksEventData );
  100. }
  101. } );
  102. widget.on( 'change', '.jetpack-search-filters-widget__post-types-select input[type="checkbox"]', function() {
  103. var t = $( this );
  104. var eventArgs = {
  105. is_customizer: args.tracksEventData.is_customizer,
  106. post_type: t.val()
  107. };
  108. if ( wp && wp.customize ) {
  109. wp.customize.state( 'saved' ).set( false );
  110. }
  111. if ( t.is( ':checked' ) ) {
  112. trackAndBumpMCStats( 'added_post_type', eventArgs );
  113. } else {
  114. trackAndBumpMCStats( 'removed_post_type', eventArgs );
  115. }
  116. } );
  117. widget.on( 'change', '.jetpack-search-filters-widget__sort-order', function() {
  118. var eventArgs = {
  119. is_customizer: args.tracksEventData.is_customizer
  120. };
  121. eventArgs.order = $( this ).val();
  122. if ( wp && wp.customize ) {
  123. wp.customize.state( 'saved' ).set( false );
  124. }
  125. trackAndBumpMCStats( 'changed_sort_order', eventArgs );
  126. } );
  127. widget.on( 'change', '.jetpack-search-filters-widget__taxonomy-select select', function() {
  128. var eventArgs = {
  129. is_customizer: args.tracksEventData.is_customizer
  130. };
  131. eventArgs.taxonomy = $( this ).val();
  132. generateFilterTitlePlaceholder( getContainer( this ) );
  133. if ( wp && wp.customize ) {
  134. wp.customize.state( 'saved' ).set( false );
  135. }
  136. trackAndBumpMCStats( 'changed_taxonomy', eventArgs );
  137. } );
  138. widget.on( 'change', 'select.date-field-select', function() {
  139. var eventArgs = {
  140. is_customizer: args.tracksEventData.is_customizer
  141. };
  142. eventArgs.field = $( this ).val();
  143. generateFilterTitlePlaceholder( getContainer( this ) );
  144. if ( wp && wp.customize ) {
  145. wp.customize.state( 'saved' ).set( false );
  146. }
  147. trackAndBumpMCStats( 'changed_date_field', eventArgs );
  148. } );
  149. widget.on( 'change', 'select.date-interval-select', function() {
  150. var eventArgs = {
  151. is_customizer: args.tracksEventData.is_customizer
  152. };
  153. eventArgs.interval = $( this ).val();
  154. generateFilterTitlePlaceholder( getContainer( this ) );
  155. if ( wp && wp.customize ) {
  156. wp.customize.state( 'saved' ).set( false );
  157. }
  158. trackAndBumpMCStats( 'changed_date_interval', eventArgs );
  159. } );
  160. widget.on( 'change', 'input.filter-count', function() {
  161. var eventArgs = {
  162. is_customizer: args.tracksEventData.is_customizer
  163. };
  164. eventArgs.count = $( this ).val();
  165. if ( wp && wp.customize ) {
  166. wp.customize.state( 'saved' ).set( false );
  167. }
  168. trackAndBumpMCStats( 'changed_filter_count', eventArgs );
  169. } );
  170. // add filter button
  171. widget.on( 'click', '.jetpack-search-filters-widget__add-filter', function( e ) {
  172. e.preventDefault();
  173. var filtersContainer = $( this )
  174. .closest( '.jetpack-search-filters-widget' )
  175. .find( '.jetpack-search-filters-widget__filters' );
  176. addFilter( filtersContainer, {
  177. type: 'taxonomy',
  178. taxonomy: '',
  179. post_type: '',
  180. field: '',
  181. interval: '',
  182. count: defaultFilterCount,
  183. name_placeholder: '',
  184. name: ''
  185. } );
  186. if ( wp && wp.customize ) {
  187. wp.customize.state( 'saved' ).set( false );
  188. }
  189. // Trigger change event to let legacy widget admin know the widget state is "dirty"
  190. filtersContainer
  191. .find( '.jetpack-search-filters-widget__filter' )
  192. .find( 'input, textarea, select' )
  193. .change();
  194. trackAndBumpMCStats( 'added_filter', args.tracksEventData );
  195. } );
  196. widget.on( 'click', '.jetpack-search-filters-widget__controls .delete', function( e ) {
  197. e.preventDefault();
  198. var filter = $( this ).closest( '.jetpack-search-filters-widget__filter' ),
  199. eventArgs = {
  200. is_customizer: args.tracksEventData.is_customizer
  201. };
  202. eventArgs.type = filter.find( '.filter-select' ).val();
  203. switch ( eventArgs.type ) {
  204. case 'taxonomy':
  205. eventArgs.taxonomy = filter.find( '.jetpack-search-filters-widget__taxonomy-select select' ).val();
  206. break;
  207. case 'date_histogram':
  208. eventArgs.dateField = filter.find( '.jetpack-search-filters-widget__date-histogram-select:first select' ).val();
  209. eventArgs.dateInterval = filter.find( '.jetpack-search-filters-widget__date-histogram-select:nth-child( 2 ) select' ).val();
  210. break;
  211. }
  212. eventArgs.filterCount = filter.find( '.filter-count' ).val();
  213. trackAndBumpMCStats( 'deleted_filter', eventArgs );
  214. filter.find( 'input, textarea, select' ).change();
  215. filter.remove();
  216. if ( wp && wp.customize ) {
  217. wp.customize.state( 'saved' ).set( false );
  218. }
  219. } );
  220. // make the filters sortable
  221. $( '.jetpack-search-filters-widget__filters' ).sortable( {
  222. placeholder: 'jetpack-search-filters-widget__filter-placeholder',
  223. axis: 'y',
  224. revert: true,
  225. cancel: 'input,textarea,button,select,option,.jetpack-search-filters-widget__controls a',
  226. change: function() {
  227. if ( wp && wp.customize ) {
  228. wp.customize.state( 'saved' ).set( false );
  229. }
  230. },
  231. update: function( e, ui ) {
  232. $( ui.item ).find( 'input, textarea, select' ).change();
  233. }
  234. } )
  235. .disableSelection();
  236. };
  237. // When widgets are updated, remove and re-add listeners
  238. $( document ).on( 'widget-updated widget-added', function( e, widget ) {
  239. widget = $( widget );
  240. var id = widget.attr( 'id' ),
  241. isJetpackSearch = ( id && ( -1 !== id.indexOf( 'jetpack-search-filters' ) ) );
  242. if ( ! isJetpackSearch ) {
  243. return;
  244. }
  245. // Intentionally not tracking widget additions and updates here as these events
  246. // seem noisy in the customizer. We'll track those via PHP.
  247. widget.off( 'change', '.filter-select' );
  248. widget.off( 'click', '.jetpack-search-filters-widget__controls .delete' );
  249. widget.off( 'change', '.jetpack-search-filters-widget__use-filters' );
  250. widget.off( 'change', '.jetpack-search-filters-widget__search-box-enabled' );
  251. widget.off( 'change', '.jetpack-search-filters-widget__sort-controls-enabled' );
  252. widget.off( 'change', '.jetpack-search-filters-widget__sort-controls-enabled' );
  253. widget.off( 'change', '.jetpack-search-filters-widget__post-type-selector' );
  254. widget.off( 'change', '.jetpack-search-filters-widget__sort-order' );
  255. widget.off( 'change', '.jetpack-search-filters-widget__taxonomy-select' );
  256. widget.off( 'change', '.jetpack-search-filters-widget__date-histogram-select:first select' );
  257. widget.off( 'change', '.jetpack-search-filters-widget__date-histogram-select:eq(1) select' );
  258. widget.off( 'click', '.jetpack-search-filters-widget__post-types-select input[type="checkbox"]' );
  259. widget.off( 'click', '.jetpack-search-filters-widget__add-filter');
  260. setListeners( widget );
  261. } );
  262. /**
  263. * This function will fire both a Tracks and MC stat.
  264. *
  265. * Tracks: Will be prefixed by 'jetpack_widget_search_' and use underscores.
  266. * MC: Will not be prefixed, and will use dashes.
  267. *
  268. * Logic borrowed from `idc-notice.js`.
  269. *
  270. * @param eventName string
  271. * @param extraProps object
  272. */
  273. function trackAndBumpMCStats( eventName, extraProps ) {
  274. if ( 'undefined' === typeof extraProps || 'object' !== typeof extraProps ) {
  275. extraProps = {};
  276. }
  277. if ( eventName && eventName.length && 'undefined' !== typeof analytics && analytics.tracks && analytics.mc ) {
  278. // Format for Tracks
  279. eventName = eventName.replace( /-/g, '_' );
  280. eventName = eventName.indexOf( 'jetpack_widget_search_' ) !== 0 ? 'jetpack_widget_search_' + eventName : eventName;
  281. analytics.tracks.recordEvent( eventName, extraProps );
  282. // Now format for MC stats
  283. eventName = eventName.replace( 'jetpack_widget_search_', '' );
  284. eventName = eventName.replace( /_/g, '-' );
  285. analytics.mc.bumpStat( 'jetpack-search-widget', eventName );
  286. }
  287. }
  288. } )( jQuery, jetpack_search_filter_admin );