192 lines
5.2 KiB
JavaScript
192 lines
5.2 KiB
JavaScript
import { isEmpty } from "@ember/utils";
|
|
import { on, observes } from "discourse-common/utils/decorators";
|
|
import TextField from "discourse/components/text-field";
|
|
import userSearch from "discourse/lib/user-search";
|
|
import { findRawTemplate } from "discourse/lib/raw-templates";
|
|
|
|
export default TextField.extend({
|
|
autocorrect: false,
|
|
autocapitalize: false,
|
|
name: "user-selector",
|
|
canReceiveUpdates: false,
|
|
single: false,
|
|
fullWidthWrap: false,
|
|
|
|
init() {
|
|
this._super(...arguments);
|
|
|
|
this._paste = e => {
|
|
let pastedText = "";
|
|
if (window.clipboardData && window.clipboardData.getData) {
|
|
// IE
|
|
pastedText = window.clipboardData.getData("Text");
|
|
} else if (e.clipboardData && e.clipboardData.getData) {
|
|
pastedText = e.clipboardData.getData("text/plain");
|
|
}
|
|
|
|
if (pastedText.length > 0) {
|
|
this.importText(pastedText);
|
|
e.preventDefault();
|
|
return false;
|
|
}
|
|
};
|
|
},
|
|
|
|
didUpdateAttrs() {
|
|
this._super(...arguments);
|
|
|
|
if (this.canReceiveUpdates) {
|
|
this._createAutocompleteInstance({ updateData: true });
|
|
}
|
|
},
|
|
|
|
@on("willDestroyElement")
|
|
_destroyAutocompleteInstance() {
|
|
$(this.element).autocomplete("destroy");
|
|
this.element.addEventListener("paste", this._paste);
|
|
},
|
|
|
|
@on("didInsertElement")
|
|
_createAutocompleteInstance(opts) {
|
|
const bool = n => {
|
|
const val = this[n];
|
|
return val === true || val === "true";
|
|
};
|
|
|
|
let selected = [],
|
|
groups = [],
|
|
currentUser = this.currentUser,
|
|
includeMentionableGroups = bool("includeMentionableGroups"),
|
|
includeMessageableGroups = bool("includeMessageableGroups"),
|
|
includeGroups = bool("includeGroups"),
|
|
allowedUsers = bool("allowedUsers"),
|
|
excludeCurrentUser = bool("excludeCurrentUser"),
|
|
single = bool("single"),
|
|
allowAny = bool("allowAny"),
|
|
disabled = bool("disabled"),
|
|
allowEmails = bool("allowEmails"),
|
|
fullWidthWrap = bool("fullWidthWrap");
|
|
|
|
const allExcludedUsernames = () => {
|
|
// hack works around some issues with allowAny eventing
|
|
let usernames = single ? [] : selected;
|
|
|
|
if (currentUser && excludeCurrentUser) {
|
|
usernames.concat([currentUser.username]);
|
|
}
|
|
|
|
return usernames.concat(this.excludedUsernames || []);
|
|
};
|
|
|
|
this.element.addEventListener("paste", this._paste);
|
|
|
|
const userSelectorComponent = this;
|
|
|
|
$(this.element)
|
|
.val(this.usernames)
|
|
.autocomplete({
|
|
template: findRawTemplate("user-selector-autocomplete"),
|
|
disabled,
|
|
single,
|
|
allowAny,
|
|
updateData: opts && opts.updateData ? opts.updateData : false,
|
|
fullWidthWrap,
|
|
|
|
dataSource(term) {
|
|
return userSearch({
|
|
term,
|
|
topicId: userSelectorComponent.topicId,
|
|
exclude: allExcludedUsernames(),
|
|
includeGroups,
|
|
allowedUsers,
|
|
includeMentionableGroups,
|
|
includeMessageableGroups,
|
|
groupMembersOf: userSelectorComponent.groupMembersOf,
|
|
allowEmails
|
|
});
|
|
},
|
|
|
|
transformComplete(v) {
|
|
if (v.username || v.name) {
|
|
if (!v.username) {
|
|
groups.push(v.name);
|
|
}
|
|
return v.username || v.name;
|
|
} else {
|
|
const excludes = allExcludedUsernames();
|
|
return v.usernames.filter(item => excludes.indexOf(item) === -1);
|
|
}
|
|
},
|
|
|
|
onChangeItems(items) {
|
|
let hasGroups = false;
|
|
items = items.map(i => {
|
|
if (groups.indexOf(i) > -1) {
|
|
hasGroups = true;
|
|
}
|
|
return i.username ? i.username : i;
|
|
});
|
|
|
|
let previouslySelected = [];
|
|
if (Array.isArray(userSelectorComponent.usernames)) {
|
|
previouslySelected = userSelectorComponent.usernames;
|
|
} else {
|
|
if (userSelectorComponent.usernames) {
|
|
previouslySelected = userSelectorComponent.usernames.split(",");
|
|
}
|
|
}
|
|
|
|
userSelectorComponent.setProperties({
|
|
usernames: items.join(","),
|
|
hasGroups
|
|
});
|
|
selected = items;
|
|
|
|
if (userSelectorComponent.onChangeCallback) {
|
|
userSelectorComponent.onChangeCallback(
|
|
previouslySelected,
|
|
selected
|
|
);
|
|
}
|
|
},
|
|
|
|
reverseTransform(i) {
|
|
return { username: i };
|
|
}
|
|
});
|
|
},
|
|
|
|
importText(text) {
|
|
let usernames = [];
|
|
if ((this.usernames || "").length > 0) {
|
|
usernames = this.usernames.split(",");
|
|
}
|
|
|
|
(text || "").split(/[, \n]+/).forEach(val => {
|
|
val = val.replace(/^@+/, "").trim();
|
|
if (
|
|
val.length > 0 &&
|
|
(!this.excludedUsernames || !this.excludedUsernames.includes(val))
|
|
) {
|
|
usernames.push(val);
|
|
}
|
|
});
|
|
this.set("usernames", usernames.uniq().join(","));
|
|
|
|
if (!this.canReceiveUpdates) {
|
|
this._createAutocompleteInstance({ updateData: true });
|
|
}
|
|
},
|
|
|
|
// THIS IS A HUGE HACK TO SUPPORT CLEARING THE INPUT
|
|
@observes("usernames")
|
|
_clearInput() {
|
|
if (arguments.length > 1 && isEmpty(this.usernames)) {
|
|
$(this.element)
|
|
.parent()
|
|
.find("a")
|
|
.click();
|
|
}
|
|
}
|
|
});
|