Skip to content
Snippets Groups Projects
Commit 1d402fc3 authored by Salvador Molina's avatar Salvador Molina
Browse files

First D8 version. Support for standard entity fields via config

parent ba6ce37a
No related branches found
No related tags found
No related merge requests found
Soft Length Limit
This module provides a counter that indicates the max. limit of
characters in a certain text field. The soft limit means that the user
will be warned if the content length of the field is exceeded, but he
will still be able to save all data in the field.
This module provides a counter that indicates the maximum recommended
characters in a certain text field. This means the user will be warned if the
content length of the field is exceeded, but will still be able to pass content
validation and be persisted in the relevant storage.
This module adds the following features:
It basically does two things:
* Lets the user configure any instance of a text field's widget, to
have a specific soft limit. This is done in the usual field settings
for entity types. This counter will always be shown on fields with a
soft limit, no matter the settings mentioned below.
* Adds a character countdown to form elements that already have a
maxlength specified. This functionality can be customized through
the options specified below.
-- Configuration of behavior of elements with "maxlength" attribute --
The following Drupal variables can be set to change the criteria for
which elements should have the limit counter:
* (bool) soft_length_limit_maxlength_counter_disabled:
If set to TRUE, no fields with maxlength attribute will have a counter.
* (bool) soft_length_limit_maxlength_counter_admin_only:
If set to TRUE, the counter will only be shown when the admin_theme is
active.
* (Array) soft_length_limit_maxlength_counter_themes:
This as an array of theme names for which the counter should be
shown. If empty, all themes show the counter.
* (Array) soft_limit_length_maxlength_exclude_selectors:
This is an array of jQuery selectors (using classes, IDs etc.) for
elements which should be excluded from having a counter, although they
have a defined maxlength, i.e. date fields, autocomplete fields
etc. could be added here.
* The icons for this came from Creative Commons Attribution 3.0
Unported License, and they came from http://icomoon.io/#icons free
package.
* Lets the user configure any instance of a text field's widget, to have a
specific soft limit. This is done in the "Manage Form Display" page of the
relevant entity type. This counter will always be shown on fields with a soft
limit.
field.widget.third_party.soft_length_limit:
type: mapping
label: 'soft_length_limit settings'
mapping:
max_limit:
type: integer
minimum_limit:
type: integer
style_select:
type: boolean
.soft-length-limit-tooltip {
div.soft-length-limit-tooltip.description {
display: inline-block;
font-style: italic;
position: absolute;
position: relative;
margin-top: 1em;
z-index: 10;
}
.form-item div.soft-length-limit-tooltip.exceeded {
.form-item div.soft-length-limit-tooltip.exceeded,
.form-item div.soft-length-limit-tooltip.under-min {
color: #a44;
}
/* Min/Enhanced tooltip */
.fieldset-wrapper .form-item .soft-length-limit-tooltip.min-style-tooltip,
.field-type-text .form-item .soft-length-limit-tooltip.min-style-tooltip {
.field-type-text .form-item .soft-length-limit-tooltip.min-style-tooltip,
.form-item.form-type-textfield .soft-length-limit-tooltip.min-style-tooltip,
.form-item.form-type-textarea .soft-length-limit-tooltip.min-style-tooltip {
background-color: transparent;
background-image: url(ico_socpub_confirm.png);
background-image: url(../img/ico_socpub_confirm.png);
background-position: left top;
background-repeat: no-repeat;
background-size: 15px 15px;
left: auto !important;
padding: 0 0 0 20px;
}
.fieldset-wrapper .form-item .soft-length-limit-tooltip.min-style-tooltip,
.field-type-text .form-item .soft-length-limit-tooltip.min-style-tooltip {
right: 10px;
}
.fieldset-wrapper .form-item .soft-length-limit-tooltip.min-style-tooltip.exceeded.under-min,
.field-type-text .form-item .soft-length-limit-tooltip.min-style-tooltip.exceeded.under-min {
background-image: none;
.form-item.form-type-textfield .soft-length-limit-tooltip.min-style-tooltip {
margin-left: 5px;
}
.fieldset-wrapper .form-item .soft-length-limit-tooltip.min-style-tooltip.under-min,
.form-item.form-type-textfield .soft-length-limit-tooltip.min-style-tooltip.under-min,
.field-type-text .form-item .soft-length-limit-tooltip.min-style-tooltip.under-min,
.form-item.form-type-textarea .soft-length-limit-tooltip.min-style-tooltip.under-min {
background-image: url(../img/ico_socpub_alert.png);
}
.fieldset-wrapper .form-item .soft-length-limit-tooltip.min-style-tooltip.exceeded,
.field-type-text .form-item .soft-length-limit-tooltip.min-style-tooltip.exceeded {
background-image: url(ico_socpub_alert.png);
.form-item.form-type-textfield .soft-length-limit-tooltip.min-style-tooltip.exceeded,
.field-type-text .form-item .soft-length-limit-tooltip.min-style-tooltip.exceeded,
.form-item.form-type-textarea .soft-length-limit-tooltip.min-style-tooltip.exceeded {
background-image: url(../img/ico_socpub_alert.png);
}
File moved
File moved
File moved
(function ($) {
var sll = sll || {};
Drupal.behaviors.softLengthLimit = {
attach: function (context, settings) {
// Preparing the input elements by adding a tooltip container.
$('.soft-length-limit:not(.soft-length-limit-processed)').each(function(index) {
$(this).addClass('soft-length-limit-processed');
var $parent = $(this).parent();
$parent.css('position','relative');
$parent.append('<div class="soft-length-limit-tooltip description"></div>');
$element = $(this);
});
var $softLengthElement = $('.soft-length-limit');
// Calculates the correct position of the tooltip and shows it.
$softLengthElement.focus(function(event){
var $tooltip = $(this).parent().find('.soft-length-limit-tooltip');
$(this).trigger('textchange', $(this).val());
$tooltip.fadeIn('fast');
});
// Hides the tooltip.
$softLengthElement.blur(function(event){
var $tooltip = $(this).parent().find('.soft-length-limit-tooltip');
$tooltip.fadeOut('fast');
});
// Shows the relevant info to the user in the tooltip.
$softLengthElement.bind('textchange', sll.refreshTooltip);
}
};
sll.refreshTooltip = function(event, prevText) {
let limit = $(this).attr('data-soft-length-limit');
let minimum = $(this).attr('data-soft-length-minimum');
let val = $(this).val();
let remaining = limit - val.length;
let $tooltip = $(this).parent().find('.soft-length-limit-tooltip');
let styleSelect = $(this).attr('data-soft-length-style-select');
// Removes the "exceeded" class if length is not exceeded.
if (prevText.length > limit && val.length <= limit) {
$tooltip.removeClass('exceeded');
$(this).removeClass('exceeded');
}
// Adds the "exceeded" class if length is exceeded.
if (val.length > limit && !$tooltip.hasClass('exceeded')) {
$tooltip.addClass('exceeded');
$(this).addClass('exceeded');
}
// Adds the "exceeded" class if the length is less than the minimum, in the case where the minimum is set.
// Adds the "under-min" class, for under-character-minimum specific behavior. Used for min/enhanced character count.
if (minimum > 0) {
if (val.length < minimum) {
$tooltip.addClass('under-min');
$(this).addClass('under-min');
}
if (val.length >= minimum) {
$tooltip.removeClass('under-min');
$(this).removeClass('under-min');
}
if (val.length > limit) {
$tooltip.addClass('exceeded');
$(this).addClass('exceeded');
}
if (val.length <= limit) {
$tooltip.removeClass('exceeded');
$(this).removeClass('exceeded');
}
}
// The minimal / enhanced version of character limits.
if (styleSelect === '1') {
// No minimum treatment.
$tooltip.html(Drupal.t('@val/@limit', {
'@val': val.length,
'@limit': limit
}));
// Add class to tooltip for different CSS treatment (icons, text alignment, etc).
$tooltip.parent().children('.soft-length-limit-tooltip').addClass('min-style-tooltip');
}
// Original character limit treatment.
if ((styleSelect === '0') || (styleSelect === undefined)) {
// No minimum value is set.
if (minimum < 1) {
if (val.length === 0) {
$tooltip.html(Drupal.t('Content limited to @limit characters',{
'@limit': limit
}));
}
else if (remaining < 0) {
$tooltip.html(Drupal.t('@limit character limit exceeded by @exceed characters.',{
'@limit': limit,
'@exceed': -remaining
}));
}
else {
$tooltip.html(Drupal.t('Content limited to @limit characters. Remaining: @remaining',{
'@limit': limit,
'@remaining': remaining
}));
}
}
// There is a minimum length set.
else {
if (val.length === 0) {
$tooltip.html(Drupal.t('Suggested minimum number of characters is @minimum, current count is @val. Content limited to @limit characters. ',{
'@limit': limit,
'@minimum': minimum,
'@val': val.length
}));
}
else if (remaining < 0) {
$tooltip.html(Drupal.t('Suggested minimum number of characters is @minimum, current count is @val. @limit character limit exceeded by @exceed characters.',{
'@limit': limit,
'@exceed': -remaining,
'@minimum': minimum,
'@val': val.length
}));
}
else {
$tooltip.html(Drupal.t('Suggested minimum number of characters is @minimum, current count is @val. Content limited to @limit characters. Remaining: @remaining.',{
'@limit': limit,
'@remaining': remaining,
'@minimum': minimum,
'@val': val.length
}));
}
}
}
};
})(jQuery);
name = Soft length limit
description = Makes a soft limit on the number of chars in text fields, which warns the user of too long texts
core = 7.x
files[] = soft_length_limit.test
name: Soft Length Limit
type: module
description: Soft limits number of chars in text fields, warning the user of too long texts
package: Fields
core: 8.x
<?php
/**
* @file
* Install/uninstall hooks for soft_length_limits module.
*/
/**
* Implements hook_uninstall().
*
* Deletes variables defined by the module.
*/
function soft_length_limit_uninstall() {
db_delete('variable')
->condition('name', "soft_length_limit_%", "LIKE")
->execute();
cache_clear_all('variables', 'cache_bootstrap');
}
(function ($) {
Drupal.behaviors.softLengthLimit = {
attach: function (context, settings) {
// Preparing the input elements by adding a tooltip container.
$('.soft-length-limit:not(.soft-length-limit-processed)').each(function(index){
$(this).addClass('soft-length-limit-processed');
var $parent = $(this).parent();
$parent.css('position','relative');
$parent.append('<div class="soft-length-limit-tooltip description"></div>');
$element = $(this);
// Used for automatically moving the tooltip when resizing the
// text area.
$parent.find('.grippie').mousedown({
element: $(this)
}, function(event){
var endDrag = function(event) {
event.data.element.focus();
$(document).unbind('mouseup',endDrag);
};
$(document).mouseup(event.data,endDrag);
});
});
// Calculates the correct position of the tooltip and shows it.
$('.soft-length-limit').focus(function(event){
var $tooltip = $(this).parent().find('.soft-length-limit-tooltip');
var left = $(this).position().left;
var top = $(this).position().top;
var bottom = top + $(this).outerHeight(true);
var right = left + $(this).outerWidth(true);
$(this).trigger('textchange', $(this).val());
if ($(this).get(0).tagName == "TEXTAREA") {
$tooltip.css('left', 10).css('top', bottom + 5);
}
else {
$tooltip.css('left', 10).css('top', bottom - 4);
}
$tooltip.fadeIn('fast');
});
// Hides the tooltip.
$('.soft-length-limit').blur(function(event){
var $tooltip = $(this).parent().find('.soft-length-limit-tooltip');
$tooltip.fadeOut('fast');
});
// Shows the relevant info to the user in the tooltip.
$('.soft-length-limit').bind('textchange', function(event, prevText){
var limit = $(this).attr('data-soft-length-limit');
var minimum = $(this).attr('data-soft-length-minimum');
var val = $(this).val();
var remaining = limit - val.length;
var $tooltip = $(this).parent().find('.soft-length-limit-tooltip');
var styleSelect = $(this).attr('data-soft-length-style-select');
// Removes the "exceeded" class if length is not exceeded
// anymore.
if (prevText.length > limit && val.length <= limit) {
$tooltip.removeClass('exceeded');
$(this).removeClass('exceeded');
}
// Adds the "exceeded" class if length is exceeded.
if (val.length > limit && !$tooltip.hasClass('exceeded')) {
$tooltip.addClass('exceeded');
$(this).addClass('exceeded');
}
// Adds the "exceeded" class if the length is less than the minimum, in the case where the minimum is set.
// Adds the "under-min" class, for under-character-minimum specific behavior. Used for min/enhanced character count.
if (minimum > 0) {
if (val.length < minimum) {
$tooltip.addClass('under-min');
$(this).addClass('under-min');
}
if (val.length >= minimum) {
$tooltip.removeClass('under-min');
$(this).removeClass('under-min');
}
if (val.length > limit) {
$tooltip.addClass('exceeded');
$(this).addClass('exceeded');
}
if (val.length <= limit) {
$tooltip.removeClass('exceeded');
$(this).removeClass('exceeded');
}
}
// The minimal/enhanced version of character limits
if (styleSelect == '1') {
// No minimum treatment
$tooltip.html(Drupal.t('@val/@limit', {
'@val': val.length,
'@limit': limit
}));
// Add class to tooltip for different CSS treatment (icons, text alignment, etc )
$tooltip.parent().children('.soft-length-limit-tooltip').addClass('min-style-tooltip');
}
// Original character limit treatment
if ((styleSelect == '0') || (styleSelect == undefined)) {
// No minimum value is set.
if (minimum < 1) {
if (val.length === 0) {
$tooltip.html(Drupal.t('Content limited to @limit characters',{
'@limit': limit
}));
}
else if (remaining < 0) {
$tooltip.html(Drupal.t('@limit character limit exceeded by @exceed characters.',{
'@limit': limit,
'@exceed': -remaining
}));
}
else {
$tooltip.html(Drupal.t('Content limited to @limit characters. Remaining: @remaining',{
'@limit': limit,
'@remaining': remaining
}));
}
}
// There is a minimum length set.
else {
if (val.length === 0) {
$tooltip.html(Drupal.t('Suggested minimum number of characters is @minimum, current count is @val. Content limited to @limit characters. ',{
'@limit': limit,
'@minimum': minimum,
'@val': val.length
}));
}
else if (remaining < 0) {
$tooltip.html(Drupal.t('Suggested minimum number of characters is @minimum, current count is @val. @limit character limit exceeded by @exceed characters.',{
'@limit': limit,
'@exceed': -remaining,
'@minimum': minimum,
'@val': val.length
}));
}
else {
$tooltip.html(Drupal.t('Suggested minimum number of characters is @minimum, current count is @val. Content limited to @limit characters. Remaining: @remaining.',{
'@limit': limit,
'@remaining': remaining,
'@minimum': minimum,
'@val': val.length
}));
}
}
}
});
}
};
})(jQuery);
soft_length_limit:
js:
js/soft_length_limit.js: {}
js/jquery.textchange.min.js: {}
css:
component:
css/soft_length_limit.css: {}
dependencies:
- core/jquery
- core/jquery.once
......@@ -2,257 +2,158 @@
/**
* @file
* Soft Length Limit module
* Soft Length Limit module.
*/
define('SOFT_LENGTH_LIMIT_TITLE_MAX', 'soft_length_limit_title_max');
define('SOFT_LENGTH_LIMIT_TITLE_MIN', 'soft_length_limit_title_min');
define('SOFT_LENGTH_STYLE_SELECT', 'soft_length_style_select');
declare(strict_types = 1);
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\WidgetInterface;
use Drupal\Core\Form\FormStateInterface;
/**
* Returns the field widget or form element types that should be affected.
*
* @param string $usage
* The desired usage of the data, can be one of 'fields' or 'elements'
* Returns the widget settings that can be used for a soft_length widget.
*
* @return array
* An array field widget or form element type names
* An array of settings and default values for each textfield type.
*/
function _soft_length_limit_types($usage) {
$return = array();
switch ($usage) {
case 'fields':
$return = array(
'text_textarea' => 'text_textarea',
'text_textfield' => 'text_textfield',
'text_textarea_with_summary' => 'text_textarea_with_summary',
);
break;
case 'elements':
$return = array(
'textarea' => 'textarea',
'textfield' => 'textfield',
'text_format' => 'text_format',
);
break;
case 'entity_types':
$return = array(
'node' => 'node',
);
break;
}
return $return;
function _soft_length_widget_settings(string $plugin_id): array {
$settings = [
'string_textfield' => [
'max_limit' => TRUE,
'minimum_limit' => TRUE,
'style_select' => TRUE,
],
'string_textarea' => [
'max_limit' => TRUE,
'minimum_limit' => TRUE,
'style_select' => TRUE,
],
'text_textfield' => [
'max_limit' => TRUE,
'minimum_limit' => TRUE,
'style_select' => TRUE,
],
'text_textarea' => [
'max_limit' => TRUE,
'minimum_limit' => TRUE,
'style_select' => TRUE,
],
'text_textarea_with_summary' => [
'max_limit' => TRUE,
'minimum_limit' => TRUE,
'style_select' => TRUE,
],
];
return $settings[$plugin_id] ?? [];
}
/**
* Implements hook_form_FORM_ID_alter().
*
* Adds soft length limit fields when editing a content type.
* Implements hook_field_widget_third_party_settings_form().
*/
function soft_length_limit_form_node_type_form_alter(&$form, &$form_state, $form_id) {
$form['submission'][SOFT_LENGTH_LIMIT_TITLE_MAX] = array(
'#type' => 'textfield',
'#title' => t('Soft length limit'),
'#default_value' => variable_get(SOFT_LENGTH_LIMIT_TITLE_MAX . '_' . $form['#node_type']->type, NULL),
'#description' => t('If any value is given here, a counter will appear next to this field, informing the user of the chosen number of allowed characters. If the number is exceeded, a warning will be shown.'),
'#element_validate' => array('element_validate_integer_positive'),
'#weight' => -2,
);
$form['submission'][SOFT_LENGTH_LIMIT_TITLE_MIN] = array(
'#type' => 'textfield',
'#title' => t('Soft length minimum'),
'#default_value' => variable_get(SOFT_LENGTH_LIMIT_TITLE_MIN . '_' . $form['#node_type']->type, NULL),
'#description' => t('If any value is given here, the minimum number recommended characters will be displayed as the editor enters text in this field.'),
'#element_validate' => array('element_validate_integer_positive'),
'#weight' => -1,
);
$form['submission'][SOFT_LENGTH_STYLE_SELECT] = array(
'#type' => 'checkbox',
'#title' => t('Enable enhanced view'),
'#default_value' => variable_get(SOFT_LENGTH_STYLE_SELECT . '_' . $form['#node_type']->type, NULL),
'#description' => t('Check this to enable an enhanced view of soft length states.'),
'#weight' => -1,
);
$form['submission']['title_label']['#weight'] = -3;
// Add a custom submit handler to validate that the editor didn't set the
// maximum length to greater than 255 characters.
$form['#validate'][] = 'soft_length_limit_validate_title_length';
// Add a custom submit handler to save the title maximum and minimum.
$form['#submit'][] = 'soft_length_limit_set_title_maxlength';
}
/**
* Form validate handler for title length fields.
*/
function soft_length_limit_validate_title_length($form, &$form_state) {
if (($form_state['values'][SOFT_LENGTH_LIMIT_TITLE_MAX] < 0) || ($form_state['values'][SOFT_LENGTH_LIMIT_TITLE_MAX] > 255)) {
form_set_error('title_length', t('The value for soft length limit must be a whole number greater than zero and less than 256'), NULL);
}
if (($form_state['values'][SOFT_LENGTH_LIMIT_TITLE_MIN] < 0) || ($form_state['values'][SOFT_LENGTH_LIMIT_TITLE_MIN] > 255)) {
form_set_error('soft_length_minimum', t('The value for soft length minimum must be a whole number greater than zero and less than 256'));
}
if ($form_state['values'][SOFT_LENGTH_LIMIT_TITLE_MAX] < $form_state['values'][SOFT_LENGTH_LIMIT_TITLE_MIN]) {
form_set_error('soft_length_minimum', t('The value for soft length minimum must be less than or equal to the soft length limit'));
function soft_length_limit_field_widget_third_party_settings_form(WidgetInterface $plugin, FieldDefinitionInterface $field_definition, $form_mode, $form, FormStateInterface $form_state) {
$plugin_id = $plugin->getPluginId();
if (!$allowed_settings = _soft_length_widget_settings($plugin_id)) {
return NULL;
}
}
/**
* Save the values of max and minimum for title.
*
* So they can be applied later as an override to #maxlength.
*/
function soft_length_limit_set_title_maxlength($form, &$form_state) {
variable_set(SOFT_LENGTH_LIMIT_TITLE_MAX . '_' . $form_state['values']['type'], $form_state['values'][SOFT_LENGTH_LIMIT_TITLE_MAX]);
variable_set(SOFT_LENGTH_LIMIT_TITLE_MIN . '_' . $form_state['values']['type'], $form_state['values'][SOFT_LENGTH_LIMIT_TITLE_MIN]);
variable_set(SOFT_LENGTH_STYLE_SELECT . '_' . $form_state['values']['type'], $form_state['values'][SOFT_LENGTH_STYLE_SELECT]);
}
/**
* Implements hook_form_FORM_ID_alter().
*
* Adds soft length limit fields when a field form field is rendered.
*/
function soft_length_limit_form_field_ui_field_edit_form_alter(&$form, &$form_state) {
$types = _soft_length_limit_types('fields');
if (isset($types[$form['#instance']['widget']['type']])) {
$form['instance']['widget']['settings']['soft_length_limit'] = array(
'#type' => 'textfield',
$element = [];
if ($allowed_settings['max_limit']) {
$element['max_limit'] = [
'#type' => 'number',
'#min' => 0,
'#title' => t('Soft length limit'),
'#default_value' => isset($form['#instance']['widget']['settings']['soft_length_limit']) ? $form['#instance']['widget']['settings']['soft_length_limit'] : NULL,
'#default_value' => $plugin->getThirdPartySetting('soft_length_limit', 'max_limit'),
'#description' => t('If any value is given here, a counter will appear next to this field, informing the user of the chosen number of allowed characters. If the number is exceeded, a warning will be shown.'),
'#element_validate' => array('element_validate_integer_positive'),
'#weight' => -3,
);
];
}
$form['instance']['widget']['settings']['soft_length_minimum'] = array(
'#type' => 'textfield',
if ($allowed_settings['minimum_limit']) {
$element['minimum_limit'] = [
'#type' => 'number',
'#min' => 0,
'#title' => t('Soft length minimum'),
'#default_value' => isset($form['#instance']['widget']['settings']['soft_length_minimum']) ? $form['#instance']['widget']['settings']['soft_length_minimum'] : NULL,
'#default_value' => $plugin->getThirdPartySetting('soft_length_limit', 'minimum_limit'),
'#description' => t('If any value is given here, the minimum number recommended characters will be displayed as the editor enters text in this field.'),
'#element_validate' => array('element_validate_integer_positive'),
'#weight' => -2,
);
];
}
$form['instance']['widget']['settings']['soft_length_style_select'] = array(
if ($allowed_settings['style_select']) {
$element['style_select'] = [
'#type' => 'checkbox',
'#title' => t('Enable enhanced view'),
'#default_value' => isset($form['#instance']['widget']['settings']['soft_length_style_select']) ? $form['#instance']['widget']['settings']['soft_length_style_select'] : 0,
'#default_value' => $plugin->getThirdPartySetting('soft_length_limit', 'style_select'),
'#description' => t('Check this to enable an enhanced view of soft length states.'),
'#weight' => -1,
);
];
}
return $element;
}
/**
* Implements hook_field_attach_form().
* Implements hook_field_widget_settings_summary_alter().
*/
function soft_length_limit_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
$entity_types = _soft_length_limit_types('entity_types');
function soft_length_limit_field_widget_settings_summary_alter(&$summary, $context) {
/* @var \Drupal\Core\Field\WidgetInterface $widget */
$widget = $context['widget'];
$plugin_id = $widget->getPluginId();
if (!isset($entity_types[$entity_type])) {
return;
if (!$allowed_settings = _soft_length_widget_settings($plugin_id)) {
return NULL;
}
$fields = field_info_instances($entity_type, $form['#bundle']);
$elements = array();
foreach ($fields as $key => $value) {
if (isset($value['widget']['settings']['soft_length_limit']) && $value['widget']['settings']['soft_length_limit'] > 0) {
$elements[$key] = $value;
}
$max_limit = $allowed_settings['max_limit']
? $widget->getThirdPartySetting('soft_length_limit', 'max_limit')
: FALSE;
$minimum_limit = $allowed_settings['minimum_limit']
? $widget->getThirdPartySetting('soft_length_limit', 'minimum_limit')
: FALSE;
$style_select = $allowed_settings['minimum_limit']
? $widget->getThirdPartySetting('soft_length_limit', 'style_select')
: FALSE;
if ($max_limit) {
$summary[] = t('Maximum recommended length: @count', ['@count' => $max_limit]);
}
if (count($elements) || isset($form['title'])) {
soft_length_limit_set_attr($form, $elements);
// Adds the javascript and CSS files as form attachments, in case the init
// hook does not add them due to the context or settings.
$form['#attached']['js'][] = drupal_get_path('module', 'soft_length_limit') . '/jquery.textchange.min.js';
$form['#attached']['js'][] = drupal_get_path('module', 'soft_length_limit') . '/soft_length_limit.js';
$form['#attached']['css'][] = drupal_get_path('module', 'soft_length_limit') . '/soft_length_limit.css';
if ($minimum_limit) {
$summary[] = t('Minimum recommended length: @count', ['@count' => $minimum_limit]);
}
if ($style_select) {
$summary[] = t('Style select: @style', ['@style' => $style_select ? 'Enabled' : 'Disabled']);
}
}
/**
* Recurse through form and set variables.
*
* Recursive helper function that sets the correct attributes for the form
* elements with a specific soft limit specified, and continues through child
* elements.
*
* @param array $element
* The form element to iterate through
*
* @param array $sub_elements
* Array of the elements which should have a soft limit attribute
* Implements hook_field_widget_form_alter().
*/
function soft_length_limit_set_attr(&$element, $sub_elements) {
$children = element_get_visible_children($element);
$types = _soft_length_limit_types('elements');
foreach ($children as $value) {
if (isset($element[$value]['#type']) && isset($types[$element[$value]['#type']])) {
if (isset($element[$value]['#field_name']) && isset($sub_elements[$element[$value]['#field_name']])) {
$widget_settings = isset($sub_elements[$element[$value]['#field_name']]['widget']['settings']) ? $sub_elements[$element[$value]['#field_name']]['widget']['settings'] : FALSE;
function soft_length_limit_field_widget_form_alter(&$element, FormStateInterface $form_state, $context) {
$third_party_settings = $context['widget']->getThirdPartySettings();
if ($widget_settings) {
// Soft limit length.
$soft_limit = $widget_settings['soft_length_limit'];
$element[$value]['#soft_length_limit'] = (isset($element[$value]['#maxlength']) && $soft_limit > $element[$value]['#maxlength']) ? $element[$value]['#maxlength'] : $soft_limit;
$element[$value]['#attributes']['data-soft-length-limit'] = $soft_limit;
$element[$value]['#attributes']['class'][] = 'soft-length-limit';
// Soft minimum.
$soft_min = isset($widget_settings['soft_length_minimum']) ? $widget_settings['soft_length_minimum'] : '';
$element[$value]['#attributes']['data-soft-length-minimum'] = $soft_min;
if (empty($third_party_settings['soft_length_limit'])) {
return NULL;
}
// Length style select.
if (isset($widget_settings['soft_length_style_select'])) {
$element[$value]['#attributes']['data-soft-length-style-select'] = $widget_settings['soft_length_style_select'];
}
}
}
}
$sll_config = $third_party_settings['soft_length_limit'];
soft_length_limit_set_attr($element[$value], $sub_elements);
if (isset($sll_config['max_limit'])) {
$element['value']['#attributes']['data-soft-length-limit'] = $sll_config['max_limit'];
$element['value']['#attributes']['class'][] = 'soft-length-limit';
}
}
/**
* Implements hook_form_FORM_ID_alter().
*
* Adds CSS and JS to display soft_length_limits when they are set for the
* title field.
*/
function soft_length_limit_form_node_form_alter(&$form, $form_state) {
$type = $form['#node']->type;
$max_length = variable_get(SOFT_LENGTH_LIMIT_TITLE_MAX . '_' . $type, NULL);
$min_length = variable_get(SOFT_LENGTH_LIMIT_TITLE_MIN . '_' . $type, NULL);
if (!$min_length) {
$min_length = 0;
if (isset($sll_config['minimum_limit'])) {
$element['value']['#attributes']['data-soft-length-minimum'] = $sll_config['minimum_limit'];
}
// Length style select.
if (isset($sll_config['style_select']) && $sll_config['style_select']) {
$element['value']['#attributes']['data-soft-length-style-select'] = (int) $sll_config['style_select'];
}
$style_select = variable_get(SOFT_LENGTH_STYLE_SELECT . '_' . $type, NULL);
// Play nice with title module ensuring that core's title is present.
if (isset($form['title']) && (!empty($max_length) || !empty($min_length))) {
$form['title']['#attributes']['class'][] = 'soft-length-limit';
$form['title']['#attributes']['data-soft-length-limit'] = $max_length;
$form['title']['#attributes']['data-soft-length-minimum'] = $min_length;
$form['#attached']['js'][] = drupal_get_path('module', 'soft_length_limit') . '/jquery.textchange.min.js';
$form['#attached']['js'][] = drupal_get_path('module', 'soft_length_limit') . '/soft_length_limit.js';
$form['#attached']['css'][] = drupal_get_path('module', 'soft_length_limit') . '/soft_length_limit.css';
$form['title']['#attributes']['data-soft-length-style-select'] = $style_select;
if (isset($element['#type']) && $element['#type'] === 'text_format') {
$element['#attributes'] = array_merge_recursive($element['#attributes'], $element['value']['#attributes']);
}
$element['#attached']['library'][] = 'soft_length_limit/soft_length_limit';
}
<?php
/**
* @file
* Test case for soft_length_limit module
*/
/**
* Tests the relevant functionality provided by the soft_length_limit module.
*/
class SoftLengthLimitWebTestCase extends DrupalWebTestCase {
/**
* Info for simpletest.module.
*/
public static function getInfo() {
return array(
'name' => 'Soft Length Limit',
'description' => 'Ensure that the soft limit is applied to the chosen fields',
'group' => 'Soft Length Limit',
);
}
/**
* Setup for individual tests.
*/
public function setUp() {
// Enable any modules required for the test.
parent::setUp(array('soft_length_limit'));
// Creating the needed user.
$this->privileged_user = $this->drupalCreateUser(
array(
'bypass node access',
'administer nodes',
'administer taxonomy',
'edit terms in 1',
));
$this->drupalLogin($this->privileged_user);
// Creating the needed field on the article node type.
$field = array(
'field_name' => 'field_test',
'type' => 'text_long',
'cardinality' => 1,
'settings' => array(),
);
field_create_field($field);
$instance = array(
'field_name' => 'field_test',
'entity_type' => 'node',
'label' => 'Test field',
'required' => 0,
'bundle' => 'article',
'description' => '',
'widget' => array(
'type' => 'text_textarea',
'weight' => -4,
'settings' => array(
'rows' => '5',
'soft_length_limit' => '666',
),
),
'display' => array(
'default' => array(
'type' => 'text_default',
'weight' => 10,
),
'teaser' => array(
'type' => 'text_default',
'weight' => 10,
),
),
);
field_create_instance($instance);
$this->drupalGet('node/add/article');
}
/**
* Tests that input element has the attributes that the javascript should use.
*/
public function testAll() {
$this->assertPattern('/<textarea .*class="[^"]*soft-length-limit[^"]*".*data-soft-length-limit="666"/', 'HTML element should contain the necessary attributesfor the soft length limiter javascript');
}
}
<?php
namespace Drupal\Tests\soft_length_limit\FunctionalJavascript;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Session\AccountInterface;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
/**
* Tests soft length limit JavaScript behavior for text fields.
*/
class SoftLengthLimitJavascriptTest extends WebDriverTestBase {
/**
* {@inheritdoc}
*/
public static $modules = [
'node',
'field',
'entity_test',
'soft_length_limit',
'text',
];
/**
* Tests that the soft length limit widget works.
*/
public function testSoftLengthLimitWithStyleSelect() {
$this->setupContentType();
$entity = EntityTest::create(['type' => 'entity_test', 'name' => 'Test Soft Length Limit.']);
$entity->save();
$admin = $this->drupalCreateUser(['administer entity_test content']);
$this->drupalLogin($admin);
$this->drupalGet($entity->toUrl('edit-form'));
$page = $this->getSession()->getPage();
$foo_field = $page->findField('Foo');
$foo_field->focus();
$foo_field->setValue('text');
$tooltip_text = $page->find('css', '.soft-length-limit-tooltip')->getText();
$foo_field->focus();
$this->assertEquals('4/20', $tooltip_text);
}
/**
* Tests that the soft length limit widget works.
*/
public function testSoftLengthLimitWithoutStyleSelect() {
$this->setupContentType(FALSE);
$entity = EntityTest::create(['type' => 'entity_test', 'name' => 'Test Soft Length Limit.']);
$entity->save();
$admin = $this->drupalCreateUser(['administer entity_test content']);
$this->drupalLogin($admin);
$this->drupalGet($entity->toUrl('edit-form'));
$page = $this->getSession()->getPage();
$foo_field = $page->findField('Foo');
$foo_field->focus();
$foo_field->setValue('text');
$tooltip_text = $page->find('css', '.soft-length-limit-tooltip')->getText();
$foo_field->focus();
$this->assertEquals('Suggested minimum number of characters is 10, current count is 4. Content limited to 20 characters. Remaining: 16.',
$tooltip_text);
}
/**
* {@inheritdoc}
*/
protected function drupalLogin(AccountInterface $account) {
// This is a clone of the UiHelperTrait::drupalLogin() method,
// which seems to make the test fail no matter what, when asserting the
// user session.
if ($this->loggedInUser) {
$this->drupalLogout();
}
$this->drupalGet('user/login');
$this->submitForm([
'name' => $account->getAccountName(),
'pass' => $account->passRaw,
], t('Log in'));
// @see ::drupalUserIsLoggedIn()
$account->sessionId = $this->getSession()->getCookie(\Drupal::service('session_configuration')->getOptions(\Drupal::request())['name']);
$this->loggedInUser = $account;
$this->container->get('current_user')->setAccount($account);
}
/**
* Sets up the entity_test entity type with a field using soft_length_limit.
*
* @param bool $style_select
* Whether to use style_select option of soft_length_limit.
*
* @throws \Drupal\Core\Entity\EntityStorageException
*/
private function setupContentType($style_select = TRUE): void {
FieldStorageConfig::create([
'type' => 'text_long',
'entity_type' => 'entity_test',
'field_name' => 'foo',
])->save();
FieldConfig::create([
'entity_type' => 'entity_test',
'bundle' => 'entity_test',
'field_name' => 'foo',
'label' => 'Foo',
'description' => 'Description of a text field',
])->save();
$widget = [
'type' => 'text_textarea',
'third_party_settings' => [
'soft_length_limit' => [
'max_limit' => 20,
'minimum_limit' => 10,
'style_select' => $style_select,
],
],
];
EntityFormDisplay::load('entity_test.entity_test.default')
->setComponent('foo', $widget)
->save();
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment