Skip to content

Commit

Permalink
pkp/pkp-lib#10624 Move methods from FieldBaseAutosuggest to useAutosu…
Browse files Browse the repository at this point in the history
…ggest API
  • Loading branch information
blesildaramirez committed Dec 2, 2024
1 parent 2c3e46b commit 2fd4c9e
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 135 deletions.
43 changes: 32 additions & 11 deletions src/components/Form/fields/Autosuggest.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@
ref="autosuggestInput"
class="pkpAutosuggest__input"
v-bind="inputProps"
@change="(event) => handleChange(event, emit)"
@focus="() => handleFocus(emit)"
@blur="() => handleBlur(emit)"
@change="(event) => handleChange(event)"
@focus="() => handleFocus()"
@blur="() => handleBlur()"
/>
<ComboboxOptions
v-if="suggestions.length || (allowCustom && localInputValue?.length)"
Expand Down Expand Up @@ -77,7 +77,7 @@
</Combobox>
</template>
<script setup>
import {useSlots} from 'vue';
import {useSlots, ref, inject} from 'vue';
import {
Combobox,
ComboboxInput,
Expand All @@ -86,11 +86,10 @@ import {
} from '@headlessui/vue';
import PkpBadge from '@/components/Badge/Badge.vue';
import Icon from '@/components/Icon/Icon.vue';
import {useAutosuggest} from '@/composables/useAutosuggest';
const slots = useSlots();
defineProps({
const props = defineProps({
id: {
type: String,
required: true,
Expand All @@ -117,14 +116,20 @@ defineProps({
},
isDisabled: {
type: Boolean,
default() {
return false;
},
default: () => false,
},
deselectLabel: {
type: String,
required: true,
},
inputValue: {
type: String,
default: () => '',
},
isFocused: {
type: Boolean,
default: () => false,
},
});
const emit = defineEmits([
Expand All @@ -134,8 +139,24 @@ const emit = defineEmits([
'deselect',
]);
const {allowCustom, localInputValue, handleChange, handleFocus, handleBlur} =
useAutosuggest();
const allowCustom = inject('allowCustom', false);
const localInputValue = ref('');
const localIsFocused = ref(props.isFocused);
function handleChange(event) {
localInputValue.value = event.target.value.trim();
emit('update:inputValue', localInputValue.value);
}
function handleFocus() {
localIsFocused.value = true;
emit('update:isFocused', localIsFocused.value);
}
function handleBlur() {
localIsFocused.value = false;
emit('update:isFocused', localIsFocused.value);
}
function selectSuggestion(suggestion) {
emit('select-suggestion', suggestion);
Expand Down
140 changes: 36 additions & 104 deletions src/components/Form/fields/FieldBaseAutosuggest.vue
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,10 @@
v-bind="autoSuggestProps"
ref="cb"
v-model:inputValue="inputValue"
v-model:suggestions="suggestions"
v-model:isFocused="isFocused"
v-model:currentSelected="currentSelected"
v-model:currentValue="currentValue"
@select-suggestion="selectSuggestion"
@deselect="deselect"
>
Expand Down Expand Up @@ -116,16 +119,17 @@
</template>

<script>
import {reactive} from 'vue';
import FieldBase from './FieldBase.vue';
import Autosuggest from './Autosuggest.vue';
import FormFieldLabel from '@/components/Form/FormFieldLabel.vue';
import Tooltip from '@/components/Tooltip/Tooltip.vue';
import HelpButton from '@/components/HelpButton/HelpButton.vue';
import FieldError from '@/components/Form/FieldError.vue';
import MultilingualProgress from '@/components/MultilingualProgress/MultilingualProgress.vue';
import {useAutosuggest} from '@/composables/useAutosuggest';
import ajaxError from '@/mixins/ajaxError';
import debounce from 'debounce';
export default {
name: 'FieldBaseAutosuggest',
Expand Down Expand Up @@ -267,27 +271,45 @@ export default {
var direction = document.body.getAttribute('dir');
return direction === 'rtl';
},
autoSuggestProps() {
return {
id: this.autosuggestId,
inputProps: this.inputProps,
suggestions: this.suggestions,
selectedLabel: this.selectedLabel,
currentValue: this.currentValue,
currentSelected: this.currentSelected,
isDisabled: this.isDisabled,
deselectLabel: this.deselectLabel,
};
},
},
watch: {
inputValue(newVal, oldVal) {
if (newVal === oldVal) {
return;
}
this.getSuggestions();
this.state.inputValue = newVal;
this.getSuggestions(this.getParams);
},
},
created() {
const opts = {
id: this.autosuggestId,
inputProps: this.inputProps,
suggestions: this.suggestions,
selectedLabel: this.selectedLabel,
isMultiple: this.isMultiple,
currentValue: this.currentValue,
name: this.name,
isDisabled: this.isDisabled,
deselectLabel: this.deselectLabel,
apiUrl: this.apiUrl,
isMultilingual: this.isMultilingual,
};
this.state = reactive({
inputValue: this.inputValue,
currentSelected: this.currentSelected,
});
const {autoSuggestProps, getSuggestions, selectSuggestion, deselect} =
useAutosuggest(this.state, opts, this.$emit, this.setSuggestions);
this.autoSuggestProps = autoSuggestProps;
this.getSuggestions = getSuggestions;
this.selectSuggestion = selectSuggestion;
this.deselect = deselect;
},
mounted() {
// Inline labels can not be used with multilingual fields
if (this.isMultilingual && this.isLabelInline) {
Expand All @@ -298,20 +320,6 @@ export default {
}
},
methods: {
/**
* Remove an item from the selected list
*
* @param {Object} itemToRemove
*/
deselect(itemToRemove) {
let newSelected = [...this.currentSelected];
newSelected.splice(
newSelected.findIndex((item) => item.value === itemToRemove.value),
1,
);
this.setSelected(newSelected);
},
/**
* Move focus to the input field
*/
Expand All @@ -323,82 +331,6 @@ export default {
this.$refs.cb.$refs.autosuggestInput.$el.focus();
},
/**
* Get suggestions from the API url
*/
getSuggestions: debounce(function () {
if (!this.inputValue) {
this.suggestions = [];
return;
}
var self = this;
$.ajax({
url: this.apiUrl,
type: 'GET',
data: {
...this.getParams,
searchPhrase: this.inputValue,
},
error(r) {
self.ajaxErrorCallback(r);
},
success(r) {
self.setSuggestions(r.items);
},
});
}, 250),
/**
* Add a suggested item to the list of selected items
*
* This method may be called without a null item argument
* when the user types into the field and hits enter. In
* such cases, select the first autosuggestion result if
* one exists
*
* @param {Object|null} item The item that was selected
*/
select(item) {
if (!item) {
if (!this.inputValue || !this.suggestions.length) {
return;
}
item = this.suggestions[0];
}
this.setSelected([...this.currentSelected, item]);
this.inputValue = '';
},
/**
* Respond to selected events from vue-autosuggest
*
* This wrapper passes the selected item to the select method.
*
* @param {Object|null} suggestion
*/
selectSuggestion(suggestion) {
this.select(suggestion ? suggestion : null);
},
/**
* Emit events to change the selected items and the field's value
*/
setSelected(selected) {
if (selected?.length > 1 && !this.isMultiple) {
// override selected value if only one option can be selected
selected = [selected[1]];
}
this.$emit('change', this.name, 'selected', selected, this.localeKey);
this.$emit(
'change',
this.name,
'value',
selected.map((s) => s.value),
this.localeKey,
);
},
/**
* This must be implemented in a component that extends
* this component
Expand Down
Loading

0 comments on commit 2fd4c9e

Please sign in to comment.