Skip to content

Commit

Permalink
Adds Description Headers for CSV autocomplete and fixes 5 year old bug
Browse files Browse the repository at this point in the history
Basically no longer caching for autocompletes which means URLs don't will override Labels.
  • Loading branch information
DiegoPino committed Jun 21, 2024
1 parent 1d27cfe commit c33d2ac
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 18 deletions.
62 changes: 62 additions & 0 deletions js/metadataauth-webform_strawberryfield.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,69 @@
return settings;
};

/**
* Overrides Drupal.autocomplete.options.source so we can avoid the opinionated cache
*/

Drupal.autocomplete.options.source = function sourceData(request, response) {
const elementId = this.element.attr('id');
var options = Drupal.autocomplete.options;
const is_sbf = this.element.data('strawberry-autocomplete');

if (!(elementId in Drupal.autocomplete.cache)) {
Drupal.autocomplete.cache[elementId] = {};
}

/**
* Filter through the suggestions removing all terms already tagged and
* display the available terms to the user.
*
* @param {object} suggestions
* Suggestions returned by the server.
*/
function showSuggestions(suggestions) {
const tagged = Drupal.autocomplete.splitValues(request.term);
const il = tagged.length;
for (let i = 0; i < il; i++) {
const index = suggestions.indexOf(tagged[i]);
if (index >= 0) {
suggestions.splice(index, 1);
}
}
response(suggestions);
}

// Get the desired term and construct the autocomplete URL for it.
const term = Drupal.autocomplete.extractLastTerm(request.term);

/**
* Transforms the data object into an array and update autocomplete results.
*
* @param {object} data
* The data sent back from the server.
*/
function sourceCallbackHandler(data) {
if (!is_sbf) {
Drupal.autocomplete.cache[elementId][term] = data;
}

// Send the new string array of terms to the jQuery UI list.
showSuggestions(data);
}

// Check if the term is already cached.
if (Drupal.autocomplete.cache[elementId].hasOwnProperty(term) && !is_sbf) {
showSuggestions(Drupal.autocomplete.cache[elementId][term]);
} else {
const options = $.extend(
{ success: sourceCallbackHandler, data: { q: term } },
Drupal.autocomplete.ajax,
);
$.ajax(this.element.attr('data-autocomplete-path'), options);
}
}

