Ghost-Admin/app/components/gh-member-label-input.js

109 lines
3.3 KiB
JavaScript

import Component from '@glimmer/component';
import {action} from '@ember/object';
import {inject as service} from '@ember/service';
export default class GhMemberLabelInput extends Component {
@service store;
get availableLabels() {
return this._availableLabels.toArray().sort((labelA, labelB) => {
return (labelA.name || '').localeCompare((labelB.name || ''), undefined, {ignorePunctuation: true});
});
}
get availableLabelNames() {
return this.availableLabels.map(label => label.name.toLowerCase());
}
constructor(...args) {
super(...args);
// perform a background query to fetch all users and set `availableLabels`
// to a live-query that will be immediately populated with what's in the
// store and be updated when the above query returns
this.store.query('label', {limit: 'all'});
this._availableLabels = this.store.peekAll('label');
}
get selectedLabels() {
if (typeof this.args.labels === 'object') {
if (this.args.labels?.length && typeof this.args.labels[0] === 'string') {
return this.args.labels.map((d) => {
return this.availableLabels.find(label => label.slug === d);
}) || [];
}
return this.args.labels || [];
}
return [];
}
willDestroy() {
super.willDestroy?.(...arguments);
this._availableLabels.forEach((label) => {
if (label.get('isNew')) {
this.store.deleteRecord(label);
}
});
}
@action
hideCreateOptionOnMatchingLabel(term) {
return !this.availableLabelNames.includes(term.toLowerCase());
}
@action
updateLabels(newLabels) {
let currentLabels = this.selectedLabels;
// destroy new+unsaved labels that are no longer selected
currentLabels.forEach(function (label) {
if (!newLabels.includes(label) && label.get('isNew')) {
label.destroyRecord();
}
});
// update labels
this.args.onChange(newLabels);
}
@action
editLabel(label, event) {
event.stopPropagation();
this.args.onLabelEdit?.(label.slug);
}
@action
createLabel(labelName) {
let currentLabels = this.selectedLabels;
let currentLabelNames = currentLabels.map(label => label.get('name').toLowerCase());
let labelToAdd;
labelName = labelName.trim();
// abort if label is already selected
if (currentLabelNames.includes(labelName.toLowerCase())) {
return;
}
// find existing label if there is one
labelToAdd = this._findLabelByName(labelName);
// create new label if no match
if (!labelToAdd) {
labelToAdd = this.store.createRecord('label', {
name: labelName
});
}
// push label onto member relationship
currentLabels.pushObject(labelToAdd);
this.args.onChange(currentLabels);
}
_findLabelByName(name) {
let withMatchingName = function (label) {
return label.name.toLowerCase() === name.toLowerCase();
};
return this.availableLabels.find(withMatchingName);
}
}