annotate core/misc/machine-name.es6.js @ 0:c75dbcec494b

Initial commit from drush-created site
author Chris Cannam
date Thu, 05 Jul 2018 14:24:15 +0000
parents
children a9cd425dd02b
rev   line source
Chris@0 1 /**
Chris@0 2 * @file
Chris@0 3 * Machine name functionality.
Chris@0 4 */
Chris@0 5
Chris@0 6 (function ($, Drupal, drupalSettings) {
Chris@0 7 /**
Chris@0 8 * Attach the machine-readable name form element behavior.
Chris@0 9 *
Chris@0 10 * @type {Drupal~behavior}
Chris@0 11 *
Chris@0 12 * @prop {Drupal~behaviorAttach} attach
Chris@0 13 * Attaches machine-name behaviors.
Chris@0 14 */
Chris@0 15 Drupal.behaviors.machineName = {
Chris@0 16
Chris@0 17 /**
Chris@0 18 * Attaches the behavior.
Chris@0 19 *
Chris@0 20 * @param {Element} context
Chris@0 21 * The context for attaching the behavior.
Chris@0 22 * @param {object} settings
Chris@0 23 * Settings object.
Chris@0 24 * @param {object} settings.machineName
Chris@0 25 * A list of elements to process, keyed by the HTML ID of the form
Chris@0 26 * element containing the human-readable value. Each element is an object
Chris@0 27 * defining the following properties:
Chris@0 28 * - target: The HTML ID of the machine name form element.
Chris@0 29 * - suffix: The HTML ID of a container to show the machine name preview
Chris@0 30 * in (usually a field suffix after the human-readable name
Chris@0 31 * form element).
Chris@0 32 * - label: The label to show for the machine name preview.
Chris@0 33 * - replace_pattern: A regular expression (without modifiers) matching
Chris@0 34 * disallowed characters in the machine name; e.g., '[^a-z0-9]+'.
Chris@0 35 * - replace: A character to replace disallowed characters with; e.g.,
Chris@0 36 * '_' or '-'.
Chris@0 37 * - standalone: Whether the preview should stay in its own element
Chris@0 38 * rather than the suffix of the source element.
Chris@0 39 * - field_prefix: The #field_prefix of the form element.
Chris@0 40 * - field_suffix: The #field_suffix of the form element.
Chris@0 41 */
Chris@0 42 attach(context, settings) {
Chris@0 43 const self = this;
Chris@0 44 const $context = $(context);
Chris@0 45 let timeout = null;
Chris@0 46 let xhr = null;
Chris@0 47
Chris@0 48 function clickEditHandler(e) {
Chris@0 49 const data = e.data;
Chris@0 50 data.$wrapper.removeClass('visually-hidden');
Chris@0 51 data.$target.trigger('focus');
Chris@0 52 data.$suffix.hide();
Chris@0 53 data.$source.off('.machineName');
Chris@0 54 }
Chris@0 55
Chris@0 56 function machineNameHandler(e) {
Chris@0 57 const data = e.data;
Chris@0 58 const options = data.options;
Chris@0 59 const baseValue = $(e.target).val();
Chris@0 60
Chris@0 61 const rx = new RegExp(options.replace_pattern, 'g');
Chris@0 62 const expected = baseValue.toLowerCase().replace(rx, options.replace).substr(0, options.maxlength);
Chris@0 63
Chris@0 64 // Abort the last pending request because the label has changed and it
Chris@0 65 // is no longer valid.
Chris@0 66 if (xhr && xhr.readystate !== 4) {
Chris@0 67 xhr.abort();
Chris@0 68 xhr = null;
Chris@0 69 }
Chris@0 70
Chris@0 71 // Wait 300 milliseconds for Ajax request since the last event to update
Chris@0 72 // the machine name i.e., after the user has stopped typing.
Chris@0 73 if (timeout) {
Chris@0 74 clearTimeout(timeout);
Chris@0 75 timeout = null;
Chris@0 76 }
Chris@0 77 if (baseValue.toLowerCase() !== expected) {
Chris@0 78 timeout = setTimeout(() => {
Chris@0 79 xhr = self.transliterate(baseValue, options).done((machine) => {
Chris@0 80 self.showMachineName(machine.substr(0, options.maxlength), data);
Chris@0 81 });
Chris@0 82 }, 300);
Chris@0 83 }
Chris@0 84 else {
Chris@0 85 self.showMachineName(expected, data);
Chris@0 86 }
Chris@0 87 }
Chris@0 88
Chris@0 89 Object.keys(settings.machineName).forEach((sourceId) => {
Chris@0 90 let machine = '';
Chris@0 91 const options = settings.machineName[sourceId];
Chris@0 92
Chris@0 93 const $source = $context.find(sourceId).addClass('machine-name-source').once('machine-name');
Chris@0 94 const $target = $context.find(options.target).addClass('machine-name-target');
Chris@0 95 const $suffix = $context.find(options.suffix);
Chris@0 96 const $wrapper = $target.closest('.js-form-item');
Chris@0 97 // All elements have to exist.
Chris@0 98 if (!$source.length || !$target.length || !$suffix.length || !$wrapper.length) {
Chris@0 99 return;
Chris@0 100 }
Chris@0 101 // Skip processing upon a form validation error on the machine name.
Chris@0 102 if ($target.hasClass('error')) {
Chris@0 103 return;
Chris@0 104 }
Chris@0 105 // Figure out the maximum length for the machine name.
Chris@0 106 options.maxlength = $target.attr('maxlength');
Chris@0 107 // Hide the form item container of the machine name form element.
Chris@0 108 $wrapper.addClass('visually-hidden');
Chris@0 109 // Determine the initial machine name value. Unless the machine name
Chris@0 110 // form element is disabled or not empty, the initial default value is
Chris@0 111 // based on the human-readable form element value.
Chris@0 112 if ($target.is(':disabled') || $target.val() !== '') {
Chris@0 113 machine = $target.val();
Chris@0 114 }
Chris@0 115 else if ($source.val() !== '') {
Chris@0 116 machine = self.transliterate($source.val(), options);
Chris@0 117 }
Chris@0 118 // Append the machine name preview to the source field.
Chris@0 119 const $preview = $(`<span class="machine-name-value">${options.field_prefix}${Drupal.checkPlain(machine)}${options.field_suffix}</span>`);
Chris@0 120 $suffix.empty();
Chris@0 121 if (options.label) {
Chris@0 122 $suffix.append(`<span class="machine-name-label">${options.label}: </span>`);
Chris@0 123 }
Chris@0 124 $suffix.append($preview);
Chris@0 125
Chris@0 126 // If the machine name cannot be edited, stop further processing.
Chris@0 127 if ($target.is(':disabled')) {
Chris@0 128 return;
Chris@0 129 }
Chris@0 130
Chris@0 131 const eventData = {
Chris@0 132 $source,
Chris@0 133 $target,
Chris@0 134 $suffix,
Chris@0 135 $wrapper,
Chris@0 136 $preview,
Chris@0 137 options,
Chris@0 138 };
Chris@0 139 // If it is editable, append an edit link.
Chris@0 140 const $link = $(`<span class="admin-link"><button type="button" class="link">${Drupal.t('Edit')}</button></span>`).on('click', eventData, clickEditHandler);
Chris@0 141 $suffix.append($link);
Chris@0 142
Chris@0 143 // Preview the machine name in realtime when the human-readable name
Chris@0 144 // changes, but only if there is no machine name yet; i.e., only upon
Chris@0 145 // initial creation, not when editing.
Chris@0 146 if ($target.val() === '') {
Chris@0 147 $source.on('formUpdated.machineName', eventData, machineNameHandler)
Chris@0 148 // Initialize machine name preview.
Chris@0 149 .trigger('formUpdated.machineName');
Chris@0 150 }
Chris@0 151
Chris@0 152 // Add a listener for an invalid event on the machine name input
Chris@0 153 // to show its container and focus it.
Chris@0 154 $target.on('invalid', eventData, clickEditHandler);
Chris@0 155 });
Chris@0 156 },
Chris@0 157
Chris@0 158 showMachineName(machine, data) {
Chris@0 159 const settings = data.options;
Chris@0 160 // Set the machine name to the transliterated value.
Chris@0 161 if (machine !== '') {
Chris@0 162 if (machine !== settings.replace) {
Chris@0 163 data.$target.val(machine);
Chris@0 164 data.$preview.html(settings.field_prefix + Drupal.checkPlain(machine) + settings.field_suffix);
Chris@0 165 }
Chris@0 166 data.$suffix.show();
Chris@0 167 }
Chris@0 168 else {
Chris@0 169 data.$suffix.hide();
Chris@0 170 data.$target.val(machine);
Chris@0 171 data.$preview.empty();
Chris@0 172 }
Chris@0 173 },
Chris@0 174
Chris@0 175 /**
Chris@0 176 * Transliterate a human-readable name to a machine name.
Chris@0 177 *
Chris@0 178 * @param {string} source
Chris@0 179 * A string to transliterate.
Chris@0 180 * @param {object} settings
Chris@0 181 * The machine name settings for the corresponding field.
Chris@0 182 * @param {string} settings.replace_pattern
Chris@0 183 * A regular expression (without modifiers) matching disallowed characters
Chris@0 184 * in the machine name; e.g., '[^a-z0-9]+'.
Chris@0 185 * @param {string} settings.replace_token
Chris@0 186 * A token to validate the regular expression.
Chris@0 187 * @param {string} settings.replace
Chris@0 188 * A character to replace disallowed characters with; e.g., '_' or '-'.
Chris@0 189 * @param {number} settings.maxlength
Chris@0 190 * The maximum length of the machine name.
Chris@0 191 *
Chris@0 192 * @return {jQuery}
Chris@0 193 * The transliterated source string.
Chris@0 194 */
Chris@0 195 transliterate(source, settings) {
Chris@0 196 return $.get(Drupal.url('machine_name/transliterate'), {
Chris@0 197 text: source,
Chris@0 198 langcode: drupalSettings.langcode,
Chris@0 199 replace_pattern: settings.replace_pattern,
Chris@0 200 replace_token: settings.replace_token,
Chris@0 201 replace: settings.replace,
Chris@0 202 lowercase: true,
Chris@0 203 });
Chris@0 204 },
Chris@0 205 };
Chris@0 206 }(jQuery, Drupal, drupalSettings));