Показать сообщение отдельно
  #2 (permalink)  
Старый 21.03.2019, 08:32
Аватар для Malleys
Профессор
Отправить личное сообщение для Malleys Посмотреть профиль Найти все сообщения от Malleys
 
Регистрация: 20.12.2009
Сообщений: 1,714

Сообщение от gunner17
При вводе запятой или нажатии клавиши Enter весь введённый текст должен превратиться в тег.
Смотрите пример ниже.

Сообщение от gunner17
По клику на тег, он должен удалиться из текстового поля.
Сделал, чтобы удалялся при долгом нажатии на экран или вызове контекстного меню вторичной кнопкой мыши, поскольку очень легко удаляется при обычном нажатии.

Также можно перемещаться между тегами при помощи стрелок и теги удаляются, как обычный текст, при помощи клавиш BackSpace и Delete.

<body><script>

class TagsField extends HTMLElement {
	constructor() {
		super();
		this.attachShadow({ mode: "open" });
		this.shadowRoot.innerHTML = `
			<style>
				span {
					background-color: #4CAF50;
					color: white;
					text-shadow: 0 1px rgba(0, 0, 0, 0.5);
					box-shadow: 0 0.1em 0.1em rgba(0, 0, 0, 0.2);
					border-radius: 1em;
					padding: 0.45em 0.8em;
					margin: 0.1em;
					display: inline-block;
				}

				label {
					border: 1px solid #ccc;
					border-radius: .5em;
					padding: .5em;
					display: inline-flex;
					font: bolder 100% sans-serif;
					flex-wrap: wrap;
					position: relative;
				}

				label::before {
					content: "Input tags";
					position: absolute;
					pointer-events: none;
					line-height: 0;
					top: 0;
					text-shadow: 2px 0 white, -2px 0 white;
				}

				input {
					all: unset;
					min-width: 5em;
					width: 0;
					padding: 0.45em 0.8em;
					margin: 0.1em;
				}
			</style>
			<label>
				<input>
			</label>
		`;
		this.input = this.shadowRoot.querySelector("input");
		this.label = this.shadowRoot.querySelector("label");
		this.input.value = "\u200b\u200b";

		this.inputHandler = this.inputHandler.bind(this);
		this.contextMenuHandler = this.contextMenuHandler.bind(this);

		"input focus keydown keyup touchstart touchmove click".split(" ").forEach(type => {
			this.input.addEventListener(type, this.inputHandler);
		});
		
		this.label.addEventListener("contextmenu", this.contextMenuHandler);
	}

	inputHandler(event) {		
		if(event.type !== "focus" && event.type !== "click") {
			if(
				this.input.selectionStart === 0 &&
				this.input.selectionEnd === 0
			) {

				if(this.input.previousElementSibling) {
					if(this.input.value.length === 1 || !this.input.value.startsWith("\u200b"))
						this.label.removeChild(this.input.previousElementSibling);
					else
						this.label.insertBefore(
							this.input.previousElementSibling,
							this.input.nextElementSibling
						);
				}
			}

			if(
				this.input.selectionStart === this.input.value.length &&
				this.input.selectionEnd === this.input.value.length
			) {
				if(this.input.nextElementSibling) {
					if(this.input.value.length === 1 || !this.input.value.endsWith("\u200b"))
						this.label.removeChild(this.input.nextElementSibling);
					else
						this.label.insertBefore(
							this.input.nextElementSibling,
							this.input
						);
				}
			}
		}

		var rawTags = this.input.value.slice(1, -1);

		if(event.type === "keyup" && event.key === "Enter") {
			rawTags += ",";
		}

		const tags = rawTags.split(",");
		const editableTag = tags.pop();

		tags.filter(tag => tag).map(this.constructor.createTag).forEach(tag => {
			this.label.insertBefore(tag, this.input);
		});

		this.input.value = `\u200b${editableTag}\u200b`;
		this.input.style.width = "0";
		this.input.style.width = this.input.scrollWidth + "px";
		this.input.selectionStart = Math.max(1, Math.min(this.input.selectionStart, this.input.value.length - 1));
		this.input.selectionEnd = Math.max(1, Math.min(this.input.selectionEnd, this.input.value.length - 1));
	}
	
	contextMenuHandler(event) {
		if(event.target.nodeName === "SPAN") {
			if(confirm("Remove tag?")) {
				event.preventDefault();
				this.label.removeChild(event.target);
			}
		}
	}

	static createTag(tag) {
		const element = document.createElement("span");
		element.textContent = tag;
		return element;
	}

	get tags() {
		return Array.from(this.label.querySelectorAll("span")).map(element => element.textContent);
	}
}

customElements.define("tags-field", TagsField);

// Поле для тегов создаётся программно следующим образом:
let tagField = document.createElement("tags-field");
document.body.append(tagField);

</script>

Последний раз редактировалось Malleys, 23.03.2019 в 01:25.
Ответить с цитированием