diff --git a/core/modules/file/file.module b/core/modules/file/file.module index 0e5b057..235d180 100644 --- a/core/modules/file/file.module +++ b/core/modules/file/file.module @@ -1255,6 +1255,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']; @@ -1275,6 +1277,29 @@ function template_preprocess_file_link(&$variables) { $variables['attributes']->addClass($classes); $variables['link'] = \Drupal::l($link_text, Url::fromUri($url, $options)); + +} + +/** + * Gets a class for the icon for a MIME type. + * + * @param string $mime_type + * A MIME type. + * + * @return string + * A class associated with the file. + */ +function file_shorten_filename($link_text) { + + $name = $link_text; + $ext = pathinfo($name, PATHINFO_EXTENSION); + $nameWoExt = chop($name, '.' . $ext); + + $nameStart = substr($nameWoExt, 0, 10); + $nameEnd = substr($nameWoExt, -4, 4); + $link_text = $nameStart . '....' . $nameEnd . '.' . $ext; + + return $link_text; } /** diff --git a/core/modules/file/src/Element/ManagedFile.php b/core/modules/file/src/Element/ManagedFile.php index 1b0984b..dec0786 100644 --- a/core/modules/file/src/Element/ManagedFile.php +++ b/core/modules/file/src/Element/ManagedFile.php @@ -238,7 +238,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']], @@ -255,6 +255,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 2fe5841..210238e 100644 --- a/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php +++ b/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php @@ -224,7 +224,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(), @@ -235,7 +235,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/themes/seven/css/components/dropzone.css b/core/themes/seven/css/components/dropzone.css new file mode 100644 index 0000000..067ccdd --- /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('../../images/dropzone-new.png') 0 center no-repeat; +} + +.dropzone .dropzone-trigger.is-hovering { + background: url('../../images/dropzone-new.png') -100px center no-repeat; +} + +.dropzone .dropzone-trigger.is-throbber.is-uploading { + background: none; +} +.dropzone .dropzone-trigger.is-uploading { + background: url('../../images/dropzone-new.png') -200px center no-repeat; +} + +.dropzone .dropzone-trigger.is-complete { + background: url('../../images/dropzone-new.png') -200px center no-repeat; +} + +.field--type-image .dropzone .dropzone-trigger.is-complete { + background: url('../../images/dropzone-new.png') -200px center no-repeat; +} + +.field--type-file .dropzone .dropzone-trigger.is-complete { + background: url('../../images/dropzone-new.png') -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; +} \ No newline at end of file diff --git a/core/themes/seven/images/dropzone-new.png b/core/themes/seven/images/dropzone-new.png new file mode 100644 index 0000000..0c069c8 --- /dev/null +++ b/core/themes/seven/images/dropzone-new.png @@ -0,0 +1,219 @@ +PNG + + IHDRdp} pHYs   +OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, +!{kּ> H3Q5 B.@ +$pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB +dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ +b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| +J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ +M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% +yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- +BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-@iTXtXML:com.adobe.xmp + + + + Adobe Photoshop CC 2015 (Windows) + 2016-02-25T13:39:17-08:00 + 2016-03-20T12:18:13-07:00 + 2016-03-20T12:18:13-07:00 + 3 + sRGB IEC61966-2.1 + + + xmp.did:203EE966C91E11E5A239B22E8DC3709D + xmp.did:A26AEC2CC91D11E5B33FB7CC67E672F6 + + + image/png + xmp.iid:b7704a5f-ba69-c944-9961-23d86bb6c0af + adobe:docid:photoshop:7669dbb6-eed0-11e5-86c8-92a1435356bc + xmp.did:ed0febdc-e0bd-4348-9325-6bc9c065c994 + + + + created + xmp.iid:ed0febdc-e0bd-4348-9325-6bc9c065c994 + 2016-02-25T13:39:17-08:00 + Adobe Photoshop CC 2015 (Windows) + + + saved + xmp.iid:14f256c7-4ba9-fe4a-92d0-843b821df19e + 2016-03-20T12:18:13-07:00 + Adobe Photoshop CC 2015 (Windows) + / + + + converted + from application/vnd.adobe.photoshop to image/png + + + derived + converted from application/vnd.adobe.photoshop to image/png + + + saved + xmp.iid:b7704a5f-ba69-c944-9961-23d86bb6c0af + 2016-03-20T12:18:13-07:00 + Adobe Photoshop CC 2015 (Windows) + / + + + + + xmp.iid:14f256c7-4ba9-fe4a-92d0-843b821df19e + xmp.did:ed0febdc-e0bd-4348-9325-6bc9c065c994 + xmp.did:ed0febdc-e0bd-4348-9325-6bc9c065c994 + + 1 + 720000/10000 + 720000/10000 + 2 + 1 + 500 + 100 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +v cHRMz%u0`:o_FIDATx]\w4eFUToI*nz[PHFi 5lMA%G ShIЖ^Z *IEtz1fw< g9{{3y;;sT l1(t@B: +PB:(t@v߿ogܛ$'hɏIe5%]~e-YHr8$Yqv։y]]dK8<_+I6<$M_z'L-JhL?dy~?II^wն7|PYۓllq'6Zx,O%ٖ= $7vs=_HwWITi8e (VfQMFK$tЗtj|mmxsI%h ̤I <:CnΔJGuЈBߝׄ*@/˖PVA +}YPVA +PB:(tVD@7ׁ%K0v:tP3<1\Hrg,&-'$G=7'vrPڞ$?3;.҉9Oxt~mInJ~,oNbtk§:Gz,ɣ"ڜ$.Pt!'Ay-K&my\kBkk7O2d6v/@vKy3+|^'15S^nIn3 {Nr"ɞ +wey֜uRP苶=>$y2~=9-z}B?ſ9>dgKlBe:h,$fz6ɕc鞎\~cwfMpGoIK$cfB_=:@ +,Y"[k6dCC9}\/t5zc`E2<9&z]S-`l5$ e`,ʅ: PBo${yL o>L ipP }zxz1ʯ͔e-$n:$'6Ho-sys|XY|{:ɋoY!w*g =F=y<3A-CYy(t@ +PYC \,9lHrP3<1\Hh] l<15$ eRrU.AfBz%[`"|mmxIf&p3
 
