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