widget-conditions.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /* jshint onevar: false, smarttabs: true */
  2. /* global isRtl */
  3. /* global widget_conditions_parent_pages */
  4. /* global widget_conditions_data */
  5. /* global jQuery */
  6. jQuery( function( $ ) {
  7. var widgets_shell = $( 'div#widgets-right' );
  8. if ( ! widgets_shell.length || ! $( widgets_shell ).find( '.widget-control-actions' ).length ) {
  9. widgets_shell = $( 'form#customize-controls' );
  10. }
  11. function setWidgetMargin( $widget ) {
  12. var currentWidth,
  13. extra;
  14. if ( $( 'body' ).hasClass( 'wp-customizer' ) ) {
  15. // set the inside widget 2 top this way we can see the widget settings
  16. $widget.find( '.widget-inside' ).css( 'top', 0 );
  17. return;
  18. }
  19. if ( $widget.hasClass( 'expanded' ) ) {
  20. // The expanded widget must be at least 400px wide in order to
  21. // contain the visibility settings. IE wasn't handling the
  22. // margin-left value properly.
  23. if ( $widget.attr( 'style' ) ) {
  24. $widget.data( 'original-style', $widget.attr( 'style' ) );
  25. }
  26. currentWidth = $widget.width();
  27. if ( currentWidth < 400 ) {
  28. extra = 400 - currentWidth;
  29. if ( isRtl ) {
  30. $widget.css( 'position', 'relative' ).css( 'right', '-' + extra + 'px' ).css( 'width', '400px' );
  31. } else {
  32. $widget.css( 'position', 'relative' ).css( 'left', '-' + extra + 'px' ).css( 'width', '400px' );
  33. }
  34. }
  35. } else if ( $widget.data( 'original-style' ) ) {
  36. // Restore any original inline styles when visibility is toggled off.
  37. $widget.attr( 'style', $widget.data( 'original-style' ) ).data( 'original-style', null );
  38. } else {
  39. $widget.removeAttr( 'style' );
  40. }
  41. }
  42. function moveWidgetVisibilityButton( $widget ) {
  43. var $displayOptionsButton = $widget.find( 'a.display-options' ).first();
  44. $displayOptionsButton.insertBefore( $widget.find( 'input.widget-control-save' ) );
  45. // Widgets with no configurable options don't show the Save button's container.
  46. $displayOptionsButton
  47. .parent()
  48. .removeClass( 'widget-control-noform' )
  49. .find( '.spinner' )
  50. .remove()
  51. .css( 'float', 'left' )
  52. .prependTo( $displayOptionsButton.parent() );
  53. }
  54. $( '.widget' ).each( function() {
  55. moveWidgetVisibilityButton( $( this ) );
  56. } );
  57. $( document ).on( 'widget-added', function( e, $widget ) {
  58. if ( $widget.find( 'div.widget-control-actions a.display-options' ).length === 0 ) {
  59. moveWidgetVisibilityButton( $widget );
  60. }
  61. } );
  62. widgets_shell.on( 'click.widgetconditions', 'a.add-condition', function( e ) {
  63. var $condition = $( this ).closest( 'div.condition' ),
  64. $conditionClone = $condition.clone().data( 'rule-major', '' ).data( 'rule-minor', '' ).data( 'has-children','' ).insertAfter( $condition );
  65. e.preventDefault();
  66. $conditionClone.find( 'select.conditions-rule-major' ).val( '' );
  67. $conditionClone.find( 'select.conditions-rule-minor' ).html( '' ).attr( 'disabled' );
  68. $conditionClone.find( 'span.conditions-rule-has-children' ).hide().find( 'input[type="checkbox"]' ).removeAttr( 'checked' );
  69. resetRuleIndexes( $conditionClone.closest( '.conditions' ) );
  70. } );
  71. widgets_shell.on( 'click.widgetconditions', 'a.display-options', function( e ) {
  72. var $displayOptionsButton = $( this ),
  73. $widget = $displayOptionsButton.closest( 'div.widget' );
  74. e.preventDefault();
  75. $widget.find( 'div.widget-conditional' ).toggleClass( 'widget-conditional-hide' );
  76. $( this ).toggleClass( 'active' );
  77. $widget.toggleClass( 'expanded' );
  78. setWidgetMargin( $widget );
  79. if ( $( this ).hasClass( 'active' ) ) {
  80. $widget.find( 'input[name=widget-conditions-visible]' ).val( '1' );
  81. $widget.find( '.condition' ).each( function() {
  82. buildMinorConditions( $( this ) );
  83. } );
  84. } else {
  85. $widget.find( 'input[name=widget-conditions-visible]' ).val( '0' );
  86. }
  87. } );
  88. widgets_shell.on( 'click.widgetconditions', 'a.delete-condition', function( e ) {
  89. var $condition = $( this ).closest( 'div.condition' );
  90. e.preventDefault();
  91. if ( $condition.is( ':first-child' ) && $condition.is( ':last-child' ) ) {
  92. $( this ).closest( 'div.widget' ).find( 'a.display-options' ).click();
  93. $condition.find( 'select.conditions-rule-major' ).val( '' ).change();
  94. } else {
  95. $condition.find( 'select.conditions-rule-major' ).change();
  96. $condition.detach();
  97. }
  98. resetRuleIndexes( $condition.closest( '.conditions' ) );
  99. } );
  100. widgets_shell.on( 'click.widgetconditions', 'div.widget-top', function() {
  101. var $widget = $( this ).closest( 'div.widget' ),
  102. $displayOptionsButton = $widget.find( 'a.display-options' );
  103. if ( $displayOptionsButton.hasClass( 'active' ) ) {
  104. $displayOptionsButton.attr( 'opened', 'true' );
  105. }
  106. if ( $displayOptionsButton.attr( 'opened' ) ) {
  107. $displayOptionsButton.removeAttr( 'opened' );
  108. $widget.toggleClass( 'expanded' );
  109. setWidgetMargin( $widget );
  110. }
  111. } );
  112. widgets_shell.on( 'change.widgetconditions', 'input.conditions-match-all', function() {
  113. $( this ).parents( '.widget-conditional' )
  114. .toggleClass( 'conjunction' )
  115. .toggleClass( 'intersection' );
  116. } );
  117. $( document ).on( 'change.widgetconditions', 'select.conditions-rule-major', function() {
  118. var $conditionsRuleMajor = $( this ),
  119. $conditionsRuleMinor = $conditionsRuleMajor.siblings( 'select.conditions-rule-minor:first' ),
  120. $conditionsRuleHasChildren = $conditionsRuleMajor.siblings( 'span.conditions-rule-has-children' ),
  121. $condition = $conditionsRuleMinor.closest( '.condition' );
  122. $condition.data( 'rule-minor', '' ).data( 'rule-major', $conditionsRuleMajor.val() );
  123. if ( $conditionsRuleMajor.val() ) {
  124. buildMinorConditions( $condition );
  125. } else {
  126. $conditionsRuleMajor.siblings( 'select.conditions-rule-minor' ).attr( 'disabled', 'disabled' ).html( '' );
  127. $conditionsRuleHasChildren.hide().find( 'input[type="checkbox"]' ).removeAttr( 'checked' );
  128. }
  129. } );
  130. $( document ).on( 'change.widgetconditions', 'select.conditions-rule-minor', function() {
  131. var $conditionsRuleMinor = $( this ),
  132. $conditionsRuleMajor = $conditionsRuleMinor.siblings( 'select.conditions-rule-major' ),
  133. $conditionsRuleHasChildren = $conditionsRuleMinor.siblings( 'span.conditions-rule-has-children' ),
  134. $condition = $conditionsRuleMinor.closest( '.condition' );
  135. $condition.data( 'rule-minor', $conditionsRuleMinor.val() );
  136. if ( $conditionsRuleMajor.val() === 'page' ) {
  137. if ( $conditionsRuleMinor.val() in widget_conditions_parent_pages ) {
  138. $conditionsRuleHasChildren.show();
  139. } else {
  140. $conditionsRuleHasChildren.hide().find( 'input[type="checkbox"]' ).removeAttr( 'checked' );
  141. }
  142. } else {
  143. $conditionsRuleHasChildren.hide().find( 'input[type="checkbox"]' ).removeAttr( 'checked' );
  144. }
  145. } );
  146. $( document ).on( 'widget-updated widget-synced', function( e, widget ) {
  147. widget.find( '.condition' ).each( function() {
  148. buildMinorConditions( $( this ) );
  149. } );
  150. } );
  151. function buildMinorConditions( condition ) {
  152. var minor,
  153. hasChildren,
  154. majorData,
  155. i,
  156. j,
  157. key,
  158. val,
  159. _len,
  160. _jlen,
  161. subkey,
  162. subval,
  163. optgroup,
  164. select = condition.find( '.conditions-rule-minor' ).html( '' ),
  165. major = condition.data( 'rule-major' );
  166. // Disable the select, if major rule is empty or if it's a `post_type`.
  167. // "Post Type" rule has been removed in Jetpack 4.7, and
  168. // because it breaks all other rules we should `return`.
  169. if ( ! major || 'post_type' === major ) {
  170. select.attr( 'disabled', 'disabled' );
  171. return;
  172. }
  173. minor = condition.data( 'rule-minor' );
  174. hasChildren = condition.data( 'rule-has-children' );
  175. majorData = widget_conditions_data[ major ];
  176. for ( i = 0, _len = majorData.length; i < _len; i++ ) {
  177. key = majorData[i][0];
  178. val = majorData[i][1];
  179. if ( typeof val === 'object' ) {
  180. optgroup = $( '<optgroup/>' ).attr( 'label', key );
  181. for ( j = 0, _jlen = val.length; j < _jlen; j++ ) {
  182. subkey = majorData[i][1][j][0];
  183. subval = majorData[i][1][j][1];
  184. optgroup.append( $( '<option/>' ).val( subkey ).text( decodeEntities( subval.replace( /&nbsp;/g, '\xA0' ) ) ) );
  185. }
  186. select.append( optgroup );
  187. } else {
  188. select.append( $( '<option/>' ).val( key ).text( decodeEntities( val.replace( /&nbsp;/g, '\xA0' ) ) ) );
  189. }
  190. }
  191. select.removeAttr( 'disabled' );
  192. select.val( minor );
  193. if ( 'page' === major && minor in widget_conditions_parent_pages ) {
  194. select.siblings( 'span.conditions-rule-has-children' ).show();
  195. if ( hasChildren ) {
  196. select.siblings( 'span.conditions-rule-has-children' ).find( 'input[type="checkbox"]' ).attr( 'checked', 'checked' );
  197. }
  198. } else {
  199. select.siblings( 'span.conditions-rule-has-children' ).hide().find( 'input[type="checkbox"]' ).removeAttr( 'checked' );
  200. }
  201. }
  202. function resetRuleIndexes( widget ) {
  203. var index = 0;
  204. widget.find( 'span.conditions-rule-has-children' )
  205. .find( 'input[type="checkbox"]' )
  206. .each( function() {
  207. $( this ).attr( 'name', 'conditions[page_children][' + index + ']' );
  208. index++;
  209. } );
  210. }
  211. function decodeEntities( encodedString ) {
  212. var textarea = document.createElement( 'textarea' );
  213. textarea.innerHTML = encodedString;
  214. return textarea.value;
  215. }
  216. } );