/**
* Overrides Drupal.autocomplete.options.search for no splitting of terms
*
* This is the only function where even is present, means we can decide per instance
Expand Down
46 changes: 29 additions & 17 deletions src/Controller/RowAutocompleteController.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,24 @@ public static function create(ContainerInterface $container) {
* Filters against Labels
*
*/
public function handleAutocomplete(Request $request, ContentEntityInterface $node, $label_header, $url_header, $match = 'STARTS_WITH', $limit = 10, $min = 2) {
public function handleAutocomplete(Request $request, ContentEntityInterface $node, $label_header, $url_header, $match = 'STARTS_WITH', $limit = 10, $min = 2, $desc_headers = NULL) {
$results = [];
$input = $request->query->get('q');
$input = Xss::filter($input);
$label_header = strtolower($label_header);
$url_header = strtolower($url_header);

$desc_headers = strtolower($desc_headers);
$desc_headers_exploded = [];
$desc_headers_indexes = [];
// Find a CSV file in this ADO.
// Get the typed string from the URL, if it exists.
if (!$input && strlen(trim($input)) < $min) {
return new JsonResponse($results);
}
if (is_string($desc_headers)) {
$desc_headers_exploded = explode(',', $desc_headers);
$desc_headers_exploded = array_slice($desc_headers_exploded, 0, 2);
}

$file = null;
if ($sbf_fields = \Drupal::service('strawberryfield.utility')->bearsStrawberryfield($node)) {
Expand All @@ -98,32 +104,38 @@ public function handleAutocomplete(Request $request, ContentEntityInterface $nod
$column_keys = $file_data_all['headers'] ?? [];
$label_original_index = array_search($label_header, $column_keys);
$url_original_index = array_search($url_header, $column_keys);
foreach ($desc_headers_exploded as $desc_header) {
$index = array_search($desc_header, $column_keys);
if ($index!== FALSE) {
$desc_headers_indexes[] = $index;
}
}

$i = 0;
if ($label_original_index !== FALSE && $url_original_index !== FALSE) {
foreach ($file_data_all['data'] as $id => &$row) {
if (isset($row[$label_original_index])) {

if ($match == 'STARTS_WITH' && stripos($row[$label_original_index], $input) === 0) {
if (($match == 'STARTS_WITH' && stripos($row[$label_original_index], $input) === 0) || ($match == 'CONTAINS' && stripos($row[$label_original_index], $input) !== FALSE)) {
$i++;

$desc = [];
$desc_string = '';
foreach ($desc_headers_indexes as $desc_header_index) {
$desc[] = $row[$desc_header_index];
}
$desc = array_filter($desc);
if (count($desc)) {
$desc_string = implode('|', $desc);
}
$desc_string = ($desc_string !== '') ? '(' . $desc_string . ')' : NULL;
$results[] = [
'value' => $row[$url_original_index],
'label' => $row[$label_original_index],
'label' => $row[$label_original_index].' '.$desc_string,
'desc' => $desc_string
];
if ($i == $limit) {
break;
}
} else
if ($match == 'CONTAINS' && stripos($row[$label_original_index], $input) !== FALSE) {
$i++;
$results[] = [
'value' => $row[$url_original_index],
'label' => $row[$label_original_index],
];
if ($i == $limit) {
break;
}
}
}
}
}
}
Expand Down
17 changes: 17 additions & 0 deletions src/Plugin/WebformElement/WebformLoDfromCSV.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ protected function defineDefaultProperties() {
'autocomplete_match' => 3,
'autocomplete_label_header' => 'label',
'autocomplete_url_header' => 'url',
'autocomplete_desc_headers' => '',
'autocomplete_match_operator' => 'CONTAINS',
] + parent::defineDefaultProperties()
+ $this->defineDefaultMultipleProperties();
Expand All @@ -62,13 +63,24 @@ public function prepare(

if (isset($element['#webform_key'])) {
$element['#autocomplete_route_name'] = 'webform_strawberryfield.rowsbylabel.autocomplete';
$desc = $element['#autocomplete_desc_headers'] ?? $properties['autocomplete_desc_headers'];
if (is_string($desc) && strlen(trim($desc)) > 0 ) {
$desc = explode(',', $desc);
$desc = array_slice($desc, 0, 2);
$desc = array_map('trim', $desc);
$desc = implode(',', $desc);
}
else {
$desc = '';
}
$element['#autocomplete_route_parameters'] = [
'node' => $element['#autocomplete_items'],
'label_header' => $element['#autocomplete_label_header'] ?? $properties['autocomplete_label_header'],
'url_header' => $element['#autocomplete_url_header'] ?? $properties['autocomplete_url_header'],
'match' => $element['#autocomplete_match_operator'] ?? $properties['autocomplete_match_operator'],
'limit' => $element['#autocomplete_limit'] ?? $properties['autocomplete_limit'],
'min' => $element['#autocomplete_match'] ?? $properties['autocomplete_match'],
'desc_headers' => $desc,
];
}
}
Expand Down Expand Up @@ -161,6 +173,11 @@ public function form(array $form, FormStateInterface $form_state) {
'#title' => $this->t('The CSV column(header name) that will be used for the URL value'),
'#required' => TRUE,
];
$form['autocomplete']['autocomplete_desc_headers'] = [
'#type' => 'textfield',
'#title' => $this->t('The CSV columns(header names), separated by a comma, that will be used for additional context/description. Leave empty if not used. It has a limited of 2 headers. Any extra ones will be ignored.'),
'#required' => FALSE,
];
$form['autocomplete']['autocomplete_limit'] = [
'#type' => 'number',
'#title' => $this->t('Autocomplete limit'),
Expand Down
3 changes: 2 additions & 1 deletion webform_strawberryfield.routing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ webform_strawberryfield.element.autocomplete:
_entity_access: 'webform.submission_create'

webform_strawberryfield.rowsbylabel.autocomplete:
path: '/webform_strawberry/csv_autocomplete/{node}/{label_header}/{url_header}/{match}/{limit}/{min}'
path: '/webform_strawberry/csv_autocomplete/{node}/{label_header}/{url_header}/{match}/{limit}/{min}/{desc_headers}'
options:
parameters:
node:
Expand All @@ -73,6 +73,7 @@ webform_strawberryfield.rowsbylabel.autocomplete:
match: 'STARTS_WITH'
limit: 10
min: 2
desc_headers: ''
_controller: '\Drupal\webform_strawberryfield\Controller\RowAutocompleteController::handleAutocomplete'
_format: json
requirements:
Expand Down

0 comments on commit c33d2ac

Please sign in to comment.