Skip to content

Commit

Permalink
Issue backdrop#101: Adding filters for caption and alignment for edit…
Browse files Browse the repository at this point in the history
…or image handling.
  • Loading branch information
quicksketch committed Jun 23, 2015
1 parent 589d1ba commit d4c688b
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 71 deletions.
28 changes: 23 additions & 5 deletions core/modules/ckeditor5/core/modules/ckeditor/ckeditor.module
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ function ckeditor_library_info() {
'js' => array(
$module_path . '/js/ckeditor.js' => array(),
),
'css' => array(
$module_path . '/css/ckeditor.css' => array(),
),
'dependencies' => array(
array('filter', 'filter'),
array('system', 'backdrop.ajax'),
Expand Down Expand Up @@ -277,7 +280,7 @@ function ckeditor_ckeditor_plugins() {
'required_html' => array(
array(
'tags' => array('img'),
'attributes' => array('src', 'alt', 'data-file-id'),
'attributes' => array('src', 'alt', 'data-file-id', 'data-align'),
),
),
'image' => $image_prefix . '/image.png',
Expand All @@ -294,11 +297,11 @@ function ckeditor_ckeditor_plugins() {
'required_html' => array(
array(
'tags' => array('img'),
'attributes' => array('data-caption', 'data-placeholder'),
'attributes' => array('data-caption'),
),
array(
'tags' => array('figure', 'figcaption'),
'attributes' => array('src', 'alt'),
'attributes' => array('src', 'alt', 'class', 'data-placeholder'),
),
)
);
Expand Down Expand Up @@ -330,6 +333,18 @@ function ckeditor_ckeditor_plugins() {
return $plugins;
}

/**
* Implements hook_form_FORM_ID_alter().
*
* Manipulate the image insert form to describe CKEditor-integration.
*/
function ckeditor_form_filter_format_editor_image_form_alter(&$form, $form_state) {
$format = $form_state['format'];
if ($format->editor === 'ckeditor') {
$form['caption']['#description'] = t('If checked, a caption area will appear in the editor.');
}
}

/**
* Enabled callback for hook_ckeditor_plugins().
*
Expand Down Expand Up @@ -485,8 +500,11 @@ function ckeditor_get_settings($format, $existing_settings) {
$settings['backdrop']['imageDialogUrl'] = url('editor/dialog/image');
}
if (isset($external_plugins['backdropimagecaption'])) {
$settings['backdrop']['captionFilterEnabled'] = array_key_exists('filter_image_caption', $format->filters);
$settings['backdrop']['alignFilterEnabled'] = array_key_exists('filter_image_align', $format->filters);
$settings['backdrop']['captionFilterEnabled'] = !empty($format->filters['filter_image_caption']->status);
$settings['backdrop']['alignFilterEnabled'] = !empty($format->filters['filter_image_align']->status);
$settings['backdrop']['imageCaptionPlaceholderText'] = t('Enter caption text here.');
$settings['image2_captionedClass'] = 'caption caption-img';
$settings['image2_alignClasses'] = array('align-left', 'align-center', 'align-right');
}
backdrop_alter('ckeditor_settings', $settings, $format);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,41 @@
* @file
* Caption: default styling for displaying image captions.
*/
div.caption {
display: inline-block;
}

div.caption-inner {
border: 1px solid #CCC;
padding: 4px;
background: #F3F3F3;
font-size: 0.857em; /* assuming you have a base font size of 14px, this is 12px */
text-align: center;
display: inline-block;
/**
* Figure and Figure Captions.
*
* Responsive figure elements, based on http://stackoverflow.com/a/13363408.
*/
.caption {
display: table;
margin: 0 12px 10px;
border: 1px solid #ccc;
}

div.caption p {
margin: .25em 0;
.align-center .caption {
margin-left: auto;
margin-right: auto;
}

div.caption img,
div.caption object {
margin-bottom: 5px;
.caption > * {
display: block;
max-width: 100%;
}

/** aligned captions **/
div.caption-left {
float: left;
margin: 10px 10px 10px 0;
.caption > figcaption {
display: table-caption;
caption-side: bottom;
max-width: none;
padding: 3px 6px;
border: 1px solid #ccc;
border-top: none;
background-color: #eee;
}

div.caption-right {
float: right;
margin: 10px 0 10px 10px;
}

div.caption-center {
display: block;
text-align: center;
}

div.caption-center .caption-inner {
display: inline-block;
/**
* While editing and whenever the caption is empty, show a placeholder.
*
* Based on http://codepen.io/flesler/pen/AEIFc.
*/
.caption > figcaption[contenteditable=true]:empty:before {
content: attr(data-placeholder);
font-style: italic;
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,14 @@ ol, ul, dl {
cursor: move;
margin: 10px 0;
}

/**
* CKEditor Image2 widgets wrap images in a <span> tag that requires center
* alignment. As normally the image itself has the "align-center" class that
* sets margin left/right to auto, on the front-end it will center. However,
* with the <span> wrapper, we need to center-align the entire wrapping
* paragraph tag while within CKEditor.
*/
p.align-center {
text-align: center;
}
12 changes: 0 additions & 12 deletions core/modules/ckeditor5/core/modules/ckeditor/css/ckeditor-rtl.css

This file was deleted.

28 changes: 28 additions & 0 deletions core/modules/ckeditor5/core/modules/ckeditor/css/ckeditor.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* CSS needed when displaying a CKEditor instance.
*/
.ckeditor-dialog-loading {
position: absolute;
top: 0;
width: 100%;
text-align: center;
}

.ckeditor-dialog-loading-link {
border-radius: 0 0 5px 5px;
border: 1px solid #B6B6B6;
border-top: none;
background: white;
padding: 3px 10px;
box-shadow: 0 0 10px -3px #000;
display: inline-block;
font-size: 14px;
position: relative;
top: 0;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@
// After a short delay, show "Loading…" message.
window.setTimeout(function () {
$content.find('span').animate({top: '0px'});
}, 1000);
}, 500);

// Store the save callback to be executed when this dialog is closed.
Backdrop.ckeditor.saveCallback = saveCallback;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ CKEDITOR.plugins.add('backdropimage', {
}

// Override requiredContent & allowedContent.
widgetDefinition.requiredContent = 'img[alt,src,width,height,data-file-id]';
widgetDefinition.allowedContent.img.attributes += ',!data-file-id';
widgetDefinition.requiredContent = 'img[alt,src,width,height]';
widgetDefinition.allowedContent.img.attributes += ',data-file-id';
// We don't allow <figure>, <figcaption>, <div> or <p> in our downcast.
delete widgetDefinition.allowedContent.figure;
delete widgetDefinition.allowedContent.figcaption;
Expand All @@ -40,9 +40,14 @@ CKEDITOR.plugins.add('backdropimage', {

// Override downcast(): since we only accept <img> in our upcast method,
// the element is already correct. We only need to update the element's
// data-entity-uuid attribute.
// data-file-id attribute.
widgetDefinition.downcast = function (element) {
element.attributes['data-entity-uuid'] = this.data['data-entity-uuid'];
if (this.data['data-file-id']) {
element.attributes['data-file-id'] = this.data['data-file-id'];
}
else if (element.attributes['data-file-id']) {
delete element.attributes['data-file-id'];
}
};

// We want to upcast <img> elements to a DOM structure required by the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@ CKEDITOR.plugins.add('backdropimagecaption', {
requires: 'backdropimage',

beforeInit: function (editor) {
// Backdrop.t() will not work inside CKEditor plugins because CKEditor loads
// the JavaScript file instead of Backdrop. Pull translated strings from the
// plugin settings that are translated server-side.
var placeholderText = editor.config.backdrop.imageCaptionPlaceholderText;

// Disable default placeholder text that comes with CKEditor's image2
// plugin: it has an inferior UX (it requires the user to manually delete
// the place holder text).
editor.lang.image2.captionPlaceholder = '';

// Backdrop.t() will not work inside CKEditor plugins because CKEditor loads
// the JavaScript file instead of Backdrop. Pull translated strings from the
// plugin settings that are translated server-side.
var placeholderText = editor.config.backdropImageCaption_captionPlaceholderText;

// Override the image2 widget definition to handle the additional
// data-align and data-caption attributes.
editor.on('widgetDefinition', function (event) {
Expand All @@ -48,13 +48,11 @@ CKEDITOR.plugins.add('backdropimagecaption', {
}, true);

// Override requiredContent & allowedContent.
widgetDefinition.requiredContent = 'img[alt,src,width,height,data-file-id,data-align,data-caption]';
widgetDefinition.requiredContent = 'img[alt,src,width,height,data-align,data-caption]';
widgetDefinition.allowedContent.img.attributes += ',data-align,data-caption';

// Override allowedContent setting for the 'caption' nested editable.
// This must match what caption_filter enforces.
// @see \Backdrop\filter\Plugin\Filter\FilterCaption::process()
// @see \Backdrop\Component\Utility\Xss::filter()
widgetDefinition.editables.caption.allowedContent = 'a[!href]; em strong cite code br';

// Override downcast(): ensure we *only* output <img>, but also ensure
Expand All @@ -65,8 +63,7 @@ CKEDITOR.plugins.add('backdropimagecaption', {
var caption = this.editables.caption;
var captionHtml = caption && caption.getData();
var attrs = img.attributes;
console.log(img);
console.log(captionFilterEnabled);

if (captionFilterEnabled) {
// If image contains a non-empty caption, serialize caption to the
// data-caption attribute.
Expand All @@ -79,7 +76,17 @@ console.log(captionFilterEnabled);
attrs['data-align'] = this.data.align;
}
}
attrs['data-file-id'] = this.data['data-file-id'];
if (this.data['data-file-id']) {
attrs['data-file-id'] = this.data['data-file-id'];
}
else if (attrs['data-file-id']) {
delete attrs['data-file-id'];
}

// CKEditor seems to apply the caption class to downcast elements, which
// we do not want. Make sure that the caption class doesn't end up in
// the raw source.
img.removeClass(editor.config.image2_captionedClass);

return img;
};
Expand All @@ -91,14 +98,17 @@ console.log(captionFilterEnabled);
// - <figure> tag (captioned image).
// We take the same attributes into account as downcast() does.
widgetDefinition.upcast = function (element, data) {
if (element.name !== 'img' || !element.attributes['data-file-id']) {
if (element.name !== 'img') {
return;
}
// Don't initialize on pasted fake objects.
else if (element.attributes['data-cke-realelement']) {
return;
}

// Remove any caption classes from the raw element itself.
element.removeClass(editor.config.image2_captionedClass);

var attrs = element.attributes;
var retElement = element;
var caption;
Expand Down Expand Up @@ -180,7 +190,7 @@ console.log(captionFilterEnabled);
CKEDITOR.tools.extend(widgetDefinition._mapDataToDialog, {
'align': 'data-align',
'data-caption': 'data-caption',
'hasCaption': 'has-caption'
'hasCaption': 'data-has-caption'
});

// Override Backdrop dialog save callback.
Expand All @@ -195,15 +205,24 @@ console.log(captionFilterEnabled);
// widget.data.hasCaption as "changed" (e.g. when hasCaption === 0
// instead of hasCaption === false). This causes image2's "state
// shifter" to enter the wrong branch of the algorithm and blow up.
dialogReturnValues['has-caption'] = !!dialogReturnValues['has-caption'];
dialogReturnValues.attributes['data-has-caption'] = !!dialogReturnValues.attributes['data-has-caption'];

var actualWidget = saveCallback(dialogReturnValues);

// By default, the template of captioned widget has no
// data-placeholder attribute. Note that it also must be done when
// upcasting existing elements (see widgetDefinition.upcast).
if (dialogReturnValues['has-caption']) {
if (dialogReturnValues.attributes['data-has-caption']) {
actualWidget.editables.caption.setAttribute('data-placeholder', placeholderText);

// Firefox will add a <br> tag to a newly created DOM element with
// no content. Remove this <br> if it is the only thing in the
// caption. Our placeholder support requires the element be entirely
// empty. See ckeditor-caption.css.
var captionElement = actualWidget.editables.caption.$;
if (captionElement.childNodes.length === 1 && captionElement.childNodes.item(0).nodeName === 'BR') {
captionElement.removeChild(captionElement.childNodes.item(0));
}
}
};
};
Expand Down

0 comments on commit d4c688b

Please sign in to comment.