1 | |
---|
2 | /** |
---|
3 | * Private namespace for local methods. |
---|
4 | */ |
---|
5 | Drupal.contentRemoveButtons = Drupal.contentRemoveButtons || {}; |
---|
6 | |
---|
7 | /** |
---|
8 | * Manipulation of content remove buttons. |
---|
9 | * |
---|
10 | * TableDrag objects for multiple value fields (and multigroups) are scanned |
---|
11 | * to find 'remove' checkboxes. These checkboxes are hidden when javascript is |
---|
12 | * enabled (using the Global CSS Killswitch, html.js, defined in drupal.js). |
---|
13 | * A new 'remove' button is created here in place of these checkboxes aimed to |
---|
14 | * provide a more user-friendly method to remove items. |
---|
15 | */ |
---|
16 | Drupal.behaviors.contentRemoveButtons = function(context) { |
---|
17 | var self = Drupal.contentRemoveButtons; |
---|
18 | |
---|
19 | $('table.content-multiple-table', context).not('.content-remove-buttons-processed').addClass('content-remove-buttons-processed').each(function() { |
---|
20 | var table = this, tableDrag = Drupal.tableDrag[$(table).attr('id')]; |
---|
21 | |
---|
22 | // Replace remove checkboxes with buttons. |
---|
23 | $('input.content-multiple-remove-checkbox', table).each(function() { |
---|
24 | var $checkbox = $(this), $row = $checkbox.parents('tr:first'); |
---|
25 | var isRemoved = $checkbox.attr('checked'); |
---|
26 | var $button = $(Drupal.theme('contentRemoveButton', tableDrag.getRemoveButtonTitle(isRemoved))); |
---|
27 | |
---|
28 | // Bind the onClick event to the remove button. |
---|
29 | $button.bind('click', function(event) { |
---|
30 | self.onClick($button, $checkbox, $row, tableDrag); |
---|
31 | return false; |
---|
32 | }); |
---|
33 | |
---|
34 | // Attach the new button to the DOM tree. |
---|
35 | $checkbox.parent().append($button); |
---|
36 | |
---|
37 | // If the row is removed, then hide the contents of the cells and show |
---|
38 | // the removed warning on the cell next to the drag'n'drop cell. |
---|
39 | if (isRemoved) { |
---|
40 | self.getCellWrappers($row).hide(); |
---|
41 | self.showRemovedWarning($row, tableDrag); |
---|
42 | |
---|
43 | // FAPI not rendering the form on errors - case #1: |
---|
44 | // If the form has been submitted and any error was found, FAPI will |
---|
45 | // send back the same exact form that was submitted to show the error |
---|
46 | // messages, but it will not invoke the rendering engine which is where |
---|
47 | // we actually assign the removed class to the row, so we need to check |
---|
48 | // this situation here and add the class if it is not present. |
---|
49 | if (!$row.hasClass('content-multiple-removed-row')) { |
---|
50 | $row.addClass('content-multiple-removed-row'); |
---|
51 | } |
---|
52 | } |
---|
53 | else { |
---|
54 | // FAPI not rendering the form on errors - case #2: |
---|
55 | // Similar issue than #1, but this time caused when user removes an |
---|
56 | // item, previews, FAPI renders the new form with the removed class, |
---|
57 | // then user changes anything in the form that causes an error, and |
---|
58 | // also restores the previously removed item. This time, FAPI will |
---|
59 | // send the form validation error with the item not flagged for removal |
---|
60 | // but having the removed class that was present when the form was |
---|
61 | // rendered in the previous step. So we need to remove this class here, |
---|
62 | // if present, because the item is not really flagged for removal. |
---|
63 | if ($row.hasClass('content-multiple-removed-row')) { |
---|
64 | $row.removeClass('content-multiple-removed-row'); |
---|
65 | } |
---|
66 | } |
---|
67 | }); |
---|
68 | }); |
---|
69 | }; |
---|
70 | |
---|
71 | /** |
---|
72 | * onClick handler for remove buttons. |
---|
73 | * |
---|
74 | * @param $button |
---|
75 | * The jQuery object of the remove button. |
---|
76 | * @param $checkbox |
---|
77 | * The jQuery object of the remove checkbox. |
---|
78 | * @param $row |
---|
79 | * The jQuery object of the table row. |
---|
80 | * @param tableDrag |
---|
81 | * The tableDrag object where the row is. |
---|
82 | */ |
---|
83 | Drupal.contentRemoveButtons.onClick = function($button, $checkbox, $row, tableDrag) { |
---|
84 | var self = Drupal.contentRemoveButtons; |
---|
85 | |
---|
86 | // Prevent the user from firing this event while another one is still being |
---|
87 | // processed. This flag is (should be) restored at end of animations. |
---|
88 | // Note that this technique is required because the browser may experience |
---|
89 | // delays while performing the animation, for whatever reason, and if this |
---|
90 | // process it fired more than once at the same time for the same row, then |
---|
91 | // it may cause unexpected behavior because the state of the elements being |
---|
92 | // manipulated would be unknown. |
---|
93 | if ($row.animating) { |
---|
94 | return; |
---|
95 | } |
---|
96 | $row.animating = true; |
---|
97 | |
---|
98 | // Toggle the state of the checkbox. |
---|
99 | var isRemoved = !$checkbox.attr('checked'); |
---|
100 | $checkbox.attr('checked', isRemoved); |
---|
101 | |
---|
102 | // Toggle the row class. |
---|
103 | if (isRemoved) { |
---|
104 | $row.addClass('content-multiple-removed-row'); |
---|
105 | } |
---|
106 | else { |
---|
107 | $row.removeClass('content-multiple-removed-row'); |
---|
108 | } |
---|
109 | |
---|
110 | // Toggle the button title. |
---|
111 | $button.attr('title', tableDrag.getRemoveButtonTitle(isRemoved)); |
---|
112 | |
---|
113 | // Get the list of cell wrappers in this row. |
---|
114 | var $cellWrappers = self.getCellWrappers($row); |
---|
115 | |
---|
116 | // If for whatever reason this row doesn't have cells with elements, |
---|
117 | // then we are done, but we still need to reset the global busy flag |
---|
118 | // and display the tableDrag changed warning. |
---|
119 | if (!$cellWrappers.size()) { |
---|
120 | tableDrag.displayChangedWarning(); |
---|
121 | $row.animating = false; |
---|
122 | return; |
---|
123 | } |
---|
124 | |
---|
125 | // Toggle the visible state of the row cells. |
---|
126 | $cellWrappers.each(function() { |
---|
127 | var $cellWrapper = $(this); |
---|
128 | |
---|
129 | // Drop the removed warning during restore operation. |
---|
130 | if (!isRemoved) { |
---|
131 | self.hideRemovedWarning($row); |
---|
132 | } |
---|
133 | |
---|
134 | // Toggle the visibility state of the contents of cells. |
---|
135 | $cellWrapper.animate({opacity: (isRemoved ? 'hide' : 'show')}, 'fast', function() { |
---|
136 | var $cell = $cellWrapper.parent(); |
---|
137 | |
---|
138 | // Show the removed warning during remove operation. |
---|
139 | if (isRemoved && $cell.prev(':first').hasClass('content-multiple-drag')) { |
---|
140 | self.showRemovedWarning($row, tableDrag); |
---|
141 | } |
---|
142 | |
---|
143 | // Disable the busy flag when animation of last cell has finished. |
---|
144 | if ($cell.next(':first').hasClass('delta-order')) { |
---|
145 | tableDrag.displayChangedWarning(); |
---|
146 | $row.animating = false; |
---|
147 | } |
---|
148 | }); |
---|
149 | }); |
---|
150 | }; |
---|
151 | |
---|
152 | /** |
---|
153 | * Show the removed warning on the given row. |
---|
154 | * |
---|
155 | * @param $row |
---|
156 | * The jQuery object of the table row. |
---|
157 | * @param tableDrag |
---|
158 | * The tableDrag object where the row is. |
---|
159 | */ |
---|
160 | Drupal.contentRemoveButtons.showRemovedWarning = function($row, tableDrag) { |
---|
161 | $('.content-multiple-drag', $row).next(':first').append(Drupal.theme('contentRemovedWarning', tableDrag.getRemovedWarning())); |
---|
162 | }; |
---|
163 | |
---|
164 | /** |
---|
165 | * Hide the removed warning from the given row. |
---|
166 | * |
---|
167 | * @param $row |
---|
168 | * The jQuery object of the table row. |
---|
169 | */ |
---|
170 | Drupal.contentRemoveButtons.hideRemovedWarning = function($row) { |
---|
171 | if ($('.content-multiple-removed-warning', $row).size()) { |
---|
172 | $('.content-multiple-removed-warning', $row).remove(); |
---|
173 | } |
---|
174 | }; |
---|
175 | |
---|
176 | /** |
---|
177 | * Get cell wrappers for the given row. |
---|
178 | * |
---|
179 | * @param $row |
---|
180 | * The jQuery object of the table row. |
---|
181 | */ |
---|
182 | Drupal.contentRemoveButtons.getCellWrappers = function($row) { |
---|
183 | // Create cell wrappers if this row has not already been processed. |
---|
184 | if (!$('.content-multiple-cell-content-wrapper', $row).size()) { |
---|
185 | // Wrap the contents of all cells (except the drag'n'drop, weight and |
---|
186 | // remove button cells) with a dummy block element. This operation makes |
---|
187 | // animations faster because we just need to show/hide a single element |
---|
188 | // per cell, and it also prevents from creating more than one warning |
---|
189 | // element per row. |
---|
190 | $row.children('td:not(.content-multiple-drag):not(.delta-order):not(.content-multiple-remove-cell)').each(function() { |
---|
191 | var $cell = $(this); |
---|
192 | $cell.wrapInner('<div class="content-multiple-cell-content-wrapper"/>'); |
---|
193 | }); |
---|
194 | } |
---|
195 | return $('.content-multiple-cell-content-wrapper', $row); |
---|
196 | }; |
---|
197 | |
---|
198 | /** |
---|
199 | * Display table change warning when appropriate. |
---|
200 | */ |
---|
201 | Drupal.tableDrag.prototype.displayChangedWarning = function() { |
---|
202 | if (this.changed == false) { |
---|
203 | $(Drupal.theme('tableDragChangedWarning')).insertAfter(this.table).hide().fadeIn('slow'); |
---|
204 | this.changed = true; |
---|
205 | } |
---|
206 | }; |
---|
207 | |
---|
208 | /** |
---|
209 | * Get the title of the remove button. |
---|
210 | * |
---|
211 | * This method is an extension of the tableDrag class. This means a separate |
---|
212 | * module can override this method for a particular tableDrag instance. For |
---|
213 | * example, the multigroup module can change the text to read 'Remove this |
---|
214 | * group of items', another module could change it to 'Remove this image', |
---|
215 | * and so on... |
---|
216 | * To override this function: |
---|
217 | * |
---|
218 | * @code |
---|
219 | * var tableId = $(table).attr('id'); |
---|
220 | * Drupal.tableDrag[tableId].getRemoveButtonTitle = function(isRemoved) { |
---|
221 | * return (isRemoved ? Drupal.t('Restore this foo') : Drupal.t('Remove this foo')); |
---|
222 | * }; |
---|
223 | * @endcode |
---|
224 | * |
---|
225 | * @param isRemoved |
---|
226 | * A flag that indicates the state of the button. |
---|
227 | */ |
---|
228 | Drupal.tableDrag.prototype.getRemoveButtonTitle = function(isRemoved) { |
---|
229 | return (isRemoved ? Drupal.t('Restore this item') : Drupal.t('Remove this item')); |
---|
230 | }; |
---|
231 | |
---|
232 | /** |
---|
233 | * Get the item removed warning. |
---|
234 | * |
---|
235 | * This method is an extension of the tableDrag class. It can be overridden by |
---|
236 | * a separate module. See getRemoveButtonTitle() for further information. |
---|
237 | */ |
---|
238 | Drupal.tableDrag.prototype.getRemovedWarning = function() { |
---|
239 | return Drupal.t('Removed'); |
---|
240 | }; |
---|
241 | |
---|
242 | /** |
---|
243 | * Theme the remove button. |
---|
244 | */ |
---|
245 | Drupal.theme.prototype.contentRemoveButton = function(title) { |
---|
246 | return '<a href="javascript:void(0)" class="content-multiple-remove-button" title="'+ title +'"></a>'; |
---|
247 | }; |
---|
248 | |
---|
249 | /** |
---|
250 | * Theme the item removed warning. |
---|
251 | */ |
---|
252 | Drupal.theme.prototype.contentRemovedWarning = function(warning) { |
---|
253 | return '<div class="content-multiple-removed-warning">'+ warning +'</div>'; |
---|
254 | }; |
---|