1 /* global ajaxurl */ |
1 /** |
2 |
2 * Contains the postboxes logic, opening and closing postboxes, reordering and saving |
|
3 * the state and ordering to the database. |
|
4 * |
|
5 * @summary Contains postboxes logic |
|
6 * |
|
7 * @since 2.5.0 |
|
8 * @requires jQuery |
|
9 */ |
|
10 |
|
11 /* global ajaxurl, postBoxL10n */ |
|
12 |
|
13 /** |
|
14 * This object contains all function to handle the behaviour of the post boxes. The post boxes are the boxes you see |
|
15 * around the content on the edit page. |
|
16 * |
|
17 * @since 2.7.0 |
|
18 * |
|
19 * @namespace postboxes |
|
20 * |
|
21 * @type {Object} |
|
22 */ |
3 var postboxes; |
23 var postboxes; |
4 |
24 |
5 (function($) { |
25 (function($) { |
6 var $document = $( document ); |
26 var $document = $( document ); |
7 |
27 |
8 postboxes = { |
28 postboxes = { |
9 add_postbox_toggles : function(page, args) { |
29 |
10 var self = this; |
30 /** |
11 |
31 * @summary Handles a click on either the postbox heading or the postbox open/close icon. |
12 self.init(page, args); |
32 * |
13 |
33 * Opens or closes the postbox. Expects `this` to equal the clicked element. |
14 $('.postbox .hndle, .postbox .handlediv').bind('click.postboxes', function() { |
34 * Calls postboxes.pbshow if the postbox has been opened, calls postboxes.pbhide |
15 var p = $(this).parent('.postbox'), id = p.attr('id'); |
35 * if the postbox has been closed. |
16 |
36 * |
17 if ( 'dashboard_browser_nag' == id ) |
37 * @since 4.4.0 |
18 return; |
38 * @memberof postboxes |
19 |
39 * @fires postboxes#postbox-toggled |
20 p.toggleClass('closed'); |
40 * |
21 |
41 * @returns {void} |
22 if ( page != 'press-this' ) |
42 */ |
23 self.save_state(page); |
43 handle_click : function () { |
24 |
44 var $el = $( this ), |
25 if ( id ) { |
45 p = $el.parent( '.postbox' ), |
26 if ( !p.hasClass('closed') && $.isFunction(postboxes.pbshow) ) |
46 id = p.attr( 'id' ), |
27 self.pbshow(id); |
47 ariaExpandedValue; |
28 else if ( p.hasClass('closed') && $.isFunction(postboxes.pbhide) ) |
48 |
29 self.pbhide(id); |
49 if ( 'dashboard_browser_nag' === id ) { |
30 } |
50 return; |
31 |
51 } |
32 $document.trigger( 'postbox-toggled', p ); |
52 |
33 }); |
53 p.toggleClass( 'closed' ); |
34 |
54 |
|
55 ariaExpandedValue = ! p.hasClass( 'closed' ); |
|
56 |
|
57 if ( $el.hasClass( 'handlediv' ) ) { |
|
58 // The handle button was clicked. |
|
59 $el.attr( 'aria-expanded', ariaExpandedValue ); |
|
60 } else { |
|
61 // The handle heading was clicked. |
|
62 $el.closest( '.postbox' ).find( 'button.handlediv' ) |
|
63 .attr( 'aria-expanded', ariaExpandedValue ); |
|
64 } |
|
65 |
|
66 if ( postboxes.page !== 'press-this' ) { |
|
67 postboxes.save_state( postboxes.page ); |
|
68 } |
|
69 |
|
70 if ( id ) { |
|
71 if ( !p.hasClass('closed') && $.isFunction( postboxes.pbshow ) ) { |
|
72 postboxes.pbshow( id ); |
|
73 } else if ( p.hasClass('closed') && $.isFunction( postboxes.pbhide ) ) { |
|
74 postboxes.pbhide( id ); |
|
75 } |
|
76 } |
|
77 |
|
78 /** |
|
79 * @summary Fires when a postbox has been opened or closed. |
|
80 * |
|
81 * Contains a jQuery object with the relevant postbox element. |
|
82 * |
|
83 * @since 4.0.0 |
|
84 * @event postboxes#postbox-toggled |
|
85 * @type {Object} |
|
86 */ |
|
87 $document.trigger( 'postbox-toggled', p ); |
|
88 }, |
|
89 |
|
90 /** |
|
91 * Adds event handlers to all postboxes and screen option on the current page. |
|
92 * |
|
93 * @since 2.7.0 |
|
94 * @memberof postboxes |
|
95 * |
|
96 * @param {string} page The page we are currently on. |
|
97 * @param {Object} [args] |
|
98 * @param {Function} args.pbshow A callback that is called when a postbox opens. |
|
99 * @param {Function} args.pbhide A callback that is called when a postbox closes. |
|
100 * @returns {void} |
|
101 */ |
|
102 add_postbox_toggles : function (page, args) { |
|
103 var $handles = $( '.postbox .hndle, .postbox .handlediv' ); |
|
104 |
|
105 this.page = page; |
|
106 this.init( page, args ); |
|
107 |
|
108 $handles.on( 'click.postboxes', this.handle_click ); |
|
109 |
|
110 /** |
|
111 * @since 2.7.0 |
|
112 */ |
35 $('.postbox .hndle a').click( function(e) { |
113 $('.postbox .hndle a').click( function(e) { |
36 e.stopPropagation(); |
114 e.stopPropagation(); |
37 }); |
115 }); |
38 |
116 |
39 $( '.postbox a.dismiss' ).bind( 'click.postboxes', function() { |
117 /** |
|
118 * @summary Hides a postbox. |
|
119 * |
|
120 * Event handler for the postbox dismiss button. After clicking the button |
|
121 * the postbox will be hidden. |
|
122 * |
|
123 * @since 3.2.0 |
|
124 * |
|
125 * @returns {void} |
|
126 */ |
|
127 $( '.postbox a.dismiss' ).on( 'click.postboxes', function( e ) { |
40 var hide_id = $(this).parents('.postbox').attr('id') + '-hide'; |
128 var hide_id = $(this).parents('.postbox').attr('id') + '-hide'; |
|
129 e.preventDefault(); |
41 $( '#' + hide_id ).prop('checked', false).triggerHandler('click'); |
130 $( '#' + hide_id ).prop('checked', false).triggerHandler('click'); |
42 return false; |
131 }); |
43 }); |
132 |
44 |
133 /** |
|
134 * @summary Hides the postbox element |
|
135 * |
|
136 * Event handler for the screen options checkboxes. When a checkbox is |
|
137 * clicked this function will hide or show the relevant postboxes. |
|
138 * |
|
139 * @since 2.7.0 |
|
140 * @fires postboxes#postbox-toggled |
|
141 * |
|
142 * @returns {void} |
|
143 */ |
45 $('.hide-postbox-tog').bind('click.postboxes', function() { |
144 $('.hide-postbox-tog').bind('click.postboxes', function() { |
46 var boxId = $(this).val(), |
145 var $el = $(this), |
|
146 boxId = $el.val(), |
47 $postbox = $( '#' + boxId ); |
147 $postbox = $( '#' + boxId ); |
48 |
148 |
49 if ( $(this).prop('checked') ) { |
149 if ( $el.prop( 'checked' ) ) { |
50 $postbox.show(); |
150 $postbox.show(); |
51 if ( $.isFunction( postboxes.pbshow ) ) |
151 if ( $.isFunction( postboxes.pbshow ) ) { |
52 self.pbshow( boxId ); |
152 postboxes.pbshow( boxId ); |
|
153 } |
53 } else { |
154 } else { |
54 $postbox.hide(); |
155 $postbox.hide(); |
55 if ( $.isFunction( postboxes.pbhide ) ) |
156 if ( $.isFunction( postboxes.pbhide ) ) { |
56 self.pbhide( boxId ); |
157 postboxes.pbhide( boxId ); |
57 } |
158 } |
58 self.save_state(page); |
159 } |
59 self._mark_area(); |
160 |
|
161 postboxes.save_state( page ); |
|
162 postboxes._mark_area(); |
|
163 |
|
164 /** |
|
165 * @since 4.0.0 |
|
166 * @see postboxes.handle_click |
|
167 */ |
60 $document.trigger( 'postbox-toggled', $postbox ); |
168 $document.trigger( 'postbox-toggled', $postbox ); |
61 }); |
169 }); |
62 |
170 |
|
171 /** |
|
172 * @summary Changes the amount of columns based on the layout preferences. |
|
173 * |
|
174 * @since 2.8.0 |
|
175 * |
|
176 * @returns {void} |
|
177 */ |
63 $('.columns-prefs input[type="radio"]').bind('click.postboxes', function(){ |
178 $('.columns-prefs input[type="radio"]').bind('click.postboxes', function(){ |
64 var n = parseInt($(this).val(), 10); |
179 var n = parseInt($(this).val(), 10); |
65 |
180 |
66 if ( n ) { |
181 if ( n ) { |
67 self._pb_edit(n); |
182 postboxes._pb_edit(n); |
68 self.save_order(page); |
183 postboxes.save_order( page ); |
69 } |
184 } |
70 }); |
185 }); |
71 }, |
186 }, |
72 |
187 |
|
188 /** |
|
189 * @summary Initializes all the postboxes, mainly their sortable behaviour. |
|
190 * |
|
191 * @since 2.7.0 |
|
192 * @memberof postboxes |
|
193 * |
|
194 * @param {string} page The page we are currently on. |
|
195 * @param {Object} [args={}] The arguments for the postbox initializer. |
|
196 * @param {Function} args.pbshow A callback that is called when a postbox opens. |
|
197 * @param {Function} args.pbhide A callback that is called when a postbox |
|
198 * closes. |
|
199 * |
|
200 * @returns {void} |
|
201 */ |
73 init : function(page, args) { |
202 init : function(page, args) { |
74 var isMobile = $(document.body).hasClass('mobile'); |
203 var isMobile = $( document.body ).hasClass( 'mobile' ), |
|
204 $handleButtons = $( '.postbox .handlediv' ); |
75 |
205 |
76 $.extend( this, args || {} ); |
206 $.extend( this, args || {} ); |
77 $('#wpbody-content').css('overflow','hidden'); |
207 $('#wpbody-content').css('overflow','hidden'); |
78 $('.meta-box-sortables').sortable({ |
208 $('.meta-box-sortables').sortable({ |
79 placeholder: 'sortable-placeholder', |
209 placeholder: 'sortable-placeholder', |
83 cursor: 'move', |
213 cursor: 'move', |
84 delay: ( isMobile ? 200 : 0 ), |
214 delay: ( isMobile ? 200 : 0 ), |
85 distance: 2, |
215 distance: 2, |
86 tolerance: 'pointer', |
216 tolerance: 'pointer', |
87 forcePlaceholderSize: true, |
217 forcePlaceholderSize: true, |
88 helper: 'clone', |
218 helper: function( event, element ) { |
|
219 /* `helper: 'clone'` is equivalent to `return element.clone();` |
|
220 * Cloning a checked radio and then inserting that clone next to the original |
|
221 * radio unchecks the original radio (since only one of the two can be checked). |
|
222 * We get around this by renaming the helper's inputs' name attributes so that, |
|
223 * when the helper is inserted into the DOM for the sortable, no radios are |
|
224 * duplicated, and no original radio gets unchecked. |
|
225 */ |
|
226 return element.clone() |
|
227 .find( ':input' ) |
|
228 .attr( 'name', function( i, currentName ) { |
|
229 return 'sort_' + parseInt( Math.random() * 100000, 10 ).toString() + '_' + currentName; |
|
230 } ) |
|
231 .end(); |
|
232 }, |
89 opacity: 0.65, |
233 opacity: 0.65, |
90 stop: function() { |
234 stop: function() { |
91 if ( $(this).find('#dashboard_browser_nag').is(':visible') && 'dashboard_browser_nag' != this.firstChild.id ) { |
235 var $el = $( this ); |
92 $(this).sortable('cancel'); |
236 |
|
237 if ( $el.find( '#dashboard_browser_nag' ).is( ':visible' ) && 'dashboard_browser_nag' != this.firstChild.id ) { |
|
238 $el.sortable('cancel'); |
93 return; |
239 return; |
94 } |
240 } |
95 |
241 |
96 postboxes.save_order(page); |
242 postboxes.save_order(page); |
97 }, |
243 }, |
98 receive: function(e,ui) { |
244 receive: function(e,ui) { |
99 if ( 'dashboard_browser_nag' == ui.item[0].id ) |
245 if ( 'dashboard_browser_nag' == ui.item[0].id ) |
100 $(ui.sender).sortable('cancel'); |
246 $(ui.sender).sortable('cancel'); |
101 |
247 |
102 postboxes._mark_area(); |
248 postboxes._mark_area(); |
|
249 $document.trigger( 'postbox-moved', ui.item ); |
103 } |
250 } |
104 }); |
251 }); |
105 |
252 |
106 if ( isMobile ) { |
253 if ( isMobile ) { |
107 $(document.body).bind('orientationchange.postboxes', function(){ postboxes._pb_change(); }); |
254 $(document.body).bind('orientationchange.postboxes', function(){ postboxes._pb_change(); }); |
108 this._pb_change(); |
255 this._pb_change(); |
109 } |
256 } |
110 |
257 |
111 this._mark_area(); |
258 this._mark_area(); |
112 }, |
259 |
113 |
260 // Set the handle buttons `aria-expanded` attribute initial value on page load. |
|
261 $handleButtons.each( function () { |
|
262 var $el = $( this ); |
|
263 $el.attr( 'aria-expanded', ! $el.parent( '.postbox' ).hasClass( 'closed' ) ); |
|
264 }); |
|
265 }, |
|
266 |
|
267 /** |
|
268 * @summary Saves the state of the postboxes to the server. |
|
269 * |
|
270 * Saves the state of the postboxes to the server. It sends two lists, one with |
|
271 * all the closed postboxes, one with all the hidden postboxes. |
|
272 * |
|
273 * @since 2.7.0 |
|
274 * @memberof postboxes |
|
275 * |
|
276 * @param {string} page The page we are currently on. |
|
277 * @returns {void} |
|
278 */ |
114 save_state : function(page) { |
279 save_state : function(page) { |
115 var closed = $('.postbox').filter('.closed').map(function() { return this.id; }).get().join(','), |
280 var closed, hidden; |
116 hidden = $('.postbox').filter(':hidden').map(function() { return this.id; }).get().join(','); |
281 |
|
282 // Return on the nav-menus.php screen, see #35112. |
|
283 if ( 'nav-menus' === page ) { |
|
284 return; |
|
285 } |
|
286 |
|
287 closed = $( '.postbox' ).filter( '.closed' ).map( function() { return this.id; } ).get().join( ',' ); |
|
288 hidden = $( '.postbox' ).filter( ':hidden' ).map( function() { return this.id; } ).get().join( ',' ); |
117 |
289 |
118 $.post(ajaxurl, { |
290 $.post(ajaxurl, { |
119 action: 'closed-postboxes', |
291 action: 'closed-postboxes', |
120 closed: closed, |
292 closed: closed, |
121 hidden: hidden, |
293 hidden: hidden, |
122 closedpostboxesnonce: jQuery('#closedpostboxesnonce').val(), |
294 closedpostboxesnonce: jQuery('#closedpostboxesnonce').val(), |
123 page: page |
295 page: page |
124 }); |
296 }); |
125 }, |
297 }, |
126 |
298 |
|
299 /** |
|
300 * @summary Saves the order of the postboxes to the server. |
|
301 * |
|
302 * Saves the order of the postboxes to the server. Sends a list of all postboxes |
|
303 * inside a sortable area to the server. |
|
304 * |
|
305 * @since 2.8.0 |
|
306 * @memberof postboxes |
|
307 * |
|
308 * @param {string} page The page we are currently on. |
|
309 * @returns {void} |
|
310 */ |
127 save_order : function(page) { |
311 save_order : function(page) { |
128 var postVars, page_columns = $('.columns-prefs input:checked').val() || 0; |
312 var postVars, page_columns = $('.columns-prefs input:checked').val() || 0; |
129 |
313 |
130 postVars = { |
314 postVars = { |
131 action: 'meta-box-order', |
315 action: 'meta-box-order', |
132 _ajax_nonce: $('#meta-box-order-nonce').val(), |
316 _ajax_nonce: $('#meta-box-order-nonce').val(), |
133 page_columns: page_columns, |
317 page_columns: page_columns, |
134 page: page |
318 page: page |
135 }; |
319 }; |
|
320 |
136 $('.meta-box-sortables').each( function() { |
321 $('.meta-box-sortables').each( function() { |
137 postVars[ 'order[' + this.id.split( '-' )[0] + ']' ] = $( this ).sortable( 'toArray' ).join( ',' ); |
322 postVars[ 'order[' + this.id.split( '-' )[0] + ']' ] = $( this ).sortable( 'toArray' ).join( ',' ); |
138 } ); |
323 } ); |
|
324 |
139 $.post( ajaxurl, postVars ); |
325 $.post( ajaxurl, postVars ); |
140 }, |
326 }, |
141 |
327 |
|
328 /** |
|
329 * @summary Marks empty postbox areas. |
|
330 * |
|
331 * Adds a message to empty sortable areas on the dashboard page. Also adds a |
|
332 * border around the side area on the post edit screen if there are no postboxes |
|
333 * present. |
|
334 * |
|
335 * @since 3.3.0 |
|
336 * @memberof postboxes |
|
337 * @access private |
|
338 * |
|
339 * @returns {void} |
|
340 */ |
142 _mark_area : function() { |
341 _mark_area : function() { |
143 var visible = $('div.postbox:visible').length, side = $('#post-body #side-sortables'); |
342 var visible = $('div.postbox:visible').length, side = $('#post-body #side-sortables'); |
144 |
343 |
145 $( '#dashboard-widgets .meta-box-sortables:visible' ).each( function() { |
344 $( '#dashboard-widgets .meta-box-sortables:visible' ).each( function() { |
146 var t = $(this); |
345 var t = $(this); |
147 |
346 |
148 if ( visible == 1 || t.children('.postbox:visible').length ) |
347 if ( visible == 1 || t.children('.postbox:visible').length ) { |
149 t.removeClass('empty-container'); |
348 t.removeClass('empty-container'); |
150 else |
349 } |
|
350 else { |
151 t.addClass('empty-container'); |
351 t.addClass('empty-container'); |
|
352 t.attr('data-emptyString', postBoxL10n.postBoxEmptyString); |
|
353 } |
152 }); |
354 }); |
153 |
355 |
154 if ( side.length ) { |
356 if ( side.length ) { |
155 if ( side.children('.postbox:visible').length ) |
357 if ( side.children('.postbox:visible').length ) |
156 side.removeClass('empty-container'); |
358 side.removeClass('empty-container'); |
157 else if ( $('#postbox-container-1').css('width') == '280px' ) |
359 else if ( $('#postbox-container-1').css('width') == '280px' ) |
158 side.addClass('empty-container'); |
360 side.addClass('empty-container'); |
159 } |
361 } |
160 }, |
362 }, |
161 |
363 |
|
364 /** |
|
365 * @summary Changes the amount of columns on the post edit page. |
|
366 * |
|
367 * @since 3.3.0 |
|
368 * @memberof postboxes |
|
369 * @fires postboxes#postboxes-columnchange |
|
370 * @access private |
|
371 * |
|
372 * @param {number} n The amount of columns to divide the post edit page in. |
|
373 * @returns {void} |
|
374 */ |
162 _pb_edit : function(n) { |
375 _pb_edit : function(n) { |
163 var el = $('.metabox-holder').get(0); |
376 var el = $('.metabox-holder').get(0); |
164 |
377 |
165 if ( el ) { |
378 if ( el ) { |
166 el.className = el.className.replace(/columns-\d+/, 'columns-' + n); |
379 el.className = el.className.replace(/columns-\d+/, 'columns-' + n); |
167 } |
380 } |
168 |
381 |
|
382 /** |
|
383 * Fires when the amount of columns on the post edit page has been changed. |
|
384 * |
|
385 * @since 4.0.0 |
|
386 * @event postboxes#postboxes-columnchange |
|
387 */ |
169 $( document ).trigger( 'postboxes-columnchange' ); |
388 $( document ).trigger( 'postboxes-columnchange' ); |
170 }, |
389 }, |
171 |
390 |
|
391 /** |
|
392 * @summary Changes the amount of columns the postboxes are in based on the |
|
393 * current orientation of the browser. |
|
394 * |
|
395 * @since 3.3.0 |
|
396 * @memberof postboxes |
|
397 * @access private |
|
398 * |
|
399 * @returns {void} |
|
400 */ |
172 _pb_change : function() { |
401 _pb_change : function() { |
173 var check = $( 'label.columns-prefs-1 input[type="radio"]' ); |
402 var check = $( 'label.columns-prefs-1 input[type="radio"]' ); |
174 |
403 |
175 switch ( window.orientation ) { |
404 switch ( window.orientation ) { |
176 case 90: |
405 case 90: |