diff -u b/core/modules/image/css/editors/image.css b/core/modules/image/css/editors/image.css
--- b/core/modules/image/css/editors/image.css
+++ b/core/modules/image/css/editors/image.css
@@ -1,6 +1,11 @@
/**
* @file
- * Styles for the Image module's in-place editor.
+ * Functional styles for the Image module's in-place editor.
+ */
+
+/**
+ * A minimum width/height is required so that users can drag and drop files
+ * onto small images.
*/
.quickedit-image-element {
min-width: 200px;
@@ -10,106 +15,38 @@
.quickedit-image-dropzone {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- background: rgba(116, 183, 255, 0.8);
- transition: background .2s;
-}
-
-.quickedit-image-dropzone.hover {
- background: rgba(116, 183, 255, 0.9);
-}
-
-.quickedit-image-dropzone.error {
- background: rgba(255, 52, 27, 0.81);
-}
-
-.quickedit-image-dropzone * {
- pointer-events: none;
}
.quickedit-image-icon {
display: block;
width: 50px;
height: 50px;
- margin: 0 0 10px 0;
background-repeat: no-repeat;
background-size: cover;
- transition: margin .5s;
-}
-
-.quickedit-image-dropzone.upload .quickedit-image-icon {
- background-image: url('../../images/upload.svg');
-}
-
-.quickedit-image-dropzone.error .quickedit-image-icon {
- background-image: url('../../images/error.svg');
-}
-
-.quickedit-image-dropzone.loading .quickedit-image-icon {
- margin: -10px 0 20px 0;
-}
-
-.quickedit-image-dropzone.loading .quickedit-image-icon::after {
- display: block;
- content: "";
- margin-left: -10px;
- margin-top: -5px;
- animation-duration: 2s;
- animation-name: quickedit-image-spin;
- animation-iteration-count: infinite;
- animation-timing-function: linear;
- width: 60px;
- height: 60px;
- border-style: solid;
- border-radius: 35px;
- border-width: 5px;
- border-color: white transparent transparent transparent;
-}
-
-@keyframes quickedit-image-spin {
- 0% {transform: rotate(0deg);}
- 50% {transform: rotate(180deg);}
- 100% {transform: rotate(360deg);}
-}
-
-.quickedit-image-text {
- display: block;
- text-align: center;
- color: white;
- font-family: "Droid sans", "Lucida Grande", sans-serif;
- pointer-events: none;
- font-size: 16px;
- -webkit-user-select: none;
}
.quickedit-image-field-info {
display: flex;
align-items: center;
justify-content: flex-end;
- background: rgba(0, 0, 0, 0.05);
- border-top: 1px solid #c5c5c5;
- padding: 5px;
}
-.quickedit-image-field-info label, .quickedit-image-field-info input {
- margin-right: 5px;
-}
-
-.quickedit-image-field-info input:last-child {
- margin-right: 0;
-}
-
-.quickedit-image-errors .messages__wrapper {
- margin: 0;
- padding: 0;
+.quickedit-image-text {
+ display: block;
}
-.quickedit-image-errors .messages--error {
- box-shadow: none;
+/**
+ * If we do not prevent pointer-events for child elements, our drag+drop events
+ * will not fire properly. This can lead to unintentional redirects if a file
+ * is dropped on a child element when a user intended to upload it.
+ */
+.quickedit-image-dropzone * {
+ pointer-events: none;
}
diff -u b/core/modules/image/image.install b/core/modules/image/image.install
--- b/core/modules/image/image.install
+++ b/core/modules/image/image.install
@@ -66,5 +66,5 @@
* Flush caches as we changed field formatter metadata.
*/
-function image_update_8001() {
+function image_update_8201() {
// Empty update to trigger a cache flush.
}
diff -u b/core/modules/image/image.libraries.yml b/core/modules/image/image.libraries.yml
--- b/core/modules/image/image.libraries.yml
+++ b/core/modules/image/image.libraries.yml
@@ -12,4 +12,6 @@
component:
css/editors/image.css: {}
+ theme:
+ css/editors/image.theme.css: {}
dependencies:
- quickedit/quickedit
diff -u b/core/modules/image/images/error.svg b/core/modules/image/images/error.svg
--- b/core/modules/image/images/error.svg
+++ b/core/modules/image/images/error.svg
@@ -4 +4 @@
-
\ No newline at end of file
+
diff -u b/core/modules/image/js/editors/image.js b/core/modules/image/js/editors/image.js
--- b/core/modules/image/js/editors/image.js
+++ b/core/modules/image/js/editors/image.js
@@ -7,6 +7,77 @@
'use strict';
+ /**
+ * Theme function for validation errors of the Image module's in-place
+ * editor.
+ *
+ * @param {object} settings
+ * Settings object used to construct the markup.
+ * @param {string} settings.errors
+ * Already escaped HTML representing error messages.
+ *
+ * @return {string}
+ * The corresponding HTML.
+ */
+ Drupal.theme.quickeditImageErrors = _.template(
+ '
' +
+ ' <%= errors %>' +
+ '
'
+ );
+
+ /**
+ * Theme function for the dropzone element of the Image module's in-place
+ * editor.
+ *
+ * @param {object} settings
+ * Settings object used to construct the markup.
+ * @param {string} settings.text
+ * Text to display inline with the dropzone element.
+ *
+ * @return {string}
+ * The corresponding HTML.
+ */
+ Drupal.theme.quickeditImageDropzone = _.template(
+ '' +
+ ' ' +
+ ' <%- text %>' +
+ '
'
+ );
+
+ /**
+ * Theme function for the toolbar of the Image module's in-place editor.
+ *
+ * @param {object} settings
+ * Settings object used to construct the markup.
+ * @param {bool} settings.alt_field
+ * Whether or not the "Alt" field is enabled for this field.
+ * @param {bool} settings.alt_field_required
+ * Whether or not the "Alt" field is required for this field.
+ * @param {string} settings.alt
+ * The current value for the "Alt" field.
+ * @param {bool} settings.title_field
+ * Whether or not the "Title" field is enabled for this field.
+ * @param {bool} settings.title_field_required
+ * Whether or not the "Title" field is required for this field.
+ * @param {string} settings.title
+ * The current value for the "Title" field.
+ *
+ * @return {string}
+ * The corresponding HTML.
+ */
+ Drupal.theme.quickeditImageToolbar = _.template(
+ ''
+ );
+
Drupal.quickedit.editors.image = Drupal.quickedit.EditorView.extend(/** @lends Drupal.quickedit.editors.image# */{
/**
@@ -15,7 +86,7 @@
* @augments Drupal.quickedit.EditorView
*
* @param {object} options
- * Options for the plain text editor.
+ * Options for the image editor.
*/
initialize: function (options) {
Drupal.quickedit.EditorView.prototype.initialize.call(this, options);
@@ -37,41 +108,6 @@
},
/**
- * Template to display errors inline with the toolbar.
- */
- template_errors: _.template(
- '' +
- ' <%= errors %>' +
- '
'
- ),
-
- /**
- * Template to display the dropzone area.
- */
- template_dropzone: _.template(
- '' +
- ' ' +
- ' <%- text %>' +
- '
'
- ),
-
- /**
- * Template to display the toolbar.
- */
- template_toolbar: _.template(
- ''
- ),
-
- /**
* @inheritdoc
*
* @param {Drupal.quickedit.FieldModel} fieldModel
@@ -136,11 +172,11 @@
$(this).removeClass('hover');
});
- $dropzone.on('drop', function (e){
+ $dropzone.on('drop', function (e) {
stopEvent(e);
// Only respond when a file is dropped (could be another element).
- if(e.originalEvent.dataTransfer && e.originalEvent.dataTransfer.files.length){
+ if(e.originalEvent.dataTransfer && e.originalEvent.dataTransfer.files.length) {
$(this).removeClass('hover');
self.uploadImage(e.originalEvent.dataTransfer.files[0]);
}
@@ -167,7 +203,6 @@
this.removeValidationErrors();
}
- // Before we submit, validate the alt/title text fields.
this.save(options);
break;
@@ -223,10 +258,10 @@
* In addition to formatting the correct request, this also handles error
* codes and messages by displaying them visually inline with the image.
*
- * Drupal.ajax is not called here as the Form API is unused by this editor,
- * and our JSON requests/responses try to be editor-agnostic. Ideally
- * similar logic and routes could be used by modules like CKEditor for
- * drag+drop file uploads as well.
+ * Drupal.ajax is not called here as the Form API is unused by this
+ * in-place editor, and our JSON requests/responses try to be editor
+ * agnostic. Ideally similar logic and routes could be used by modules
+ * like CKEditor for drag+drop file uploads as well.
*
* @param {string} type
* The type of request (i.e. GET, POST, PUT, DELETE, etc.)
@@ -247,7 +282,7 @@
cache: false,
contentType: false,
processData: false,
- success: function(response) {
+ success: function (response) {
if (response.main_error) {
this.renderDropzone('error', response.main_error);
if (response.errors.length) {
@@ -259,7 +294,7 @@
callback(response);
}
},
- error: function() {
+ error: function () {
this.renderDropzone('error', Drupal.t('A server error has occurred.'));
}
});
@@ -280,7 +315,7 @@
var url = Drupal.quickedit.util.buildUrl(fieldID, Drupal.url('quickedit/image/info/!entity_type/!id/!field_name/!langcode/!view_mode'));
var self = this;
self.ajax('GET', url, null, function (response) {
- $toolbar = $(self.template_toolbar(response));
+ $toolbar = $(Drupal.theme.quickeditImageToolbar(response));
$toolgroup.append($toolbar);
$toolbar.on('keyup paste', function () {
fieldModel.set('state', 'changed');
@@ -308,7 +343,7 @@
$dropzone.children('.quickedit-image-text').html(text);
}
else {
- $dropzone = $(this.template_dropzone({
+ $dropzone = $(Drupal.theme.quickeditImageDropzone({
state: state,
text: text
}));
@@ -336,7 +371,7 @@
* @inheritdoc
*/
showValidationErrors: function () {
- var $errors = $(this.template_errors({
+ var $errors = $(Drupal.theme.quickeditImageErrors({
errors: this.model.get('validationErrors')
}));
$('#' + this.fieldModel.toolbarView.getMainWysiwygToolgroupId())
diff -u b/core/themes/stable/css/image/editors/image.css b/core/themes/stable/css/image/editors/image.css
--- b/core/themes/stable/css/image/editors/image.css
+++ b/core/themes/stable/css/image/editors/image.css
@@ -1,6 +1,11 @@
/**
* @file
- * Styles for the Image module's in-place editor.
+ * Functional styles for the Image module's in-place editor.
+ */
+
+/**
+ * A minimum width/height is required so that users can drag and drop files
+ * onto small images.
*/
.quickedit-image-element {
min-width: 200px;
@@ -10,106 +15,38 @@
.quickedit-image-dropzone {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- background: rgba(116, 183, 255, 0.8);
- transition: background .2s;
-}
-
-.quickedit-image-dropzone.hover {
- background: rgba(116, 183, 255, 0.9);
-}
-
-.quickedit-image-dropzone.error {
- background: rgba(255, 52, 27, 0.81);
-}
-
-.quickedit-image-dropzone * {
- pointer-events: none;
}
.quickedit-image-icon {
display: block;
width: 50px;
height: 50px;
- margin: 0 0 10px 0;
background-repeat: no-repeat;
background-size: cover;
- transition: margin .5s;
-}
-
-.quickedit-image-dropzone.upload .quickedit-image-icon {
- background-image: url('../../../images/image/upload.svg');
-}
-
-.quickedit-image-dropzone.error .quickedit-image-icon {
- background-image: url('../../../images/image/error.svg');
-}
-
-.quickedit-image-dropzone.loading .quickedit-image-icon {
- margin: -10px 0 20px 0;
-}
-
-.quickedit-image-dropzone.loading .quickedit-image-icon::after {
- display: block;
- content: "";
- margin-left: -10px;
- margin-top: -5px;
- animation-duration: 2s;
- animation-name: quickedit-image-spin;
- animation-iteration-count: infinite;
- animation-timing-function: linear;
- width: 60px;
- height: 60px;
- border-style: solid;
- border-radius: 35px;
- border-width: 5px;
- border-color: white transparent transparent transparent;
-}
-
-@keyframes quickedit-image-spin {
- 0% {transform: rotate(0deg);}
- 50% {transform: rotate(180deg);}
- 100% {transform: rotate(360deg);}
-}
-
-.quickedit-image-text {
- display: block;
- text-align: center;
- color: white;
- font-family: "Droid sans", "Lucida Grande", sans-serif;
- pointer-events: none;
- font-size: 16px;
- -webkit-user-select: none;
}
.quickedit-image-field-info {
display: flex;
align-items: center;
justify-content: flex-end;
- background: rgba(0, 0, 0, 0.05);
- border-top: 1px solid #c5c5c5;
- padding: 5px;
}
-.quickedit-image-field-info label, .quickedit-image-field-info input {
- margin-right: 5px;
-}
-
-.quickedit-image-field-info input:last-child {
- margin-right: 0;
-}
-
-.quickedit-image-errors .messages__wrapper {
- margin: 0;
- padding: 0;
+.quickedit-image-text {
+ display: block;
}
-.quickedit-image-errors .messages--error {
- box-shadow: none;
+/**
+ * If we do not prevent pointer-events for child elements, our drag+drop events
+ * will not fire properly. This can lead to unintentional redirects if a file
+ * is dropped on a child element when a user intended to upload it.
+ */
+.quickedit-image-dropzone * {
+ pointer-events: none;
}
diff -u b/core/themes/stable/images/image/error.svg b/core/themes/stable/images/image/error.svg
--- b/core/themes/stable/images/image/error.svg
+++ b/core/themes/stable/images/image/error.svg
@@ -4 +4 @@
-
\ No newline at end of file
+
diff -u b/core/themes/stable/stable.info.yml b/core/themes/stable/stable.info.yml
--- b/core/themes/stable/stable.info.yml
+++ b/core/themes/stable/stable.info.yml
@@ -99,9 +99,11 @@
theme:
css/image.admin.css: css/image/image.admin.css
image/quickedit.inPlaceEditor.image:
- css:
- component:
- css/editors/image.css: css/image/editors/image.css
+ css:
+ component:
+ css/editors/image.css: css/image/editors/image.css
+ theme:
+ css/editors/image.theme.css: css/image/editors/image.theme.css
language/drupal.language.admin:
css:
only in patch2:
unchanged:
--- /dev/null
+++ b/core/modules/image/css/editors/image.theme.css
@@ -0,0 +1,88 @@
+/**
+ * @file
+ * Theme styles for the Image module's in-place editor.
+ */
+
+.quickedit-image-dropzone {
+ background: rgba(116, 183, 255, 0.8);
+ transition: background .2s;
+}
+
+.quickedit-image-icon {
+ margin: 0 0 10px 0;
+ transition: margin .5s;
+}
+
+.quickedit-image-dropzone.hover {
+ background: rgba(116, 183, 255, 0.9);
+}
+
+.quickedit-image-dropzone.error {
+ background: rgba(255, 52, 27, 0.81);
+}
+
+.quickedit-image-dropzone.upload .quickedit-image-icon {
+ background-image: url('../../images/upload.svg');
+}
+
+.quickedit-image-dropzone.error .quickedit-image-icon {
+ background-image: url('../../images/error.svg');
+}
+
+.quickedit-image-dropzone.loading .quickedit-image-icon {
+ margin: -10px 0 20px 0;
+}
+
+.quickedit-image-dropzone.loading .quickedit-image-icon::after {
+ display: block;
+ content: "";
+ margin-left: -10px;
+ margin-top: -5px;
+ animation-duration: 2s;
+ animation-name: quickedit-image-spin;
+ animation-iteration-count: infinite;
+ animation-timing-function: linear;
+ width: 60px;
+ height: 60px;
+ border-style: solid;
+ border-radius: 35px;
+ border-width: 5px;
+ border-color: white transparent transparent transparent;
+}
+
+@keyframes quickedit-image-spin {
+ 0% {transform: rotate(0deg);}
+ 50% {transform: rotate(180deg);}
+ 100% {transform: rotate(360deg);}
+}
+
+.quickedit-image-text {
+ text-align: center;
+ color: white;
+ font-family: "Droid sans", "Lucida Grande", sans-serif;
+ font-size: 16px;
+ -webkit-user-select: none;
+}
+
+.quickedit-image-field-info {
+ background: rgba(0, 0, 0, 0.05);
+ border-top: 1px solid #c5c5c5;
+ padding: 5px;
+}
+
+.quickedit-image-field-info label, .quickedit-image-field-info input {
+ margin-right: 5px;
+}
+
+.quickedit-image-field-info input:last-child {
+ margin-right: 0;
+}
+
+.quickedit-image-errors .messages__wrapper {
+ margin: 0;
+ padding: 0;
+}
+
+.quickedit-image-errors .messages--error {
+ box-shadow: none;
+}
only in patch2:
unchanged:
--- /dev/null
+++ b/core/themes/stable/css/image/editors/image.theme.css
@@ -0,0 +1,88 @@
+/**
+ * @file
+ * Theme styles for the Image module's in-place editor.
+ */
+
+.quickedit-image-dropzone {
+ background: rgba(116, 183, 255, 0.8);
+ transition: background .2s;
+}
+
+.quickedit-image-icon {
+ margin: 0 0 10px 0;
+ transition: margin .5s;
+}
+
+.quickedit-image-dropzone.hover {
+ background: rgba(116, 183, 255, 0.9);
+}
+
+.quickedit-image-dropzone.error {
+ background: rgba(255, 52, 27, 0.81);
+}
+
+.quickedit-image-dropzone.upload .quickedit-image-icon {
+ background-image: url('../../../images/image/upload.svg');
+}
+
+.quickedit-image-dropzone.error .quickedit-image-icon {
+ background-image: url('../../../images/image/error.svg');
+}
+
+.quickedit-image-dropzone.loading .quickedit-image-icon {
+ margin: -10px 0 20px 0;
+}
+
+.quickedit-image-dropzone.loading .quickedit-image-icon::after {
+ display: block;
+ content: "";
+ margin-left: -10px;
+ margin-top: -5px;
+ animation-duration: 2s;
+ animation-name: quickedit-image-spin;
+ animation-iteration-count: infinite;
+ animation-timing-function: linear;
+ width: 60px;
+ height: 60px;
+ border-style: solid;
+ border-radius: 35px;
+ border-width: 5px;
+ border-color: white transparent transparent transparent;
+}
+
+@keyframes quickedit-image-spin {
+ 0% {transform: rotate(0deg);}
+ 50% {transform: rotate(180deg);}
+ 100% {transform: rotate(360deg);}
+}
+
+.quickedit-image-text {
+ text-align: center;
+ color: white;
+ font-family: "Droid sans", "Lucida Grande", sans-serif;
+ font-size: 16px;
+ -webkit-user-select: none;
+}
+
+.quickedit-image-field-info {
+ background: rgba(0, 0, 0, 0.05);
+ border-top: 1px solid #c5c5c5;
+ padding: 5px;
+}
+
+.quickedit-image-field-info label, .quickedit-image-field-info input {
+ margin-right: 5px;
+}
+
+.quickedit-image-field-info input:last-child {
+ margin-right: 0;
+}
+
+.quickedit-image-errors .messages__wrapper {
+ margin: 0;
+ padding: 0;
+}
+
+.quickedit-image-errors .messages--error {
+ box-shadow: none;
+}