'); + if (this.progress.message) { + this.progress.element.find('.throbber').after('
' + this.progress.message + '
'); + } + + // 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); + + //if($(this.element).hasClass('upload-button')) { + // console.log('uploaded'); + //} else if($(this.element).hasClass('remove-button')) { + // console.log('removed'); + //} + + }; + + Drupal.Ajax.prototype.success = function (response, status) { + + // 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
element. + var elementParents = $(this.element).parents('[data-drupal-selector]').addBack().toArray(); + + // Track if any command is altering the focus so we can avoid changing the + // focus set by the Ajax command. + var focusChanged = false; + for (var i in response) { + if (response.hasOwnProperty(i) && response[i].command && this.commands[response[i].command]) { + this.commands[response[i].command](this, response[i], status); + if (response[i].command === 'invoke' && response[i].method === 'focus') { + focusChanged = true; + } + } + } + + // If the focus hasn't be changed by the ajax commands, try to refocus the + // triggering element or one of its parents if that element does not exist + // anymore. + if (!focusChanged && this.element && !$(this.element).data('disable-refocus')) { + var target = false; + + for (var n = elementParents.length - 1; !target && n > 0; n--) { + target = document.querySelector('[data-drupal-selector="' + elementParents[n].getAttribute('data-drupal-selector') + '"]'); + } + + if (target) { + $(target).trigger('focus'); + } + } + + if($(this.element).hasClass('upload-button')) { + //console.log('uploaded'); + $(target).find('.dropzone-trigger').addClass('is-complete'); + } else if($(this.element).hasClass('remove-button')) { + //console.log('removed'); + } + + // Reattach behaviors, if they were detached in beforeSerialize(). The + // attachBehaviors() called on the new content from processing the response + // commands is not sufficient, because behaviors from the entire form need + // to be reattached. + if (this.$form) { + var settings = this.settings || drupalSettings; + Drupal.attachBehaviors(this.$form.get(0), settings); + } + + // move the throbber to the dropzone trigger + if($(target).find('.image-preview').length) { + var dropzone = $(target).find('.dropzone').find('.dropzone-trigger'); + $(target).find('.image-preview').appendTo(dropzone); + } + + // Remove any response-specific settings so they don't get used on the next + // call by mistake. + this.settings = null; + + }; + + } + +})(jQuery, Drupal); + + + diff --git a/core/themes/seven/seven.libraries.yml b/core/themes/seven/seven.libraries.yml index a5b6d8a..bf1c2af 100644 --- a/core/themes/seven/seven.libraries.yml +++ b/core/themes/seven/seven.libraries.yml @@ -13,6 +13,7 @@ global-styling: css/components/colors.css: {} css/components/messages.css: {} css/components/dropbutton.component.css: {} + css/components/dropzone.css: {} css/components/entity-meta.css: {} css/components/field-ui.css: {} css/components/form.css: {} @@ -32,7 +33,11 @@ global-styling: css/components/views-ui.css: {} layout: css/layout/layout.css: {} + js: + js/dropzone.js: {} dependencies: + - core/drupal.ajax + - core/drupal.progress - system/admin node-form: diff --git a/core/themes/seven/seven.theme b/core/themes/seven/seven.theme index 9afa603..5f0278d 100644 --- a/core/themes/seven/seven.theme +++ b/core/themes/seven/seven.theme @@ -186,3 +186,10 @@ function seven_form_node_form_alter(&$form, FormStateInterface $form_state) { $form['revision_information']['#type'] = 'container'; $form['revision_information']['#group'] = 'meta'; } + +/** + * Implements hook_theme_suggestions_form_element_alter(). + */ +function seven_theme_suggestions_form_element_alter(&$suggestions, $variables) { + $suggestions[] = 'form_element__' . $variables['element']['#type']; +} diff --git a/core/themes/seven/templates/form-element--managed-file.html.twig b/core/themes/seven/templates/form-element--managed-file.html.twig new file mode 100644 index 0000000..0a4792f --- /dev/null +++ b/core/themes/seven/templates/form-element--managed-file.html.twig @@ -0,0 +1,105 @@ +{# +/** + * @file + * Theme override for a managed file form element. + * + * Available variables: + * - attributes: HTML attributes for the containing element. + * - errors: (optional) Any errors for this form element, may not be set. + * - prefix: (optional) The form element prefix, may not be set. + * - suffix: (optional) The form element suffix, may not be set. + * - required: The required marker, or empty if the associated form element is + * not required. + * - type: The type of the element. + * - name: The name of the element. + * - label: A rendered label element. + * - label_display: Label display setting. It can have these values: + * - before: The label is output before the element. This is the default. + * The label includes the #title and the required marker, if #required. + * - after: The label is output after the element. For example, this is used + * for radio and checkbox #type elements. If the #title is empty but the + * field is #required, the label will contain only the required marker. + * - invisible: Labels are critical for screen readers to enable them to + * properly navigate through forms but can be visually distracting. This + * property hides the label for everyone except screen readers. + * - attribute: Set the title attribute on the element to create a tooltip but + * output no label element. This is supported only for checkboxes and radios + * in \Drupal\Core\Render\Element\CompositeFormElementTrait::preRenderCompositeFormElement(). + * It is used where a visual label is not needed, such as a table of + * checkboxes where the row and column provide the context. The tooltip will + * include the title and required marker. + * - description: (optional) A list of description properties containing: + * - content: A description of the form element, may not be set. + * - attributes: (optional) A list of HTML attributes to apply to the + * description content wrapper. Will only be set when description is set. + * - description_display: Description display setting. It can have these values: + * - before: The description is output before the element. + * - after: The description is output after the element. This is the default + * value. + * - invisible: The description is output after the element, hidden visually + * but available to screen readers. + * - disabled: True if the element is disabled. + * - title_display: Title display setting. + * + * @see template_preprocess_form_element() + */ +#} +{% +set classes = [ +'js-form-item', +'form-item', +'js-form-type-' ~ type|clean_class, +'form-type-' ~ type|clean_class, +'js-form-item-' ~ name|clean_class, +'form-item-' ~ name|clean_class, +'dropzone-wrapper', +'clearfix', +disabled == 'disabled' ? 'form-disabled', +errors ? 'form-item--error', +] +%} +{% +set description_classes = [ +'dropzone-description', +description_display == 'invisible' ? 'visually-hidden', +] +%} + +{#{{ kint(children) }}#} + +{# @todo: is this being used? #} +{#{% if errors %}#} + {#
#} + {#{{ errors }}#} + {#
#} +{#{% endif %}#} + + + {% if prefix is not empty %} + {{ prefix }} + {% endif %} +
+
+ + {{ children }} + + {% if suffix is not empty %} + {{ suffix }} + {% endif %} + {% if label_display == 'after' %} + {{ label }} + {% endif %} + + {% if description.content %} + + + {{ description.content }} +
+ {% endif %} + + + + diff --git a/core/themes/seven/templates/image-widget.html.twig b/core/themes/seven/templates/image-widget.html.twig new file mode 100644 index 0000000..5a2d8a1 --- /dev/null +++ b/core/themes/seven/templates/image-widget.html.twig @@ -0,0 +1,27 @@ +{# +/** + * @file + * Theme override for an image field widget. + * + * Available variables: + * - attributes: HTML attributes for the containing element. + * - data: Render elements of the image widget. + * + * @see template_preprocess_image_widget() + */ +#} + +{{ attach_library('classy/image-widget') }} + + {% if data.preview %} +
+ {{ data.preview }} +
+ {% endif %} +
+ + {# Render widget data without the image preview that was output already. #} + {{ data|without('preview') }} + +
+