throw new coding_exception('Setting the value of an autocomplete field requires javascript.');
}
- // Set the value of the autocomplete's input.
- // If this autocomplete offers suggestions then these should be fetched by setting the value and waiting for the
- // JS to finish fetching those suggestions.
+ // Clear all current selections.
+ $rootnode = $this->field->getParent()->getParent();
+ $selections = $rootnode->findAll('css', '.form-autocomplete-selection [role=option]');
+ foreach ($selections as $selection) {
+ $selection->click();
+ $this->wait_for_pending_js();
+ }
- $istagelement = $this->field->hasAttribute('data-tags') && $this->field->getAttribute('data-tags');
+ $allowscreation = $this->field->hasAttribute('data-tags') && !empty($this->field->getAttribute('data-tags'));
+ $hasmultiple = $this->field->hasAttribute('data-multiple') && !empty($this->field->getAttribute('data-multiple'));
- if ($istagelement && false !== strpos($value, ',')) {
- // Commas have a special meaning as a value separator in 'tag' autocomplete elements.
+ if ($hasmultiple && false !== strpos($value, ',')) {
+ // Commas have a special meaning as a value separator in 'multiple' autocomplete elements.
// To handle this we break the value up by comma, and enter it in chunks.
$values = explode(',', $value);
while ($value = array_shift($values)) {
- $this->set_value($value);
+ $this->add_value(trim($value), $allowscreation);
}
} else {
- $this->field->setValue($value);
- $this->wait_for_pending_js();
+ $this->add_value(trim($value), $allowscreation);
+ }
+ }
- // If the autocomplete found suggestions, then it will have:
- // 1) marked itself as expanded; and
- // 2) have an aria-selected suggestion in the list.
- $expanded = $this->field->getAttribute('aria-expanded');
- $suggestion = $this->field->getParent()->find('css', '.form-autocomplete-suggestions > [aria-selected="true"]');
-
- if ($expanded && null !== $suggestion) {
- // A suggestion was found.
- // Click on the first item in the list.
- $suggestion->click();
- } else {
- // Press the return key to create a new tag.
- behat_base::type_keys($this->session, [behat_keys::ENTER]);
- }
- $this->wait_for_pending_js();
+ /**
+ * Add a value to the autocomplete.
+ *
+ * @param string $value
+ * @param bool $allowscreation
+ */
+ protected function add_value(string $value, bool $allowscreation): void {
+ $value = trim($value);
- // Press the escape to close the autocomplete suggestions list.
- behat_base::type_keys($this->session, [behat_keys::ESCAPE]);
- $this->wait_for_pending_js();
+ // Click into the field.
+ $this->field->click();
+
+ // Remove any existing text.
+ do {
+ behat_base::type_keys($this->session, [behat_keys::BACKSPACE, behat_keys::DELETE]);
+ } while (strlen($this->field->getValue()) > 0);
+ $this->wait_for_pending_js();
+
+ // Type in the new value.
+ behat_base::type_keys($this->session, str_split($value));
+ $this->wait_for_pending_js();
+
+ // If the autocomplete found suggestions, then it will have:
+ // 1) marked itself as expanded; and
+ // 2) have an aria-selected suggestion in the list.
+ $expanded = $this->field->getAttribute('aria-expanded');
+ $suggestion = $this->field->getParent()->getParent()->find('css', '.form-autocomplete-suggestions > [aria-selected="true"]');
+
+ if ($expanded && null !== $suggestion) {
+ // A suggestion was found.
+ // Click on the first item in the list.
+ $suggestion->click();
+ } else if ($allowscreation) {
+ // Press the return key to create a new entry.
+ behat_base::type_keys($this->session, [behat_keys::ENTER]);
+ } else {
+ throw new \InvalidArgumentException(
+ "Unable to find '{$value}' in the list of options, and unable to create a new option"
+ );
}
+
+ $this->wait_for_pending_js();
+
+ // Press the escape to close the autocomplete suggestions list.
+ behat_base::type_keys($this->session, [behat_keys::ESCAPE]);
+ $this->wait_for_pending_js();
}
}
}}
{{#showSuggestions}}
<div class="d-md-inline-block mr-md-2 position-relative">
- <input type="text" id="{{inputId}}" class="form-control" list="{{suggestionsId}}" placeholder="{{placeholder}}" role="combobox" aria-expanded="false" autocomplete="off" autocorrect="off" autocapitalize="off" aria-autocomplete="list" aria-owns="{{suggestionsId}} {{selectionId}}" {{#tags}}data-tags="1"{{/tags}}/>
+ <input type="text"{{!
+ }} id="{{inputId}}"{{!
+ }} class="form-control"{{!
+ }} list="{{suggestionsId}}"{{!
+ }} placeholder="{{placeholder}}"{{!
+ }} role="combobox"{{!
+ }} aria-expanded="false"{{!
+ }} autocomplete="off"{{!
+ }} autocorrect="off"{{!
+ }} autocapitalize="off"{{!
+ }} aria-autocomplete="list"{{!
+ }} aria-owns="{{suggestionsId}} {{selectionId}}"{{!
+ }} {{#tags}}data-tags="1"{{/tags}}{{!
+ }} {{#multiple}}data-multiple="multiple"{{/multiple}}{{!
+ }}>
<span class="form-autocomplete-downarrow position-absolute p-1" id="{{downArrowId}}">▼</span>
</div>
{{/showSuggestions}}
{{^showSuggestions}}
<div class="d-md-inline-block mr-md-2">
- <input type="text" id="{{inputId}}" class="form-control" placeholder="{{placeholder}}" role="textbox" aria-owns="{{selectionId}}" {{#tags}}data-tags="1"{{/tags}}/>
+ <input type="text"{{!
+ }} id="{{inputId}}"{{!
+ }} class="form-control"{{!
+ }} placeholder="{{placeholder}}"{{!
+ }} role="textbox"{{!
+ }} aria-owns="{{selectionId}}"{{!
+ }} {{#tags}}data-tags="1"{{/tags}}{{!
+ }} {{#multiple}}data-multiple="multiple"{{/multiple}}{{!
+ }}>
</div>
{{/showSuggestions}}