import Vue from "vue";
const EMOJI_REGEX =
/[\u{231A}-\u{231B}\u{23E9}-\u{23FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{2934}-\u{2935}\u{2B05}-\u{2B07}\u{2B1B}-\u{2B1C}\u{2B50}\u{2B55}\u{3030}\u{303D}\u{3297}-\u{3299}\u{1F004}\u{1F0CF}\u{1F170}-\u{1F251}\u{1F300}-\u{1F5FF}\u{1F600}-\u{1F64F}\u{1F680}-\u{1F6FF}\u{1F700}-\u{1F77F}\u{1F780}-\u{1F7FF}\u{1F800}-\u{1F8FF}\u{1F900}-\u{1F9FF}\u{1FA00}-\u{1FAFF}\u{FE00}-\u{FE0F}]/gu;
const HAS_EMOJI_REGEX =
/[\u{231A}-\u{231B}\u{23E9}-\u{23FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{2934}-\u{2935}\u{2B05}-\u{2B07}\u{2B1B}-\u{2B1C}\u{2B50}\u{2B55}\u{3030}\u{303D}\u{3297}-\u{3299}\u{1F004}\u{1F0CF}\u{1F170}-\u{1F251}\u{1F300}-\u{1F5FF}\u{1F600}-\u{1F64F}\u{1F680}-\u{1F6FF}\u{1F700}-\u{1F77F}\u{1F780}-\u{1F7FF}\u{1F800}-\u{1F8FF}\u{1F900}-\u{1F9FF}\u{1FA00}-\u{1FAFF}\u{FE00}-\u{FE0F}]/u;
const elementCache = new WeakMap();
const noEmoji = {
getInputElement(el) {
const cache = elementCache.get(el);
if (cache && cache.input) return cache.input;
const input =
el.querySelector(".el-input__inner") ||
el.querySelector(".el-textarea__inner") ||
el.querySelector("input") ||
el.querySelector("textarea") ||
el;
if (!cache) {
elementCache.set(el, { input });
} else {
cache.input = input;
}
return input;
},
removeEmoji(value) {
if (!value || typeof value !== "string") return value;
if (!HAS_EMOJI_REGEX.test(value)) return value;
return value.replace(EMOJI_REGEX, "");
},
triggerInput(input, value) {
const oldValue = input.value;
if (oldValue === value) return;
input.value = value;
const event = new Event("input", { bubbles: true, cancelable: true });
input.dispatchEvent(event);
},
handleInput(e, directive) {
const input = e.target;
const value = input.value;
if (!value || !HAS_EMOJI_REGEX.test(value)) return;
const cleanedValue = value.replace(EMOJI_REGEX, "");
if (value !== cleanedValue) {
const cursorPos = input.selectionStart;
directive.triggerInput(input, cleanedValue);
Vue.nextTick(() => {
const newPos = Math.min(cursorPos, cleanedValue.length);
if (input.setSelectionRange) {
input.setSelectionRange(newPos, newPos);
}
});
}
},
handlePaste(e, directive) {
const clipboardData = e.clipboardData || window.clipboardData;
if (!clipboardData) return;
const pastedText = clipboardData.getData("text");
if (!pastedText) return;
if (!HAS_EMOJI_REGEX.test(pastedText)) return;
e.preventDefault();
const cleanedText = pastedText.replace(EMOJI_REGEX, "");
if (cleanedText === pastedText) return;
const input = e.target;
const start = input.selectionStart || 0;
const end = input.selectionEnd || 0;
const currentValue = input.value || "";
const newValue =
currentValue.substring(0, start) +
cleanedText +
currentValue.substring(end);
directive.triggerInput(input, newValue);
Vue.nextTick(() => {
const newPos = start + cleanedText.length;
if (input.setSelectionRange) {
input.setSelectionRange(newPos, newPos);
}
});
},
handleComposition(e, directive) {
if (e.type === "compositionstart") {
e.target._isComposing = true;
} else if (e.type === "compositionend") {
e.target._isComposing = false;
Vue.nextTick(() => {
directive.handleInput(e, directive);
});
}
},
inserted(el, binding) {
Vue.nextTick(() => {
const input = noEmoji.getInputElement(el);
if (!input) return;
const handlers = {
input: function (e) {
if (e.target._isComposing) return;
noEmoji.handleInput(e, noEmoji);
},
paste: function (e) {
noEmoji.handlePaste(e, noEmoji);
},
compositionstart: function (e) {
noEmoji.handleComposition(e, noEmoji);
},
compositionend: function (e) {
noEmoji.handleComposition(e, noEmoji);
},
};
input.addEventListener("input", handlers.input, false);
input.addEventListener("paste", handlers.paste, false);
input.addEventListener(
"compositionstart",
handlers.compositionstart,
false
);
input.addEventListener("compositionend", handlers.compositionend, false);
const cache = elementCache.get(el) || {};
cache.handlers = handlers;
elementCache.set(el, cache);
if (input.value && HAS_EMOJI_REGEX.test(input.value)) {
const cleanedValue = noEmoji.removeEmoji(input.value);
if (input.value !== cleanedValue) {
noEmoji.triggerInput(input, cleanedValue);
}
}
});
},
update(el, binding) {
const input = noEmoji.getInputElement(el);
if (!input || !input.value) return;
if (!HAS_EMOJI_REGEX.test(input.value)) return;
const cleanedValue = noEmoji.removeEmoji(input.value);
if (input.value !== cleanedValue) {
noEmoji.triggerInput(input, cleanedValue);
}
},
unbind(el) {
const cache = elementCache.get(el);
if (!cache) return;
const { input, handlers } = cache;
if (input && handlers) {
input.removeEventListener("input", handlers.input);
input.removeEventListener("paste", handlers.paste);
input.removeEventListener("compositionstart", handlers.compositionstart);
input.removeEventListener("compositionend", handlers.compositionend);
}
elementCache.delete(el);
},
};
export default noEmoji;