3 * A Backbone View that provides the visual UX view of CKEditor toolbar
7 (function(Drupal, Backbone, $) {
8 Drupal.ckeditor.VisualView = Backbone.View.extend(
9 /** @lends Drupal.ckeditor.VisualView# */ {
11 'click .ckeditor-toolbar-group-name': 'onGroupNameClick',
12 'click .ckeditor-groupnames-toggle': 'onGroupNamesToggleClick',
13 'click .ckeditor-add-new-group button': 'onAddGroupButtonClick',
17 * Backbone View for CKEditor toolbar configuration; visual UX.
21 * @augments Backbone.View
26 'change:isDirty change:groupNamesVisible',
30 // Add a toggle for the button group names.
31 $(Drupal.theme('ckeditorButtonGroupNamesToggle')).prependTo(
32 this.$el.find('#ckeditor-active-toolbar').parent(),
39 * Render function for rendering the toolbar configuration.
42 * Model used for the view.
43 * @param {string} [value]
44 * The value that was changed.
45 * @param {object} changedAttributes
46 * The attributes that was changed.
48 * @return {Drupal.ckeditor.VisualView}
49 * The {@link Drupal.ckeditor.VisualView} object.
51 render(model, value, changedAttributes) {
52 this.insertPlaceholders();
55 // Toggle button group names.
56 let groupNamesVisible = this.model.get('groupNamesVisible');
57 // If a button was just placed in the active toolbar, ensure that the
58 // button group names are visible.
61 changedAttributes.changes &&
62 changedAttributes.changes.isDirty
64 this.model.set({ groupNamesVisible: true }, { silent: true });
65 groupNamesVisible = true;
68 .find('[data-toolbar="active"]')
69 .toggleClass('ckeditor-group-names-are-visible', groupNamesVisible);
71 .find('.ckeditor-groupnames-toggle')
74 ? Drupal.t('Hide group names')
75 : Drupal.t('Show group names'),
77 .attr('aria-pressed', groupNamesVisible);
83 * Handles clicks to a button group name.
85 * @param {jQuery.Event} event
86 * The click event on the button group.
88 onGroupNameClick(event) {
89 const $group = $(event.currentTarget).closest(
90 '.ckeditor-toolbar-group',
92 Drupal.ckeditor.openGroupNameDialog(this, $group);
94 event.stopPropagation();
95 event.preventDefault();
99 * Handles clicks on the button group names toggle button.
101 * @param {jQuery.Event} event
102 * The click event on the toggle button.
104 onGroupNamesToggleClick(event) {
107 !this.model.get('groupNamesVisible'),
109 event.preventDefault();
113 * Prompts the user to provide a name for a new button group; inserts it.
115 * @param {jQuery.Event} event
116 * The event of the button click.
118 onAddGroupButtonClick(event) {
120 * Inserts a new button if the openGroupNameDialog function returns true.
122 * @param {bool} success
123 * A flag that indicates if the user created a new group (true) or
124 * canceled out of the dialog (false).
125 * @param {jQuery} $group
126 * A jQuery DOM fragment that represents the new button group. It has
127 * not been added to the DOM yet.
129 function insertNewGroup(success, $group) {
132 $(event.currentTarget)
133 .closest('.ckeditor-row')
134 .children('.ckeditor-toolbar-groups'),
136 // Focus on the new group.
137 $group.trigger('focus');
141 // Pass in a DOM fragment of a placeholder group so that the new group
142 // name can be applied to it.
143 Drupal.ckeditor.openGroupNameDialog(
145 $(Drupal.theme('ckeditorToolbarGroup')),
149 event.preventDefault();
153 * Handles jQuery Sortable stop sort of a button group.
155 * @param {jQuery.Event} event
156 * The event triggered on the group drag.
158 * A jQuery.ui.sortable argument that contains information about the
159 * elements involved in the sort action.
161 endGroupDrag(event, ui) {
163 Drupal.ckeditor.registerGroupMove(this, ui.item, success => {
165 // Cancel any sorting in the configuration area.
167 .find('.ckeditor-toolbar-configuration')
168 .find('.ui-sortable')
175 * Handles jQuery Sortable start sort of a button.
177 * @param {jQuery.Event} event
178 * The event triggered on the group drag.
180 * A jQuery.ui.sortable argument that contains information about the
181 * elements involved in the sort action.
183 startButtonDrag(event, ui) {
184 this.$el.find('a:focus').trigger('blur');
186 // Show the button group names as soon as the user starts dragging.
187 this.model.set('groupNamesVisible', true);
191 * Handles jQuery Sortable stop sort of a button.
193 * @param {jQuery.Event} event
194 * The event triggered on the button drag.
196 * A jQuery.ui.sortable argument that contains information about the
197 * elements involved in the sort action.
199 endButtonDrag(event, ui) {
201 Drupal.ckeditor.registerButtonMove(this, ui.item, success => {
203 // Cancel any sorting in the configuration area.
204 view.$el.find('.ui-sortable').sortable('cancel');
206 // Refocus the target button so that the user can continue from a known
208 ui.item.find('a').trigger('focus');
213 * Invokes jQuery.sortable() on new buttons and groups in a CKEditor config.
216 // Make the buttons sortable.
218 .find('.ckeditor-buttons')
221 // Change this to .ckeditor-toolbar-group-buttons.
222 connectWith: '.ckeditor-buttons',
223 placeholder: 'ckeditor-button-placeholder',
224 forcePlaceholderSize: true,
225 tolerance: 'pointer',
227 start: this.startButtonDrag.bind(this),
228 // Sorting within a sortable.
229 stop: this.endButtonDrag.bind(this),
233 // Add the drag and drop functionality to button groups.
235 .find('.ckeditor-toolbar-groups')
238 connectWith: '.ckeditor-toolbar-groups',
239 cancel: '.ckeditor-add-new-group',
240 placeholder: 'ckeditor-toolbar-group-placeholder',
241 forcePlaceholderSize: true,
243 stop: this.endGroupDrag.bind(this),
246 // Add the drag and drop functionality to buttons.
247 this.$el.find('.ckeditor-multiple-buttons li').draggable({
248 connectToSortable: '.ckeditor-toolbar-active .ckeditor-buttons',
254 * Wraps the invocation of methods to insert blank groups and rows.
256 insertPlaceholders() {
257 this.insertPlaceholderRow();
258 this.insertNewGroupButtons();
262 * Inserts a blank row at the bottom of the CKEditor configuration.
264 insertPlaceholderRow() {
265 let $rows = this.$el.find('.ckeditor-row');
266 // Add a placeholder row. to the end of the list if one does not exist.
267 if (!$rows.eq(-1).hasClass('placeholder')) {
269 .find('.ckeditor-toolbar-active')
270 .children('.ckeditor-active-toolbar-configuration')
271 .append(Drupal.theme('ckeditorRow'));
273 // Update the $rows variable to include the new row.
274 $rows = this.$el.find('.ckeditor-row');
275 // Remove blank rows except the last one.
276 const len = $rows.length;
278 .filter((index, row) => {
279 // Do not remove the last row.
280 if (index + 1 === len) {
285 .find('.ckeditor-toolbar-group')
286 .not('.placeholder').length === 0
289 // Then get all rows that are placeholders and remove them.
294 * Inserts a button in each row that will add a new CKEditor button group.
296 insertNewGroupButtons() {
297 // Insert an add group button to each row.
298 this.$el.find('.ckeditor-row').each(function() {
299 const $row = $(this);
300 const $groups = $row.find('.ckeditor-toolbar-group');
301 const $button = $row.find('.ckeditor-add-new-group');
302 if ($button.length === 0) {
304 .children('.ckeditor-toolbar-groups')
305 .append(Drupal.theme('ckeditorNewButtonGroup'));
307 // If a placeholder group exists, make sure it's at the end of the row.
308 else if (!$groups.eq(-1).hasClass('ckeditor-add-new-group')) {
309 $button.appendTo($row.children('.ckeditor-toolbar-groups'));
315 })(Drupal, Backbone, jQuery);