summaryrefslogtreecommitdiffstatshomepage
path: root/core/misc/machine-name.js
diff options
context:
space:
mode:
Diffstat (limited to 'core/misc/machine-name.js')
-rw-r--r--core/misc/machine-name.js161
1 files changed, 130 insertions, 31 deletions
diff --git a/core/misc/machine-name.js b/core/misc/machine-name.js
index 7281c4a3eda2..e890685ec515 100644
--- a/core/misc/machine-name.js
+++ b/core/misc/machine-name.js
@@ -1,12 +1,43 @@
/**
-* DO NOT EDIT THIS FILE.
-* See the following change record for more information,
-* https://www.drupal.org/node/2815083
-* @preserve
-**/
+ * @file
+ * Machine name functionality.
+ */
(function ($, Drupal, drupalSettings) {
+ /**
+ * Attach the machine-readable name form element behavior.
+ *
+ * @type {Drupal~behavior}
+ *
+ * @prop {Drupal~behaviorAttach} attach
+ * Attaches machine-name behaviors.
+ */
Drupal.behaviors.machineName = {
+ /**
+ * Attaches the behavior.
+ *
+ * @param {Element} context
+ * The context for attaching the behavior.
+ * @param {object} settings
+ * Settings object.
+ * @param {object} settings.machineName
+ * A list of elements to process, keyed by the HTML ID of the form
+ * element containing the human-readable value. Each element is an object
+ * defining the following properties:
+ * - target: The HTML ID of the machine name form element.
+ * - suffix: The HTML ID of a container to show the machine name preview
+ * in (usually a field suffix after the human-readable name
+ * form element).
+ * - label: The label to show for the machine name preview.
+ * - replace_pattern: A regular expression (without modifiers) matching
+ * disallowed characters in the machine name; e.g., '[^a-z0-9]+'.
+ * - replace: A character to replace disallowed characters with; e.g.,
+ * '_' or '-'.
+ * - standalone: Whether the preview should stay in its own element
+ * rather than the suffix of the source element.
+ * - field_prefix: The #field_prefix of the form element.
+ * - field_suffix: The #field_suffix of the form element.
+ */
attach(context, settings) {
const self = this;
const $context = $(context);
@@ -25,22 +56,29 @@
const data = e.data;
const options = data.options;
const baseValue = e.target.value;
+
const rx = new RegExp(options.replace_pattern, 'g');
- const expected = baseValue.toLowerCase().replace(rx, options.replace).substr(0, options.maxlength);
+ const expected = baseValue
+ .toLowerCase()
+ .replace(rx, options.replace)
+ .substr(0, options.maxlength);
+ // Abort the last pending request because the label has changed and it
+ // is no longer valid.
if (xhr && xhr.readystate !== 4) {
xhr.abort();
xhr = null;
}
+ // Wait 300 milliseconds for Ajax request since the last event to update
+ // the machine name i.e., after the user has stopped typing.
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
-
if (baseValue.toLowerCase() !== expected) {
timeout = setTimeout(() => {
- xhr = self.transliterate(baseValue, options).done(machine => {
+ xhr = self.transliterate(baseValue, options).done((machine) => {
self.showMachineName(machine.substr(0, options.maxlength), data);
});
}, 300);
@@ -49,33 +87,54 @@
}
}
- Object.keys(settings.machineName).forEach(sourceId => {
+ Object.keys(settings.machineName).forEach((sourceId) => {
const options = settings.machineName[sourceId];
- const $source = $(once('machine-name', $context.find(sourceId).addClass('machine-name-source')));
- const $target = $context.find(options.target).addClass('machine-name-target');
+
+ const $source = $(
+ once(
+ 'machine-name',
+ $context.find(sourceId).addClass('machine-name-source'),
+ ),
+ );
+ const $target = $context
+ .find(options.target)
+ .addClass('machine-name-target');
const $suffix = $context.find(options.suffix);
const $wrapper = $target.closest('.js-form-item');
-
- if (!$source.length || !$target.length || !$suffix.length || !$wrapper.length) {
+ // All elements have to exist.
+ if (
+ !$source.length ||
+ !$target.length ||
+ !$suffix.length ||
+ !$wrapper.length
+ ) {
return;
}
-
+ // Skip processing upon a form validation error on the machine name.
if ($target.hasClass('error')) {
return;
}
-
+ // Figure out the maximum length for the machine name.
options.maxlength = $target.attr('maxlength');
+ // Hide the form item container of the machine name form element.
$wrapper.addClass('visually-hidden');
+ // Initial machine name from the target field default value.
const machine = $target[0].value;
- const $preview = $(`<span class="machine-name-value">${options.field_prefix}${Drupal.checkPlain(machine)}${options.field_suffix}</span>`);
+ // Append the machine name preview to the source field.
+ const $preview = $(
+ `<span class="machine-name-value">${
+ options.field_prefix
+ }${Drupal.checkPlain(machine)}${options.field_suffix}</span>`,
+ );
$suffix.empty();
-
if (options.label) {
- $suffix.append(`<span class="machine-name-label">${options.label}: </span>`);
+ $suffix.append(
+ `<span class="machine-name-label">${options.label}: </span>`,
+ );
}
-
$suffix.append($preview);
+ // If the machine name cannot be edited, stop further processing.
if ($target.is(':disabled')) {
return;
}
@@ -86,35 +145,56 @@
$suffix,
$wrapper,
$preview,
- options
+ options,
};
+ // If no initial value, determine machine name based on the
+ // human-readable form element value.
if (machine === '' && $source[0].value !== '') {
- self.transliterate($source[0].value, options).done(machineName => {
- self.showMachineName(machineName.substr(0, options.maxlength), eventData);
+ self.transliterate($source[0].value, options).done((machineName) => {
+ self.showMachineName(
+ machineName.substr(0, options.maxlength),
+ eventData,
+ );
});
}
- const $link = $(`<span class="admin-link"><button type="button" class="link">${Drupal.t('Edit')}</button></span>`).on('click', eventData, clickEditHandler);
+ // If it is editable, append an edit link.
+ const $link = $(
+ `<span class="admin-link"><button type="button" class="link">${Drupal.t(
+ 'Edit',
+ )}</button></span>`,
+ ).on('click', eventData, clickEditHandler);
$suffix.append($link);
+ // Preview the machine name in realtime when the human-readable name
+ // changes, but only if there is no machine name yet; i.e., only upon
+ // initial creation, not when editing.
if ($target[0].value === '') {
- $source.on('formUpdated.machineName', eventData, machineNameHandler).trigger('formUpdated.machineName');
+ $source
+ .on('formUpdated.machineName', eventData, machineNameHandler)
+ // Initialize machine name preview.
+ .trigger('formUpdated.machineName');
}
+ // Add a listener for an invalid event on the machine name input
+ // to show its container and focus it.
$target.on('invalid', eventData, clickEditHandler);
});
},
showMachineName(machine, data) {
const settings = data.options;
-
+ // Set the machine name to the transliterated value.
if (machine !== '') {
if (machine !== settings.replace) {
data.$target[0].value = machine;
- data.$preview.html(settings.field_prefix + Drupal.checkPlain(machine) + settings.field_suffix);
+ data.$preview.html(
+ settings.field_prefix +
+ Drupal.checkPlain(machine) +
+ settings.field_suffix,
+ );
}
-
data.$suffix.show();
} else {
data.$suffix.hide();
@@ -123,6 +203,26 @@
}
},
+ /**
+ * Transliterate a human-readable name to a machine name.
+ *
+ * @param {string} source
+ * A string to transliterate.
+ * @param {object} settings
+ * The machine name settings for the corresponding field.
+ * @param {string} settings.replace_pattern
+ * A regular expression (without modifiers) matching disallowed characters
+ * in the machine name; e.g., '[^a-z0-9]+'.
+ * @param {string} settings.replace_token
+ * A token to validate the regular expression.
+ * @param {string} settings.replace
+ * A character to replace disallowed characters with; e.g., '_' or '-'.
+ * @param {number} settings.maxlength
+ * The maximum length of the machine name.
+ *
+ * @return {jQuery}
+ * The transliterated source string.
+ */
transliterate(source, settings) {
return $.get(Drupal.url('machine_name/transliterate'), {
text: source,
@@ -130,9 +230,8 @@
replace_pattern: settings.replace_pattern,
replace_token: settings.replace_token,
replace: settings.replace,
- lowercase: true
+ lowercase: true,
});
- }
-
+ },
};
-})(jQuery, Drupal, drupalSettings); \ No newline at end of file
+})(jQuery, Drupal, drupalSettings);