Chris@0
|
1 /**
|
Chris@0
|
2 * @file
|
Chris@0
|
3 * A Backbone View that provides the visual UX view of CKEditor toolbar
|
Chris@0
|
4 * configuration.
|
Chris@0
|
5 */
|
Chris@0
|
6
|
Chris@17
|
7 (function(Drupal, Backbone, $) {
|
Chris@17
|
8 Drupal.ckeditor.VisualView = Backbone.View.extend(
|
Chris@17
|
9 /** @lends Drupal.ckeditor.VisualView# */ {
|
Chris@17
|
10 events: {
|
Chris@17
|
11 'click .ckeditor-toolbar-group-name': 'onGroupNameClick',
|
Chris@17
|
12 'click .ckeditor-groupnames-toggle': 'onGroupNamesToggleClick',
|
Chris@17
|
13 'click .ckeditor-add-new-group button': 'onAddGroupButtonClick',
|
Chris@17
|
14 },
|
Chris@0
|
15
|
Chris@17
|
16 /**
|
Chris@17
|
17 * Backbone View for CKEditor toolbar configuration; visual UX.
|
Chris@17
|
18 *
|
Chris@17
|
19 * @constructs
|
Chris@17
|
20 *
|
Chris@17
|
21 * @augments Backbone.View
|
Chris@17
|
22 */
|
Chris@17
|
23 initialize() {
|
Chris@17
|
24 this.listenTo(
|
Chris@17
|
25 this.model,
|
Chris@17
|
26 'change:isDirty change:groupNamesVisible',
|
Chris@17
|
27 this.render,
|
Chris@17
|
28 );
|
Chris@17
|
29
|
Chris@17
|
30 // Add a toggle for the button group names.
|
Chris@17
|
31 $(Drupal.theme('ckeditorButtonGroupNamesToggle')).prependTo(
|
Chris@17
|
32 this.$el.find('#ckeditor-active-toolbar').parent(),
|
Chris@17
|
33 );
|
Chris@17
|
34
|
Chris@17
|
35 this.render();
|
Chris@17
|
36 },
|
Chris@17
|
37
|
Chris@17
|
38 /**
|
Chris@17
|
39 * Render function for rendering the toolbar configuration.
|
Chris@17
|
40 *
|
Chris@17
|
41 * @param {*} model
|
Chris@17
|
42 * Model used for the view.
|
Chris@17
|
43 * @param {string} [value]
|
Chris@17
|
44 * The value that was changed.
|
Chris@17
|
45 * @param {object} changedAttributes
|
Chris@17
|
46 * The attributes that was changed.
|
Chris@17
|
47 *
|
Chris@17
|
48 * @return {Drupal.ckeditor.VisualView}
|
Chris@17
|
49 * The {@link Drupal.ckeditor.VisualView} object.
|
Chris@17
|
50 */
|
Chris@17
|
51 render(model, value, changedAttributes) {
|
Chris@17
|
52 this.insertPlaceholders();
|
Chris@17
|
53 this.applySorting();
|
Chris@17
|
54
|
Chris@17
|
55 // Toggle button group names.
|
Chris@17
|
56 let groupNamesVisible = this.model.get('groupNamesVisible');
|
Chris@17
|
57 // If a button was just placed in the active toolbar, ensure that the
|
Chris@17
|
58 // button group names are visible.
|
Chris@17
|
59 if (
|
Chris@17
|
60 changedAttributes &&
|
Chris@17
|
61 changedAttributes.changes &&
|
Chris@17
|
62 changedAttributes.changes.isDirty
|
Chris@17
|
63 ) {
|
Chris@17
|
64 this.model.set({ groupNamesVisible: true }, { silent: true });
|
Chris@17
|
65 groupNamesVisible = true;
|
Chris@17
|
66 }
|
Chris@17
|
67 this.$el
|
Chris@17
|
68 .find('[data-toolbar="active"]')
|
Chris@17
|
69 .toggleClass('ckeditor-group-names-are-visible', groupNamesVisible);
|
Chris@17
|
70 this.$el
|
Chris@17
|
71 .find('.ckeditor-groupnames-toggle')
|
Chris@17
|
72 .text(
|
Chris@17
|
73 groupNamesVisible
|
Chris@17
|
74 ? Drupal.t('Hide group names')
|
Chris@17
|
75 : Drupal.t('Show group names'),
|
Chris@17
|
76 )
|
Chris@17
|
77 .attr('aria-pressed', groupNamesVisible);
|
Chris@17
|
78
|
Chris@17
|
79 return this;
|
Chris@17
|
80 },
|
Chris@17
|
81
|
Chris@17
|
82 /**
|
Chris@17
|
83 * Handles clicks to a button group name.
|
Chris@17
|
84 *
|
Chris@17
|
85 * @param {jQuery.Event} event
|
Chris@17
|
86 * The click event on the button group.
|
Chris@17
|
87 */
|
Chris@17
|
88 onGroupNameClick(event) {
|
Chris@17
|
89 const $group = $(event.currentTarget).closest(
|
Chris@17
|
90 '.ckeditor-toolbar-group',
|
Chris@17
|
91 );
|
Chris@17
|
92 Drupal.ckeditor.openGroupNameDialog(this, $group);
|
Chris@17
|
93
|
Chris@17
|
94 event.stopPropagation();
|
Chris@17
|
95 event.preventDefault();
|
Chris@17
|
96 },
|
Chris@17
|
97
|
Chris@17
|
98 /**
|
Chris@17
|
99 * Handles clicks on the button group names toggle button.
|
Chris@17
|
100 *
|
Chris@17
|
101 * @param {jQuery.Event} event
|
Chris@17
|
102 * The click event on the toggle button.
|
Chris@17
|
103 */
|
Chris@17
|
104 onGroupNamesToggleClick(event) {
|
Chris@17
|
105 this.model.set(
|
Chris@17
|
106 'groupNamesVisible',
|
Chris@17
|
107 !this.model.get('groupNamesVisible'),
|
Chris@17
|
108 );
|
Chris@17
|
109 event.preventDefault();
|
Chris@17
|
110 },
|
Chris@17
|
111
|
Chris@17
|
112 /**
|
Chris@17
|
113 * Prompts the user to provide a name for a new button group; inserts it.
|
Chris@17
|
114 *
|
Chris@17
|
115 * @param {jQuery.Event} event
|
Chris@17
|
116 * The event of the button click.
|
Chris@17
|
117 */
|
Chris@17
|
118 onAddGroupButtonClick(event) {
|
Chris@17
|
119 /**
|
Chris@17
|
120 * Inserts a new button if the openGroupNameDialog function returns true.
|
Chris@17
|
121 *
|
Chris@17
|
122 * @param {bool} success
|
Chris@17
|
123 * A flag that indicates if the user created a new group (true) or
|
Chris@17
|
124 * canceled out of the dialog (false).
|
Chris@17
|
125 * @param {jQuery} $group
|
Chris@17
|
126 * A jQuery DOM fragment that represents the new button group. It has
|
Chris@17
|
127 * not been added to the DOM yet.
|
Chris@17
|
128 */
|
Chris@17
|
129 function insertNewGroup(success, $group) {
|
Chris@17
|
130 if (success) {
|
Chris@17
|
131 $group.appendTo(
|
Chris@17
|
132 $(event.currentTarget)
|
Chris@17
|
133 .closest('.ckeditor-row')
|
Chris@17
|
134 .children('.ckeditor-toolbar-groups'),
|
Chris@17
|
135 );
|
Chris@17
|
136 // Focus on the new group.
|
Chris@17
|
137 $group.trigger('focus');
|
Chris@17
|
138 }
|
Chris@17
|
139 }
|
Chris@17
|
140
|
Chris@17
|
141 // Pass in a DOM fragment of a placeholder group so that the new group
|
Chris@17
|
142 // name can be applied to it.
|
Chris@17
|
143 Drupal.ckeditor.openGroupNameDialog(
|
Chris@17
|
144 this,
|
Chris@17
|
145 $(Drupal.theme('ckeditorToolbarGroup')),
|
Chris@17
|
146 insertNewGroup,
|
Chris@17
|
147 );
|
Chris@17
|
148
|
Chris@17
|
149 event.preventDefault();
|
Chris@17
|
150 },
|
Chris@17
|
151
|
Chris@17
|
152 /**
|
Chris@17
|
153 * Handles jQuery Sortable stop sort of a button group.
|
Chris@17
|
154 *
|
Chris@17
|
155 * @param {jQuery.Event} event
|
Chris@17
|
156 * The event triggered on the group drag.
|
Chris@17
|
157 * @param {object} ui
|
Chris@17
|
158 * A jQuery.ui.sortable argument that contains information about the
|
Chris@17
|
159 * elements involved in the sort action.
|
Chris@17
|
160 */
|
Chris@17
|
161 endGroupDrag(event, ui) {
|
Chris@17
|
162 const view = this;
|
Chris@17
|
163 Drupal.ckeditor.registerGroupMove(this, ui.item, success => {
|
Chris@17
|
164 if (!success) {
|
Chris@17
|
165 // Cancel any sorting in the configuration area.
|
Chris@17
|
166 view.$el
|
Chris@17
|
167 .find('.ckeditor-toolbar-configuration')
|
Chris@17
|
168 .find('.ui-sortable')
|
Chris@17
|
169 .sortable('cancel');
|
Chris@17
|
170 }
|
Chris@17
|
171 });
|
Chris@17
|
172 },
|
Chris@17
|
173
|
Chris@17
|
174 /**
|
Chris@17
|
175 * Handles jQuery Sortable start sort of a button.
|
Chris@17
|
176 *
|
Chris@17
|
177 * @param {jQuery.Event} event
|
Chris@17
|
178 * The event triggered on the group drag.
|
Chris@17
|
179 * @param {object} ui
|
Chris@17
|
180 * A jQuery.ui.sortable argument that contains information about the
|
Chris@17
|
181 * elements involved in the sort action.
|
Chris@17
|
182 */
|
Chris@17
|
183 startButtonDrag(event, ui) {
|
Chris@17
|
184 this.$el.find('a:focus').trigger('blur');
|
Chris@17
|
185
|
Chris@17
|
186 // Show the button group names as soon as the user starts dragging.
|
Chris@17
|
187 this.model.set('groupNamesVisible', true);
|
Chris@17
|
188 },
|
Chris@17
|
189
|
Chris@17
|
190 /**
|
Chris@17
|
191 * Handles jQuery Sortable stop sort of a button.
|
Chris@17
|
192 *
|
Chris@17
|
193 * @param {jQuery.Event} event
|
Chris@17
|
194 * The event triggered on the button drag.
|
Chris@17
|
195 * @param {object} ui
|
Chris@17
|
196 * A jQuery.ui.sortable argument that contains information about the
|
Chris@17
|
197 * elements involved in the sort action.
|
Chris@17
|
198 */
|
Chris@17
|
199 endButtonDrag(event, ui) {
|
Chris@17
|
200 const view = this;
|
Chris@17
|
201 Drupal.ckeditor.registerButtonMove(this, ui.item, success => {
|
Chris@17
|
202 if (!success) {
|
Chris@17
|
203 // Cancel any sorting in the configuration area.
|
Chris@17
|
204 view.$el.find('.ui-sortable').sortable('cancel');
|
Chris@17
|
205 }
|
Chris@17
|
206 // Refocus the target button so that the user can continue from a known
|
Chris@17
|
207 // place.
|
Chris@17
|
208 ui.item.find('a').trigger('focus');
|
Chris@17
|
209 });
|
Chris@17
|
210 },
|
Chris@17
|
211
|
Chris@17
|
212 /**
|
Chris@17
|
213 * Invokes jQuery.sortable() on new buttons and groups in a CKEditor config.
|
Chris@17
|
214 */
|
Chris@17
|
215 applySorting() {
|
Chris@17
|
216 // Make the buttons sortable.
|
Chris@17
|
217 this.$el
|
Chris@17
|
218 .find('.ckeditor-buttons')
|
Chris@17
|
219 .not('.ui-sortable')
|
Chris@17
|
220 .sortable({
|
Chris@17
|
221 // Change this to .ckeditor-toolbar-group-buttons.
|
Chris@17
|
222 connectWith: '.ckeditor-buttons',
|
Chris@17
|
223 placeholder: 'ckeditor-button-placeholder',
|
Chris@17
|
224 forcePlaceholderSize: true,
|
Chris@17
|
225 tolerance: 'pointer',
|
Chris@17
|
226 cursor: 'move',
|
Chris@17
|
227 start: this.startButtonDrag.bind(this),
|
Chris@17
|
228 // Sorting within a sortable.
|
Chris@17
|
229 stop: this.endButtonDrag.bind(this),
|
Chris@17
|
230 })
|
Chris@17
|
231 .disableSelection();
|
Chris@17
|
232
|
Chris@17
|
233 // Add the drag and drop functionality to button groups.
|
Chris@17
|
234 this.$el
|
Chris@17
|
235 .find('.ckeditor-toolbar-groups')
|
Chris@17
|
236 .not('.ui-sortable')
|
Chris@17
|
237 .sortable({
|
Chris@17
|
238 connectWith: '.ckeditor-toolbar-groups',
|
Chris@17
|
239 cancel: '.ckeditor-add-new-group',
|
Chris@17
|
240 placeholder: 'ckeditor-toolbar-group-placeholder',
|
Chris@17
|
241 forcePlaceholderSize: true,
|
Chris@17
|
242 cursor: 'move',
|
Chris@17
|
243 stop: this.endGroupDrag.bind(this),
|
Chris@17
|
244 });
|
Chris@17
|
245
|
Chris@17
|
246 // Add the drag and drop functionality to buttons.
|
Chris@17
|
247 this.$el.find('.ckeditor-multiple-buttons li').draggable({
|
Chris@17
|
248 connectToSortable: '.ckeditor-toolbar-active .ckeditor-buttons',
|
Chris@17
|
249 helper: 'clone',
|
Chris@17
|
250 });
|
Chris@17
|
251 },
|
Chris@17
|
252
|
Chris@17
|
253 /**
|
Chris@17
|
254 * Wraps the invocation of methods to insert blank groups and rows.
|
Chris@17
|
255 */
|
Chris@17
|
256 insertPlaceholders() {
|
Chris@17
|
257 this.insertPlaceholderRow();
|
Chris@17
|
258 this.insertNewGroupButtons();
|
Chris@17
|
259 },
|
Chris@17
|
260
|
Chris@17
|
261 /**
|
Chris@17
|
262 * Inserts a blank row at the bottom of the CKEditor configuration.
|
Chris@17
|
263 */
|
Chris@17
|
264 insertPlaceholderRow() {
|
Chris@17
|
265 let $rows = this.$el.find('.ckeditor-row');
|
Chris@17
|
266 // Add a placeholder row. to the end of the list if one does not exist.
|
Chris@17
|
267 if (!$rows.eq(-1).hasClass('placeholder')) {
|
Chris@17
|
268 this.$el
|
Chris@17
|
269 .find('.ckeditor-toolbar-active')
|
Chris@17
|
270 .children('.ckeditor-active-toolbar-configuration')
|
Chris@17
|
271 .append(Drupal.theme('ckeditorRow'));
|
Chris@17
|
272 }
|
Chris@17
|
273 // Update the $rows variable to include the new row.
|
Chris@17
|
274 $rows = this.$el.find('.ckeditor-row');
|
Chris@17
|
275 // Remove blank rows except the last one.
|
Chris@17
|
276 const len = $rows.length;
|
Chris@17
|
277 $rows
|
Chris@17
|
278 .filter((index, row) => {
|
Chris@17
|
279 // Do not remove the last row.
|
Chris@17
|
280 if (index + 1 === len) {
|
Chris@17
|
281 return false;
|
Chris@17
|
282 }
|
Chris@17
|
283 return (
|
Chris@17
|
284 $(row)
|
Chris@17
|
285 .find('.ckeditor-toolbar-group')
|
Chris@17
|
286 .not('.placeholder').length === 0
|
Chris@17
|
287 );
|
Chris@17
|
288 })
|
Chris@17
|
289 // Then get all rows that are placeholders and remove them.
|
Chris@17
|
290 .remove();
|
Chris@17
|
291 },
|
Chris@17
|
292
|
Chris@17
|
293 /**
|
Chris@17
|
294 * Inserts a button in each row that will add a new CKEditor button group.
|
Chris@17
|
295 */
|
Chris@17
|
296 insertNewGroupButtons() {
|
Chris@17
|
297 // Insert an add group button to each row.
|
Chris@17
|
298 this.$el.find('.ckeditor-row').each(function() {
|
Chris@17
|
299 const $row = $(this);
|
Chris@17
|
300 const $groups = $row.find('.ckeditor-toolbar-group');
|
Chris@17
|
301 const $button = $row.find('.ckeditor-add-new-group');
|
Chris@17
|
302 if ($button.length === 0) {
|
Chris@17
|
303 $row
|
Chris@17
|
304 .children('.ckeditor-toolbar-groups')
|
Chris@17
|
305 .append(Drupal.theme('ckeditorNewButtonGroup'));
|
Chris@17
|
306 }
|
Chris@17
|
307 // If a placeholder group exists, make sure it's at the end of the row.
|
Chris@17
|
308 else if (!$groups.eq(-1).hasClass('ckeditor-add-new-group')) {
|
Chris@17
|
309 $button.appendTo($row.children('.ckeditor-toolbar-groups'));
|
Chris@17
|
310 }
|
Chris@17
|
311 });
|
Chris@17
|
312 },
|
Chris@0
|
313 },
|
Chris@17
|
314 );
|
Chris@17
|
315 })(Drupal, Backbone, jQuery);
|