diff --git a/core/misc/icons/bebebe/dropzone-new.svg b/core/misc/icons/bebebe/dropzone-new.svg new file mode 100644 index 0000000..b3b8e49 --- /dev/null +++ b/core/misc/icons/bebebe/dropzone-new.svg @@ -0,0 +1,13 @@ + diff --git a/core/modules/file/file.module b/core/modules/file/file.module index 687a62c..bc41504 100644 --- a/core/modules/file/file.module +++ b/core/modules/file/file.module @@ -1263,6 +1263,8 @@ function template_preprocess_file_link(&$variables) { // Use the description as the link text if available. if (empty($variables['description'])) { $link_text = $file_entity->getFilename(); + $link_text = file_shorten_filename($link_text); + $options['attributes']['title'] = $file_entity->getFilename(); } else { $link_text = $variables['description']; @@ -1286,6 +1288,31 @@ function template_preprocess_file_link(&$variables) { } /** + * Shortens a file name. + * + * @param string $filename + * The filename to shorten. + * @param int $limit + * (optional) The maximum length of the filename (without the extension) that + * will not be shortened. + * + * @return string + * The shortened filename, or the original filename if it's less than $limit + * characters long. + */ +function file_shorten_filename($filename, $limit = 10) { + $ext = pathinfo($filename, PATHINFO_EXTENSION); + + $name = pathinfo($filename, PATHINFO_FILENAME); + if (strlen($name) > $limit) { + return substr($name, 0, $limit) . '...' . substr($name, -4) . '.' . $ext; + } + else { + return $filename; + } +} + +/** * Gets a class for the icon for a MIME type. * * @param string $mime_type diff --git a/core/modules/file/src/Element/ManagedFile.php b/core/modules/file/src/Element/ManagedFile.php index f465b18..a784757 100644 --- a/core/modules/file/src/Element/ManagedFile.php +++ b/core/modules/file/src/Element/ManagedFile.php @@ -239,7 +239,7 @@ public static function processManagedFile(&$element, FormStateInterface $form_st '#name' => $parents_prefix . '_upload_button', '#type' => 'submit', '#value' => t('Upload'), - '#attributes' => ['class' => ['js-hide']], + '#attributes' => ['class' => ['upload-button', 'js-hide']], '#validate' => [], '#submit' => ['file_managed_file_submit'], '#limit_validation_errors' => [$element['#parents']], @@ -256,6 +256,7 @@ public static function processManagedFile(&$element, FormStateInterface $form_st '#name' => $parents_prefix . '_remove_button', '#type' => 'submit', '#value' => $element['#multiple'] ? t('Remove selected') : t('Remove'), + '#attributes' => ['class' => ['remove-button']], '#validate' => [], '#submit' => ['file_managed_file_submit'], '#limit_validation_errors' => [$element['#parents']], diff --git a/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php b/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php index f881419..03032f3 100644 --- a/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php +++ b/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php @@ -227,7 +227,7 @@ public static function process($element, FormStateInterface $form_state, $form) '#description' => t('This text will be used by screen readers, search engines, or when the image cannot be loaded.'), // @see https://www.drupal.org/node/465106#alt-text '#maxlength' => 512, - '#weight' => -12, + '#weight' => 1, '#access' => (bool) $item['fids'] && $element['#alt_field'], '#required' => $element['#alt_field_required'], '#element_validate' => $element['#alt_field_required'] == 1 ? array(array(get_called_class(), 'validateRequiredFields')) : array(), @@ -238,7 +238,7 @@ public static function process($element, FormStateInterface $form_state, $form) '#default_value' => isset($item['title']) ? $item['title'] : '', '#description' => t('The title is used as a tool tip when the user hovers the mouse over the image.'), '#maxlength' => 1024, - '#weight' => -11, + '#weight' => 2, '#access' => (bool) $item['fids'] && $element['#title_field'], '#required' => $element['#title_field_required'], '#element_validate' => $element['#title_field_required'] == 1 ? array(array(get_called_class(), 'validateRequiredFields')) : array(), diff --git a/core/modules/system/src/Tests/Update/UpdatePathRC1TestBaseFilledTest.php b/core/modules/system/src/Tests/Update/UpdatePathRC1TestBaseFilledTest.php index eb95fce..e65a613 100644 --- a/core/modules/system/src/Tests/Update/UpdatePathRC1TestBaseFilledTest.php +++ b/core/modules/system/src/Tests/Update/UpdatePathRC1TestBaseFilledTest.php @@ -112,7 +112,8 @@ public function testUpdatedSite() { $this->assertRaw('+31612345679'); $this->assertText('Test Article - New title'); $this->assertText('test.txt'); - $this->assertText('druplicon.small'); + // The full-length file name is druplicon.small_.png. + $this->assertText('druplicon....all_.png'); $this->assertRaw('General discussion'); $this->assertText('Test Article - New title'); $this->assertText('Test 1'); diff --git a/core/modules/system/src/Tests/Update/UpdatePathTestBaseFilledTest.php b/core/modules/system/src/Tests/Update/UpdatePathTestBaseFilledTest.php index 6edbfe3..a071fae 100644 --- a/core/modules/system/src/Tests/Update/UpdatePathTestBaseFilledTest.php +++ b/core/modules/system/src/Tests/Update/UpdatePathTestBaseFilledTest.php @@ -112,7 +112,8 @@ public function testUpdatedSite() { $this->assertRaw('+31612345679'); $this->assertText('Test Article - New title'); $this->assertText('test.txt'); - $this->assertText('druplicon.small'); + // The full-length file name is druplicon.small_.png. + $this->assertText('druplicon....all_.png'); $this->assertRaw('General discussion'); $this->assertText('Test Article - New title'); $this->assertText('Test 1'); diff --git a/core/themes/seven/css/components/dropzone.css b/core/themes/seven/css/components/dropzone.css new file mode 100644 index 0000000..7b16f00 --- /dev/null +++ b/core/themes/seven/css/components/dropzone.css @@ -0,0 +1,105 @@ +/** + * Dropzone. + */ +.dropzone-wrapper { + width: 100%; + border: 1px solid #bfbfbf; + border-radius: 2px; + background: #fcfcfa; +} + +.dropzone { + position: relative; + width: 100%; + height: 100%; + min-height: 100px; + display: table; +} + +.dropzone > div { + display: table-cell; + vertical-align: middle; +} + +/* hide error message*/ +.dropzone .messages--error { display: none; } + +/* form file */ +.dropzone .js-form-file { + position: absolute; + left: 0; + top: 0; + cursor: pointer; + min-height: 100px; + width: 100px; + display: inline-block; + opacity: 0; +} + +.dropzone .file { + background: none; + padding: 0; +} + +.dropzone .dropzone-trigger { + position: relative; + text-align: center; + min-height: 100px; + height: 100%; + width: 100px; + border-right: 1px solid #bfbfbf; +} + +.dropzone .dropzone-trigger { + background: url('../../../../misc/icons/bebebe/dropzone-new.svg') 0 center no-repeat; +} + +.dropzone .dropzone-trigger.is-hovering { + background: url('../../../../misc/icons/bebebe/dropzone-new.svg') -100px center no-repeat; +} + +.dropzone .dropzone-trigger.is-throbber.is-uploading { + background: none; +} +.dropzone .dropzone-trigger.is-uploading { + background: url('../../../../misc/icons/bebebe/dropzone-new.svg') -200px center no-repeat; +} + +.dropzone .dropzone-trigger.is-complete { + background: url('../../../../misc/icons/bebebe/dropzone-new.svg') -200px center no-repeat; +} + +.field--type-image .dropzone .dropzone-trigger.is-complete { + background: url('../../../../misc/icons/bebebe/dropzone-new.svg') -200px center no-repeat; +} + +.field--type-file .dropzone .dropzone-trigger.is-complete { + background: url('../../../../misc/icons/bebebe/dropzone-new.svg') -200px center no-repeat; +} + + +.dropzone-description { + padding: 10px; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + display: table-cell; +} + +.dropzone-preview { + border: 1px solid #ccc; + border-radius: 2px; + background: #fdfdfc; + margin-bottom: 1em; padding: 0.5em 1em; +} + +.dropzone-buttons { + padding: 0; + margin: 0; + list-style: none; +} + +.dropzone-buttons li { + display: inline-block; + margin-right: 10px; +} diff --git a/core/themes/seven/js/dropzone.js b/core/themes/seven/js/dropzone.js new file mode 100644 index 0000000..8c7f8b7 --- /dev/null +++ b/core/themes/seven/js/dropzone.js @@ -0,0 +1,109 @@ +(function ($, Drupal) { + + 'use strict'; + + Drupal.behaviors.dropzone = { + attach: function (context, settings) { + $(context).find('.js-form-file') + .on('dragover dragleave mouseenter mouseleave', function () { + $(this).closest('.dropzone').find('.dropzone-trigger').toggleClass('is-hovering'); + }); + + Drupal.ajax.instances + .filter(function (instance) { + return instance.element.length > 0 && instance.element.hasClass('upload-button') && instance.element.once('magic').length > 0; + }) + .forEach(function (instance) { + instance.setProgressIndicatorThrobber = function () { + // Avoid code repetition. + this.prototype.setProgressIndicatorThrobber(); + // Undo the .after() call in the prototype method. + $(this.element).nextAll().remove(); + + // Move the throbber to the dropzone trigger. + var dropzone = $(this.element).closest('.dropzone').find('.dropzone-trigger'); + $(this.element).closest('.dropzone').find('.dropzone-trigger').removeClass('is-complete').addClass('is-throbber is-uploading'); + $(this.progress.element).appendTo(dropzone); + }; + + instance.success = function () { + // Remove the progress element. + if (this.progress.element) { + $(this.progress.element).remove(); + } + if (this.progress.object) { + this.progress.object.stopMonitoring(); + } + $(this.element).prop('disabled', false); + + // Save element's ancestors tree so if the element is removed from the dom + // we can try to refocus one of its parents. Using addBack reverse the + // result array, meaning that index 0 is the highest parent in the hierarchy + // in this situation it is usually a