ckeditor_taxonomy_glossary-1.0.0-alpha1/js/ckeditor5_plugins/glossaryLink/src/autocomplete.js

js/ckeditor5_plugins/glossaryLink/src/autocomplete.js
(($, Drupal, once) => {
	/**
	 * Glossary autocomplete utilities.
	 */
	Drupal.glossaryAutocomplete = Drupal.glossaryAutocomplete || {};

	/**
	 * Shows a modal for creating a new term.
	 */
	Drupal.glossaryAutocomplete.showCreateTermModal = (termName, $input) => {
		// Check if site is multilingual and get available languages
		const isMultilingual = typeof drupalSettings !== "undefined" && 
			drupalSettings.path && 
			drupalSettings.path.currentLanguage && 
			drupalSettings.language && 
			Object.keys(drupalSettings.language).length > 1;

		const currentLanguage = (typeof drupalSettings !== "undefined" && drupalSettings.path && drupalSettings.path.currentLanguage) 
			? drupalSettings.path.currentLanguage 
			: 'en';
		
		// Build language selector HTML if multilingual
		let languageSelectorHtml = '';
		if (isMultilingual && drupalSettings.language) {
			const languageOptions = Object.keys(drupalSettings.language)
				.map(langcode => {
					const language = drupalSettings.language[langcode];
					const selected = langcode === currentLanguage ? 'selected' : '';
					return `<option value="${langcode}" ${selected}>${language.name} (${langcode.toUpperCase()})</option>`;
				})
				.join('');
			
			languageSelectorHtml = `
				<div class="form-item">
					<label for="new-term-language">${Drupal.t("Language")}</label>
					<select id="new-term-language">
						${languageOptions}
					</select>
				</div>
			`;
		}

		// Create modal HTML
		const modalHtml = `
      <div id="glossary-create-modal" class="glossary-modal-overlay">
        <div class="glossary-modal">
          <div class="glossary-modal-header">
            <h3>${Drupal.t("Create New Glossary Term")}</h3>
            <button type="button" class="glossary-modal-close">&times;</button>
          </div>
          <div class="glossary-modal-body">
            <div class="form-item">
              <label for="new-term-name">${Drupal.t("Term Name")} *</label>
              <input type="text" id="new-term-name" value="" required maxlength="255" />
            </div>
            <div class="form-item">
              <label for="new-term-description">${Drupal.t("Description")}</label>
              <textarea id="new-term-description" rows="3" maxlength="500" placeholder="${Drupal.t("Optional description for this term")}"></textarea>
            </div>
            ${languageSelectorHtml}
            <div class="glossary-modal-messages"></div>
          </div>
          <div class="glossary-modal-footer">
            <button type="button" class="btn btn-primary" id="create-term-submit">${Drupal.t("Create Term")}</button>
            <button type="button" class="btn btn-secondary glossary-modal-cancel">${Drupal.t("Cancel")}</button>
          </div>
        </div>
      </div>
    `;

		// Add modal to page
		$("body").append(modalHtml);
		const $modal = $("#glossary-create-modal");

		// Store current scroll position and prevent body scrolling
		const scrollTop = $(window).scrollTop();
		$("body").addClass("glossary-modal-open").css("top", `${-scrollTop}px`);
		$("body").data("scroll-top", scrollTop);

		// Safely set the term name value after DOM creation
		$("#new-term-name").val(termName).focus().select();

		// Prevent modal from closing when clicking inside the modal content
		$modal.find(".glossary-modal").on("click", (e) => {
			e.stopPropagation();
		});

		// Function to close modal and restore body state
		const closeModal = () => {
			const scrollTop = $("body").data("scroll-top") || 0;
			$("body")
				.removeClass("glossary-modal-open")
				.css("top", "")
				.removeData("scroll-top");
			$(window).scrollTop(scrollTop);
			$modal.remove();
		};

		// Handle close buttons
		$modal
			.find(".glossary-modal-close, .glossary-modal-cancel")
			.on("click", closeModal);

		$modal.on("click", function (e) {
			// Only close if clicking directly on the overlay (not on modal content)
			if (e.target === this) {
				closeModal();
			}
		});

		// Handle form submission
		$("#create-term-submit").on("click", function () {
			const name = $("#new-term-name").val().trim();
			const description = $("#new-term-description").val().trim();
			const selectedLanguage = $("#new-term-language").length ? $("#new-term-language").val() : currentLanguage;

			if (!name) {
				Drupal.glossaryAutocomplete.showModalMessage(
					Drupal.t("Term name is required"),
					"error",
				);
				return;
			}

			// Disable button and show loading
			$(this).prop("disabled", true).text(Drupal.t("Creating..."));

			// Create the term
			$.ajax({
				url: "/glossary/create-term",
				method: "POST",
				contentType: "application/json",
				headers: { 'X-CSRF-Token': drupalSettings.csrfToken },
				data: JSON.stringify({
					name: name,
					description: description,
					langcode: selectedLanguage,
				}),
				success: (response) => {
					if (response.success && response.term) {
						// Set the new term in the input
						$input.data("glossary-id", response.term.id);
						$input.val(`${response.term.name} (${response.term.id})`);

						// Close modal
						closeModal();

						// Get the CKEditor instance and execute the glossaryLink command
						const editor = $input.data("ckeditor-instance");
						const uiInstance = $input.data("ui-instance");

						if (editor && uiInstance) {
							// Execute the glossaryLink command to create the link
							editor.execute("glossaryLink", response.term.id);
							// Hide the form
							uiInstance._hideForm();
						}

						// Show success message
						Drupal.announce(
							Drupal.t(
								'Glossary term "@name" created and linked successfully.',
								{ "@name": response.term.name },
							),
						);
					} else {
						Drupal.glossaryAutocomplete.showModalMessage(
							Drupal.t("Failed to create term"),
							"error",
						);
					}
				},
				error: (xhr) => {
					let errorMsg = Drupal.t("Failed to create term");
					if (xhr.responseJSON?.error) {
						errorMsg = xhr.responseJSON.error;

						// Handle existing term case
						if (xhr.status === 409 && xhr.responseJSON.existing_term) {
							const existingTerm = xhr.responseJSON.existing_term;
							errorMsg += Drupal.t(". Use existing term?");

							const useExistingHtml = `
                <div class="existing-term-option">
                  <button type="button" class="btn btn-link" id="use-existing-term" 
                          data-term-id="${existingTerm.id}" data-term-name="${existingTerm.name}">
                    ${Drupal.t('Use "@name" (ID: @id)', { "@name": existingTerm.name, "@id": existingTerm.id })}
                  </button>
                </div>
              `;

							$(".glossary-modal-messages").append(useExistingHtml);

							$("#use-existing-term").on("click", function () {
								const termId = $(this).data("term-id");
								const termName = $(this).data("term-name");

								$input.data("glossary-id", termId);
								$input.val(`${termName} (${termId})`);
								closeModal();

								// Get the CKEditor instance and execute the glossaryLink command
								const editor = $input.data("ckeditor-instance");
								const uiInstance = $input.data("ui-instance");

								if (editor && uiInstance) {
									// Execute the glossaryLink command to create the link
									editor.execute("glossaryLink", termId);
									// Hide the form
									uiInstance._hideForm();
								}
							});
						}
					}

					Drupal.glossaryAutocomplete.showModalMessage(errorMsg, "error");
					$(this).prop("disabled", false).text(Drupal.t("Create Term"));
				},
			});
		});
	};

	/**
	 * Shows a message in the modal.
	 */
	Drupal.glossaryAutocomplete.showModalMessage = (message, type = "info") => {
		const $messages = $(".glossary-modal-messages");
		$messages.empty();

		const alertClass = type === "error" ? "alert-danger" : "alert-success";
		const messageHtml = `<div class="alert ${alertClass}">${message}</div>`;

		$messages.html(messageHtml);
	};
})(jQuery, Drupal, once);

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc