comparison core/modules/ckeditor/js/views/VisualView.es6.js @ 4:a9cd425dd02b

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