PluginProbe ʕ •ᴥ•ʔ
Custom Sidebars – Dynamic Sidebar Classic Widget Area Manager / 3.38
Custom Sidebars – Dynamic Sidebar Classic Widget Area Manager v3.38
trunk 2.1.2.0 3.0.0.0 3.0.0.1 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.7.1 3.0.8 3.0.8.1 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.3 3.31 3.32 3.35 3.36 3.37 3.38
custom-sidebars / assets / js / cs-cloning.js
custom-sidebars / assets / js Last commit date
cs-cloning.js 5 years ago cs-cloning.min.js 5 years ago cs-visibility.js 5 years ago cs-visibility.min.js 5 years ago cs.js 5 years ago cs.min.js 5 years ago retirement-admin-notice.js 5 years ago
cs-cloning.js
310 lines
1 /*! Custom Sidebars - v3.2.3
2 * Copyright (c) 2020; * Licensed GPLv2+ */
3 /*global jQuery:false */
4 /*global window:false */
5 /*global document:false */
6 /*global wp:false */
7 /*global wpmUi:false */
8
9 jQuery(function init_cloning() {
10 var $doc = jQuery( document ),
11 $all = jQuery( '#widgets-right' ),
12 is_cloning = false;
13
14 /**
15 * Updates all group_id values for the widget-templates to the next free id.
16 */
17 var update_template_groups = function update_template_groups() {
18 var $groups = jQuery( '#widgets-left input.csb-clone-group' ),
19 next_id = parseInt( $groups.first().val() );
20 while ( $all.find( 'input.csb-clone-group[value="' + next_id + '"]' ).length ) {
21 next_id += 1;
22 }
23 $groups.val( next_id );
24 };
25
26 /**
27 * Clones the widget:
28 * Add a new widget using default WordPress JS API and then update all the
29 * input values of the new widget to match the original widget.
30 */
31 var clone_widget = function clone_widget( ev ) {
32 var $widget = jQuery( this ).closest( '.widget' ),
33 $available = jQuery( '#widgets-left' ),
34 $chooser = jQuery( '.widgets-chooser' ),
35 $content = jQuery( '#wpbody-content' );
36
37 ev.preventDefault();
38 is_cloning = true;
39
40 // 1. If the current widget is new then first save the current widget
41 var state = $widget.find( 'input.csb-clone-state' ).val();
42 if ( 'new' === state ) {
43 window.wpWidgets.save( $widget, 0, 0, 0 );
44 }
45
46 // 2. Close any open chooser
47 window.wpWidgets.clearWidgetSelection();
48 $chooser.slideUp( 200, function() {
49 $chooser.hide();
50 $content.append( this );
51 });
52
53 // 3. Find the "widget-in-question".
54 var class_name = $widget.find('input.id_base').val(),
55 $base = $available.find('input.id_base[value="' + class_name + '"]'),
56 $in_question = $base.closest( '.widget' );
57 $in_question.addClass( 'widget-in-question' );
58
59 // 4. Provide data about the origin widget.
60 var group_id = $widget.find( 'input.csb-clone-group' ).val(),
61 $contr = $in_question.find( '.widget-control-actions' ),
62 $group = $in_question.find( 'input.csb-clone-group' ),
63 $state = $in_question.find( 'input.csb-clone-state' );
64 $group.val( group_id );
65 $state.val( 'empty' );
66
67 // 5. Select the current sidebar in the chooser.
68 var $sidebar = $widget.closest( '.widgets-sortables' ),
69 sb_id = $sidebar.attr( 'id' );
70 $chooser.find ( '.widgets-chooser-selected' ).removeClass( 'widgets-chooser-selected' );
71 $chooser.find( 'li' ).each( function() {
72 var $li = jQuery( this );
73 if ( sb_id === $li.data('sidebarId') ) {
74 $li.addClass( 'widgets-chooser-selected' ).focus();
75 }
76 });
77
78 // 6. Add the new widget to the sidebar.
79 // This will directly trigger the ajax command to save the widget.
80 window.wpWidgets.addWidget( $chooser );
81
82 // 7. Remove the custom elements and information again.
83 window.wpWidgets.clearWidgetSelection();
84 update_template_groups();
85
86 is_cloning = false;
87
88 return false;
89 };
90
91 /**
92 * Update all widgets belonging to the same group.
93 */
94 var prepare_update_group = function prepare_update_group( ev ) {
95 var $widget = jQuery( this ).closest( '.widget' ),
96 group_id = $widget.find( 'input.csb-clone-group' ).val(),
97 $members = $all.find( 'input.csb-clone-group[value="' + group_id + '"]' ).closest( '.widget' ).not( $widget );
98 $members.each(function() {
99 var $item = jQuery( this ),
100 $state = $item.find( 'input.csb-clone-state' );
101 $item.addClass('wpmui-loading').attr( 'data-reload', true );
102 });
103 };
104
105 /**
106 * Moves the "Clone" button next to the save button.
107 */
108 var init_widget = function init_widget( ev, el ) {
109 var $widget = jQuery( el ).closest( '.widget' ),
110 $btn = $widget.find( '.csb-clone-button' ),
111 $target = $widget.find( '.widget-control-actions .widget-control-save' ),
112 $spinner = $widget.find( '.widget-control-actions .spinner' ),
113 $btn_save = $widget.find( '.widget-control-save' );
114
115 if ( $widget.data( '_csb_cloning' ) ) {
116 return;
117 }
118
119 $spinner.insertBefore( $target ).css({ 'float': 'left' });
120 $btn.insertBefore( $target ).click( clone_widget );
121 $btn_save.click( prepare_update_group );
122
123 $widget.data( '_csb_cloning', true );
124 };
125
126 /**
127 * Updates the group-counter when a widget is added.
128 */
129 var update_group_counter = function update_group_counter( ev, el ) {
130 // We do NOT want to change the group-id when we clone a widget...
131 if ( is_cloning ) {
132 return false;
133 }
134 var $widget = jQuery( el ).closest( '.widget' ),
135 $widget_group = $widget.find( 'input.csb-clone-group' ),
136 group_id = parseInt( $widget_group.val() ),
137 check = null;
138 do {
139 check = $all.find( 'input.csb-clone-group[value="' + group_id + '"]' );
140 if ( ! check.length || ( 1 === check.length && check[0] === $widget_group[0] ) ) {
141 break;
142 } else {
143 group_id += 1;
144 }
145 }
146 while ( true );
147
148 $widget_group.val( group_id );
149 update_template_groups();
150 };
151
152
153 /**
154 * Viually highlights all widgets of the same group.
155 */
156 var mark_group = function mark_group( ev ) {
157 var $widget = jQuery( this ).closest( '.widget' ),
158 group_id = $widget.find( 'input.csb-clone-group' ).val(),
159 $members = $all.find( 'input.csb-clone-group[value="' + group_id + '"]' ).closest( '.widget' );
160
161 if ( isNaN( group_id ) || group_id < 1 ) {
162 return;
163 }
164
165 $members.addClass('csb-marker');
166 $widget.removeClass('csb-marker');
167 };
168
169 /**
170 * Removes the visual highlighting of group widgets.
171 */
172 var unmark_group = function unmark_group( ev ) {
173 var $marked = jQuery( '.widget.csb-marker' );
174 $marked.removeClass('csb-marker');
175 };
176
177 /**
178 * Remove widget from group/assign to group again (only works until widget
179 * was saved.)
180 */
181 var toggle_group = function toggle_group( ev ) {
182 var $widget = jQuery( this ).closest( '.widget' ),
183 $title = $widget.find( '.widget-title h4' ),
184 $icon = $title.find( '.btn-clone-group' ),
185 $group = $widget.find( 'input.csb-clone-group' );
186 ev.preventDefault();
187 ev.stopPropagation();
188 if ( $title.hasClass( 'group-active' ) ) {
189 $title.removeClass( 'group-active' );
190 $icon.removeClass('dashicons-admin-links').addClass('dashicons-editor-unlink');
191 $group.data( 'group', $group.val() );
192 $group.val( 0 );
193 unmark_group();
194 } else {
195 $title.addClass( 'group-active' );
196 $icon.addClass('dashicons-admin-links').removeClass('dashicons-editor-unlink');
197 $group.val( $group.data( 'group' ) );
198 mark_group.call( this, [ev] );
199 }
200 return false;
201 };
202
203 /**
204 * Adds icons to all widgets that are inside a group.
205 */
206 var init_group_icons = function init_group_icons() {
207 var $groups = $all.find( 'input.csb-clone-group' );
208 $groups.each(function() {
209 var group_id = jQuery( this ).val(),
210 $members = $all.find( 'input.csb-clone-group[value="' + group_id + '"]' ).closest( '.widget' ),
211 $titles = $members.find( '.widget-title h4, .widget-title h3' ),
212 action = 'add';
213 if ( isNaN( group_id ) || group_id < 1 ) {
214 action = 'remove';
215 }
216 if ( $members.length < 2 ) {
217 action = 'remove';
218 }
219 // Always remove the icons from the group.
220 $titles.removeClass( 'csb-group group-active' )
221 .find( '.btn-clone-group' ).remove();
222 $members.removeAttr( 'data-csb-icon' );
223 // If action is "add" then we add the icons again.
224 if ( action === 'add' ) {
225 $titles.addClass( 'csb-group group-active' )
226 .prepend( '<i class="dashicons dashicons-admin-links btn-clone-group"></i> ' );
227 $titles.find( '.btn-clone-group' )
228 .hover( mark_group, unmark_group )
229 .click( toggle_group );
230 }
231 });
232 };
233
234 /**
235 * Saves the specified widget if the clone-state is "empty".
236 */
237 var populate_widget = function populate_widget( $widget ) {
238 var $state = $widget.find( 'input.csb-clone-state' );
239
240 if ( $state.val() === 'empty' ) {
241 $widget.addClass( 'wpmui-loading' );
242 window.wpWidgets.save( $widget, 0, 1, 0 );
243 }
244 };
245
246 /**
247 * Update all widgets belonging to the same group.
248 */
249 var update_group_widgets = function update_group_widgets( el ) {
250 var $widgets = $all.find( '.widget[data-reload]' );
251
252 $widgets.each(function() {
253 var $item = jQuery( this ),
254 $state = $item.find( 'input.csb-clone-state' );
255
256 $state.val( 'empty' );
257 $item.removeAttr( 'data-reload' );
258 window.wpWidgets.save( $item, 0, 0, 0 );
259 });
260 };
261
262 /**
263 * Global ajax observer reacts to all ajax responses. We need this to find
264 * out when a new widget is saved for the first time.
265 */
266 var ajax_observer = function ajax_observer( ev, xhr, opt, resp ) {
267 var data = ( 'string' === typeof opt.data ? opt.data : '' ),
268 find_action = data.match( /^.*&action=([^&]+).*$/ ),
269 find_widget = data.match( /^.*&widget-id=([^&]+).*$/ ),
270 action = (find_action && find_action.length === 2 ? find_action[1] : ''),
271 widget = (find_widget && find_widget.length === 2 ? find_widget[1] : '');
272
273 if ( ! widget.length ) {
274 return;
275 }
276
277 var $base = jQuery( '.widget input.widget-id[value="' + widget + '"]' ),
278 $widget = $base.closest( '.widget' );
279
280 switch ( action ) {
281 case 'save-widget':
282 $widget.removeClass( 'wpmui-loading' );
283 if ( ! resp.length ) {
284 // Populate widget with data from group, if required.
285 populate_widget( $widget );
286 } else if ( resp.match( /^deleted:/ ) ) {
287 // Widget was deleted and is removed with animation.
288 window.setTimeout( init_group_icons, 400 );
289 } else {
290 // Existing widget was updated.
291 init_group_icons();
292 update_group_widgets( $widget );
293 }
294 break;
295
296 default:
297 // Unrelated ajax event.
298 }
299 };
300
301
302 $all.find( '.widget' ).each( init_widget );
303 $doc.on( 'widget-added', init_widget );
304 $doc.on( 'widget-added', update_group_counter );
305 $doc.ajaxSuccess( ajax_observer );
306
307 init_group_icons();
308 update_template_groups();
309 });
310