Commit b61edd72 authored by alexpott's avatar alexpott

Issue #2174589 by Wim Leers, ikeigenwijs, el7cosmos, setvik, YesCT: Split up ckeditor.admin.js

parent fda020ec
......@@ -23,7 +23,15 @@ drupal.ckeditor.plugins.drupalimagecaption:
drupal.ckeditor.admin:
version: VERSION
js:
# Core.
js/ckeditor.admin.js: {}
# Models.
js/models/Model.js: {}
# Views.
js/views/AuralView.js: {}
js/views/KeyboardView.js: {}
js/views/ControllerView.js: {}
js/views/VisualView.js: {}
css:
theme:
css/ckeditor.admin.css: {}
......
This diff is collapsed.
/**
* @file
* A Backbone Model for the state of a CKEditor toolbar configuration .
*/
(function (Drupal, Backbone) {
"use strict";
/**
* Backbone model for the CKEditor toolbar configuration state.
*/
Drupal.ckeditor.Model = Backbone.Model.extend({
defaults: {
// The CKEditor configuration that is being manipulated through the UI.
activeEditorConfig: null,
// The textarea that contains the serialized representation of the active
// CKEditor configuration.
$textarea: null,
// Tracks whether the active toolbar DOM structure has been changed. When
// true, activeEditorConfig needs to be updated, and when that is updated,
// $textarea will also be updated.
isDirty: false,
// The configuration for the hidden CKEditor instance that is used to build
// the features metadata.
hiddenEditorConfig: null,
// A hash, keyed by a feature name, that details CKEditor plugin features.
featuresMetadata: null,
// Whether the button group names are currently visible.
groupNamesVisible: false
},
sync: function () {
// Push the settings into the textarea.
this.get('$textarea').val(JSON.stringify(this.get('activeEditorConfig')));
}
});
})(Drupal, Backbone);
/**
* @file
* A Backbone View that provides the aural view of CKEditor toolbar configuration.
*/
(function (Drupal, Backbone, $) {
"use strict";
/**
* Backbone View for CKEditor toolbar configuration; aural UX (output only).
*/
Drupal.ckeditor.AuralView = Backbone.View.extend({
events: {
'click .ckeditor-buttons a': 'announceButtonHelp',
'click .ckeditor-multiple-buttons a': 'announceSeparatorHelp',
'focus .ckeditor-button a': 'onFocus',
'focus .ckeditor-button-separator a': 'onFocus',
'focus .ckeditor-toolbar-group': 'onFocus'
},
/**
* {@inheritdoc}
*/
initialize: function () {
// Announce the button and group positions when the model is no longer
// dirty.
this.listenTo(this.model, 'change:isDirty', this.announceMove);
},
/**
* Calls announce on buttons and groups when their position is changed.
*
* @param Drupal.ckeditor.ConfigurationModel model
* @param Boolean isDirty
* A model attribute that indicates if the changed toolbar configuration
* has been stored or not.
*/
announceMove: function (model, isDirty) {
// Announce the position of a button or group after the model has been
// updated.
if (!isDirty) {
var item = document.activeElement || null;
if (item) {
var $item = $(item);
if ($item.hasClass('ckeditor-toolbar-group')) {
this.announceButtonGroupPosition($item);
}
else if ($item.parent().hasClass('ckeditor-button')) {
this.announceButtonPosition($item.parent());
}
}
}
},
/**
* Handles the focus event of elements in the active and available toolbars.
*
* @param jQuery.Event event
*/
onFocus: function (event) {
event.stopPropagation();
var $originalTarget = $(event.target);
var $currentTarget = $(event.currentTarget);
var $parent = $currentTarget.parent();
if ($parent.hasClass('ckeditor-button') || $parent.hasClass('ckeditor-button-separator')) {
this.announceButtonPosition($currentTarget.parent());
}
else if ($originalTarget.attr('role') !== 'button' && $currentTarget.hasClass('ckeditor-toolbar-group')) {
this.announceButtonGroupPosition($currentTarget);
}
},
/**
* Announces the current position of a button group.
*
* @param jQuery $group
* A jQuery set that contains an li element that wraps a group of buttons.
*/
announceButtonGroupPosition: function ($group) {
var $groups = $group.parent().children();
var $row = $group.closest('.ckeditor-row');
var $rows = $row.parent().children();
var position = $groups.index($group) + 1;
var positionCount = $groups.not('.placeholder').length;
var row = $rows.index($row) + 1;
var rowCount = $rows.not('.placeholder').length;
var text = Drupal.t('@groupName button group in position @position of @positionCount in row @row of @rowCount.', {
'@groupName': $group.attr('data-drupal-ckeditor-toolbar-group-name'),
'@position': position,
'@positionCount': positionCount,
'@row': row,
'@rowCount': rowCount
});
// If this position is the first in the last row then tell the user that
// pressing the down arrow key will create a new row.
if (position === 1 && row === rowCount) {
text += "\n";
text += Drupal.t("Press the down arrow key to create a new row.");
}
Drupal.announce(text, 'assertive');
},
/**
* Announces current button position.
*
* @param jQuery $button
* A jQuery set that contains an li element that wraps a button.
*/
announceButtonPosition: function ($button) {
var $row = $button.closest('.ckeditor-row');
var $rows = $row.parent().children();
var $buttons = $button.closest('.ckeditor-buttons').children();
var $group = $button.closest('.ckeditor-toolbar-group');
var $groups = $group.parent().children();
var groupPosition = $groups.index($group) + 1;
var groupPositionCount = $groups.not('.placeholder').length;
var position = $buttons.index($button) + 1;
var positionCount = $buttons.length;
var row = $rows.index($row) + 1;
var rowCount = $rows.not('.placeholder').length;
// The name of the button separator is 'button separator' and its type
// is 'separator', so we do not want to print the type of this item,
// otherwise the UA will speak 'button separator separator'.
var type = ($button.attr('data-drupal-ckeditor-type') === 'separator') ? '' : Drupal.t('button');
var text;
// The button is located in the available button set.
if ($button.closest('.ckeditor-toolbar-disabled').length > 0) {
text = Drupal.t('@name @type.', {
'@name': $button.children().attr('aria-label'),
'@type': type
});
text += "\n" + Drupal.t('Press the down arrow key to activate.');
Drupal.announce(text, 'assertive');
}
// The button is in the active toolbar.
else if ($group.not('.placeholder').length === 1) {
text = Drupal.t('@name @type in position @position of @positionCount in @groupName button group in row @row of @rowCount.', {
'@name': $button.children().attr('aria-label'),
'@type': type,
'@position': position,
'@positionCount': positionCount,
'@groupName': $group.attr('data-drupal-ckeditor-toolbar-group-name'),
'@row': row,
'@rowCount': rowCount
});
// If this position is the first in the last row then tell the user that
// pressing the down arrow key will create a new row.
if (groupPosition === 1 && position === 1 && row === rowCount) {
text += "\n";
text += Drupal.t("Press the down arrow key to create a new button group in a new row.");
}
// If this position is the last one in this row then tell the user that
// moving the button to the next group will create a new group.
if (groupPosition === groupPositionCount && position === positionCount) {
text += "\n";
text += Drupal.t("This is the last group. Move the button forward to create a new group.");
}
Drupal.announce(text, 'assertive');
}
},
/**
* Provides help information when a button is clicked.
*
* @param jQuery.Event event
*/
announceButtonHelp: function (event) {
var $link = $(event.currentTarget);
var $button = $link.parent();
var enabled = $button.closest('.ckeditor-toolbar-active').length > 0;
var message;
if (enabled) {
message = Drupal.t('The "@name" button is currently enabled.', {
'@name': $link.attr('aria-label')
});
message += "\n" + Drupal.t('Use the keyboard arrow keys to change the position of this button.');
message += "\n" + Drupal.t('Press the up arrow key on the top row to disable the button.');
}
else {
message = Drupal.t('The "@name" button is currently disabled.', {
'@name': $link.attr('aria-label')
});
message += "\n" + Drupal.t('Use the down arrow key to move this button into the active toolbar.');
}
Drupal.announce(message);
event.preventDefault();
},
/**
* Provides help information when a separator is clicked.
*
* @param jQuery.Event event
*/
announceSeparatorHelp: function (event) {
var $link = $(event.currentTarget);
var $button = $link.parent();
var enabled = $button.closest('.ckeditor-toolbar-active').length > 0;
var message;
if (enabled) {
message = Drupal.t('This @name is currently enabled.', {
'@name': $link.attr('aria-label')
});
message += "\n" + Drupal.t('Use the keyboard arrow keys to change the position of this separator.');
}
else {
message = Drupal.t('Separators are used to visually split individual buttons.');
message += "\n" + Drupal.t('This @name is currently disabled.', {
'@name': $link.attr('aria-label')
});
message += "\n" + Drupal.t('Use the down arrow key to move this separator into the active toolbar.');
message += "\n" + Drupal.t('You may add multiple separators to each button group.');
}
Drupal.announce(message);
event.preventDefault();
}
});
})(Drupal, Backbone, jQuery);
This diff is collapsed.
This diff is collapsed.
/**
* @file
* A Backbone View that provides the visual UX view of CKEditor toolbar configuration.
*/
(function (Drupal, Backbone, $) {
"use strict";
/**
* Backbone View for CKEditor toolbar configuration; visual UX.
*/
Drupal.ckeditor.VisualView = Backbone.View.extend({
events: {
'click .ckeditor-toolbar-group-name': 'onGroupNameClick',
'click .ckeditor-groupnames-toggle': 'onGroupNamesToggleClick',
'click .ckeditor-add-new-group button': 'onAddGroupButtonClick'
},
/**
* {@inheritdoc}
*/
initialize: function () {
this.listenTo(this.model, 'change:isDirty change:groupNamesVisible', this.render);
// Add a toggle for the button group names.
$(Drupal.theme('ckeditorButtonGroupNamesToggle'))
.prependTo(this.$el.find('#ckeditor-active-toolbar').parent());
this.render();
},
/**
* {@inheritdoc}
*/
render: function (model, value, changedAttributes) {
this.insertPlaceholders();
this.applySorting();
// Toggle button group names.
var groupNamesVisible = this.model.get('groupNamesVisible');
// If a button was just placed in the active toolbar, ensure that the
// button group names are visible.
if (changedAttributes && changedAttributes.changes && changedAttributes.changes.isDirty) {
this.model.set({groupNamesVisible: true}, {silent: true});
groupNamesVisible = true;
}
this.$el.find('[data-toolbar="active"]').toggleClass('ckeditor-group-names-are-visible', groupNamesVisible);
this.$el.find('.ckeditor-groupnames-toggle')
.text((groupNamesVisible) ? Drupal.t('Hide group names') : Drupal.t('Show group names'))
.attr('aria-pressed', groupNamesVisible);
return this;
},
/**
* Handles clicks to a button group name.
*
* @param jQuery.Event event
*/
onGroupNameClick: function (event) {
var $group = $(event.currentTarget).closest('.ckeditor-toolbar-group');
Drupal.ckeditor.openGroupNameDialog(this, $group);
event.stopPropagation();
event.preventDefault();
},
/**
* Handles clicks on the button group names toggle button.
*/
onGroupNamesToggleClick: function (event) {
this.model.set('groupNamesVisible', !this.model.get('groupNamesVisible'));
event.preventDefault();
},
/**
* Prompts the user to provide a name for a new button group; inserts it.
*
* @param jQuery.Event event
*/
onAddGroupButtonClick: function (event) {
/**
* Inserts a new button if the openGroupNameDialog function returns true.
*
* @param Boolean success
* A flag that indicates if the user created a new group (true) or
* canceled out of the dialog (false).
* @param jQuery $group
* A jQuery DOM fragment that represents the new button group. It has
* not been added to the DOM yet.
*/
function insertNewGroup(success, $group) {
if (success) {
$group.appendTo($(event.currentTarget).closest('.ckeditor-row').children('.ckeditor-toolbar-groups'));
// Focus on the new group.
$group.trigger('focus');
}
}
// Pass in a DOM fragment of a placeholder group so that the new group
// name can be applied to it.
Drupal.ckeditor.openGroupNameDialog(this, $(Drupal.theme('ckeditorToolbarGroup')), insertNewGroup);
event.preventDefault();
},
/**
* Handles jQuery Sortable stop sort of a button group.
*
* @param jQuery.Event event
* @param Object ui
* A jQuery.ui.sortable argument that contains information about the
* elements involved in the sort action.
*/
endGroupDrag: function (event, ui) {
var view = this;
Drupal.ckeditor.registerGroupMove(this, ui.item, function (success) {
if (!success) {
// Cancel any sorting in the configuration area.
view.$el.find('.ckeditor-toolbar-configuration').find('.ui-sortable').sortable('cancel');
}
});
},
/**
* Handles jQuery Sortable start sort of a button.
*
* @param jQuery.Event event
* @param Object ui
* A jQuery.ui.sortable argument that contains information about the
* elements involved in the sort action.
*/
startButtonDrag: function (event, ui) {
this.$el.find('a:focus').trigger('blur');
// Show the button group names as soon as the user starts dragging.
this.model.set('groupNamesVisible', true);
},
/**
* Handles jQuery Sortable stop sort of a button.
*
* @param jQuery.Event event
* @param Object ui
* A jQuery.ui.sortable argument that contains information about the
* elements involved in the sort action.
*/
endButtonDrag: function (event, ui) {
var view = this;
Drupal.ckeditor.registerButtonMove(this, ui.item, function (success) {
if (!success) {
// Cancel any sorting in the configuration area.
view.$el.find('.ui-sortable').sortable('cancel');
}
// Refocus the target button so that the user can continue from a known
// place.
ui.item.find('a').trigger('focus');
});
},
/**
* Invokes jQuery.sortable() on new buttons and groups in a CKEditor config.
*/
applySorting: function () {
// Make the buttons sortable.
this.$el.find('.ckeditor-buttons').not('.ui-sortable').sortable({
// Change this to .ckeditor-toolbar-group-buttons.
connectWith: '.ckeditor-buttons',
placeholder: 'ckeditor-button-placeholder',
forcePlaceholderSize: true,
tolerance: 'pointer',
cursor: 'move',
start: this.startButtonDrag.bind(this),
// Sorting within a sortable.
stop: this.endButtonDrag.bind(this)
}).disableSelection();
// Add the drag and drop functionality to button groups.
this.$el.find('.ckeditor-toolbar-groups').not('.ui-sortable').sortable({
connectWith: '.ckeditor-toolbar-groups',
cancel: '.ckeditor-add-new-group',
placeholder: 'ckeditor-toolbar-group-placeholder',
forcePlaceholderSize: true,
cursor: 'move',
stop: this.endGroupDrag.bind(this)
});
// Add the drag and drop functionality to buttons.
this.$el.find('.ckeditor-multiple-buttons li').draggable({
connectToSortable: '.ckeditor-toolbar-active .ckeditor-buttons',
helper: 'clone'
});
},
/**
* Wraps the invocation of methods to insert blank groups and rows.
*/
insertPlaceholders: function () {
this.insertPlaceholderRow();
this.insertNewGroupButtons();
},
/**
* Inserts a blank row at the bottom of the CKEditor configuration.
*/
insertPlaceholderRow: function () {
var $rows = this.$el.find('.ckeditor-row');
// Add a placeholder row. to the end of the list if one does not exist.
if (!$rows.eq(-1).hasClass('placeholder')) {
this.$el
.find('.ckeditor-toolbar-active')
.children('.ckeditor-active-toolbar-configuration')
.append(Drupal.theme('ckeditorRow'));
}
// Update the $rows variable to include the new row.
$rows = this.$el.find('.ckeditor-row');
// Remove blank rows except the last one.
var len = $rows.length;
$rows.filter(function (index, row) {
// Do not remove the last row.
if (index + 1 === len) {
return false;
}
return $(row).find('.ckeditor-toolbar-group').not('.placeholder').length === 0;
})
// Then get all rows that are placeholders and remove them.
.remove();
},
/**
* Inserts a button in each row that will add a new CKEditor button group.
*/
insertNewGroupButtons: function () {
// Insert an add group button to each row.
this.$el.find('.ckeditor-row').each(function () {
var $row = $(this);
var $groups = $row.find('.ckeditor-toolbar-group');
var $button = $row.find('.ckeditor-add-new-group');
if ($button.length === 0) {
$row.children('.ckeditor-toolbar-groups').append(Drupal.theme('ckeditorNewButtonGroup'));
}
// If a placeholder group exists, make sure it's at the end of the row.
else if (!$groups.eq(-1).hasClass('ckeditor-add-new-group')) {
$button.appendTo($row.children('.ckeditor-toolbar-groups'));
}
});
}
});
})(Drupal, Backbone, jQuery);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment