hesabixSite/templates/qa/ask_question.html.twig

696 lines
35 KiB
Twig
Raw Normal View History

2025-09-05 09:37:27 +03:30
{% extends 'base.html.twig' %}
{% block title %}پرسیدن سوال جدید - پرسش و پاسخ{% endblock %}
{% block body %}
2025-09-05 11:52:08 +03:30
<main class="min-h-screen bg-gray-50">
<div class="container mx-auto px-4 py-8">
<div class="max-w-4xl mx-auto">
<!-- هدر فرم -->
<div class="text-center mb-8">
<h1 class="text-3xl lg:text-4xl font-bold text-gray-900 mb-4">
پرسیدن سوال جدید
</h1>
<p class="text-lg text-gray-600">
سوال خود را مطرح کنید تا از تجربه دیگران استفاده کنید
</p>
</div>
<!-- فرم ایجاد سوال -->
<div class="bg-white rounded-2xl shadow-soft overflow-hidden">
<div class="p-8">
{{ form_start(form, {'attr': {'novalidate': 'novalidate', 'class': 'space-y-8'}}) }}
2025-09-05 09:37:27 +03:30
2025-09-05 11:52:08 +03:30
<!-- عنوان سوال -->
<div>
<label for="{{ form.title.vars.id }}" class="block text-sm font-medium text-gray-700 mb-2">
عنوان سوال
</label>
{{ form_widget(form.title, {'attr': {'class': 'w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200'}}) }}
2025-09-05 09:37:27 +03:30
{{ form_errors(form.title) }}
2025-09-05 11:52:08 +03:30
<p class="mt-2 text-sm text-gray-600">
2025-09-05 09:37:27 +03:30
عنوان سوال باید واضح و مختصر باشد. سعی کنید مشکل خود را در یک جمله خلاصه کنید.
2025-09-05 11:52:08 +03:30
</p>
2025-09-05 09:37:27 +03:30
</div>
2025-09-05 11:52:08 +03:30
<!-- محتوای سوال -->
<div>
<label for="{{ form.content.vars.id }}" class="block text-sm font-medium text-gray-700 mb-2">
محتوای سوال
</label>
<!-- نوار ابزار ادیتور -->
<div class="flex flex-wrap gap-2 p-3 bg-gray-50 border border-gray-300 rounded-t-xl">
<button type="button"
onclick="formatText('bold')"
title="پررنگ"
class="p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-200 rounded-lg transition-colors duration-200">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"></path>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"></path>
2025-09-05 09:37:27 +03:30
</svg>
</button>
2025-09-05 11:52:08 +03:30
<button type="button"
onclick="formatText('italic')"
title="کج"
class="p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-200 rounded-lg transition-colors duration-200">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2025-09-05 09:37:27 +03:30
<line x1="19" y1="4" x2="10" y2="4"></line>
<line x1="14" y1="20" x2="5" y2="20"></line>
<line x1="15" y1="4" x2="9" y2="20"></line>
</svg>
</button>
2025-09-05 11:52:08 +03:30
<button type="button"
onclick="formatText('code')"
title="کد"
class="p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-200 rounded-lg transition-colors duration-200">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2025-09-05 09:37:27 +03:30
<polyline points="16,18 22,12 16,6"></polyline>
<polyline points="8,6 2,12 8,18"></polyline>
</svg>
</button>
2025-09-05 11:52:08 +03:30
<button type="button"
onclick="insertList()"
title="لیست"
class="p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-200 rounded-lg transition-colors duration-200">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2025-09-05 09:37:27 +03:30
<line x1="8" y1="6" x2="21" y2="6"></line>
<line x1="8" y1="12" x2="21" y2="12"></line>
<line x1="8" y1="18" x2="21" y2="18"></line>
<line x1="3" y1="6" x2="3.01" y2="6"></line>
<line x1="3" y1="12" x2="3.01" y2="12"></line>
<line x1="3" y1="18" x2="3.01" y2="18"></line>
</svg>
</button>
</div>
2025-09-05 11:52:08 +03:30
{{ form_widget(form.content, {'attr': {'class': 'w-full px-4 py-3 border border-gray-300 border-t-0 rounded-b-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200', 'rows': 10}}) }}
2025-09-05 09:37:27 +03:30
{{ form_errors(form.content) }}
2025-09-05 11:52:08 +03:30
<p class="mt-2 text-sm text-gray-600">
2025-09-05 09:37:27 +03:30
سوال خود را به تفصیل شرح دهید. هرچه جزئیات بیشتری ارائه دهید، پاسخ‌های بهتری دریافت خواهید کرد.
2025-09-05 11:52:08 +03:30
<br><span class="text-gray-500">می‌توانید از دکمه‌های بالا برای فرمت کردن متن استفاده کنید.</span>
</p>
2025-09-05 09:37:27 +03:30
</div>
2025-09-05 11:52:08 +03:30
<!-- تگ‌ها -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">
تگ‌ها
<span class="text-red-500">*</span>
</label>
<div class="border border-gray-300 rounded-xl p-6 bg-gradient-to-br from-gray-50 to-blue-50">
<!-- تگ‌های انتخاب شده -->
<div class="mb-6">
<div class="flex items-center justify-between mb-3">
<h4 class="text-sm font-semibold text-gray-700">تگ‌های انتخاب شده</h4>
<span class="text-xs text-gray-500" id="tag-count">0 تگ انتخاب شده</span>
</div>
<div class="selected-tags min-h-12 flex flex-wrap gap-2 p-3 bg-white rounded-lg border-2 border-dashed border-gray-200" id="selected-tags">
<div class="flex items-center text-gray-400 text-sm">
<svg class="w-4 h-4 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
هیچ تگی انتخاب نشده است
</div>
</div>
</div>
<!-- جستجو و افزودن تگ -->
<div class="mb-6">
<div class="relative">
<input type="text"
class="w-full px-4 py-3 pr-12 border border-gray-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200 text-sm"
id="tag-input"
placeholder="نام تگ را تایپ کنید...">
<button class="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600 transition-colors duration-200"
type="button"
id="search-icon">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
</svg>
</button>
</div>
<div class="flex items-center justify-between mt-3">
<button class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-all duration-200 text-sm font-medium flex items-center space-x-2 space-x-reverse"
type="button"
id="add-tag-btn">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<line x1="12" y1="5" x2="12" y2="19"></line>
<line x1="5" y1="12" x2="19" y2="12"></line>
</svg>
<span>افزودن تگ</span>
</button>
<span class="text-xs text-gray-500">حداقل 1 و حداکثر 5 تگ</span>
</div>
2025-09-05 09:37:27 +03:30
</div>
2025-09-05 11:52:08 +03:30
<!-- تگ‌های پیشنهادی -->
<div>
<div class="flex items-center justify-between mb-3">
<h4 class="text-sm font-semibold text-gray-700">تگ‌های محبوب</h4>
<button class="text-xs text-blue-600 hover:text-blue-800 transition-colors duration-200"
type="button"
id="show-all-tags">
نمایش همه
</button>
</div>
<div class="flex flex-wrap gap-2" id="tag-suggestions">
2025-09-05 09:37:27 +03:30
{% for tag in availableTags %}
2025-09-05 11:52:08 +03:30
<button type="button"
class="inline-flex items-center px-3 py-2 bg-white text-gray-700 text-sm font-medium rounded-full border border-gray-300 hover:bg-blue-50 hover:border-blue-300 hover:text-blue-700 cursor-pointer transition-all duration-200 tag-suggestion"
data-tag-id="{{ tag.id }}"
data-tag-name="{{ tag.name }}">
<svg class="w-3 h-3 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
2025-09-05 09:37:27 +03:30
{{ tag.name }}
2025-09-05 11:52:08 +03:30
</button>
2025-09-05 09:37:27 +03:30
{% endfor %}
</div>
</div>
</div>
2025-09-05 11:52:08 +03:30
<p class="mt-2 text-sm text-gray-600">
2025-09-05 09:37:27 +03:30
تگ‌های مرتبط را انتخاب کنید تا دیگران راحت‌تر بتوانند سوال شما را پیدا کنند.
2025-09-05 11:52:08 +03:30
<br><span class="text-gray-500">می‌توانید تگ جدید ایجاد کنید یا از تگ‌های موجود انتخاب کنید.</span>
</p>
2025-09-05 09:37:27 +03:30
</div>
2025-09-05 11:52:08 +03:30
<!-- دکمه‌های فرم -->
<div class="flex justify-between items-center pt-6 border-t border-gray-200">
<a href="{{ path('qa_index') }}"
class="inline-flex items-center space-x-2 space-x-reverse px-6 py-3 bg-gray-100 text-gray-700 rounded-xl hover:bg-gray-200 transition-all duration-200 font-medium">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 12H5"></path>
2025-09-05 09:37:27 +03:30
<polyline points="12,19 5,12 12,5"></polyline>
2025-09-05 11:52:08 +03:30
</svg>
<span>انصراف</span>
2025-09-05 09:37:27 +03:30
</a>
2025-09-05 11:52:08 +03:30
<button type="submit"
class="inline-flex items-center space-x-2 space-x-reverse px-8 py-3 bg-blue-600 text-white rounded-xl hover:bg-blue-700 transition-all duration-200 font-medium shadow-lg hover:shadow-xl transform hover:-translate-y-0.5">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2025-09-05 09:37:27 +03:30
<line x1="22" y1="2" x2="11" y2="13"></line>
<polygon points="22,2 15,22 11,13 2,9 22,2"></polygon>
2025-09-05 11:52:08 +03:30
</svg>
<span>ارسال سوال</span>
2025-09-05 09:37:27 +03:30
</button>
</div>
{{ form_end(form) }}
</div>
</div>
<!-- راهنمای پرسیدن سوال -->
2025-09-05 11:52:08 +03:30
<div class="bg-white rounded-2xl shadow-soft mt-8 overflow-hidden">
<div class="bg-gradient-to-r from-blue-50 to-purple-50 px-8 py-6">
<h3 class="text-xl font-semibold text-gray-900 flex items-center">
<svg class="w-6 h-6 text-blue-600 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4"></path>
2025-09-05 09:37:27 +03:30
<path d="M21 12c.552 0 1-.448 1-1s-.448-1-1-1-1 .448-1 1 .448 1 1 1z"></path>
<path d="M3 12c.552 0 1-.448 1-1s-.448-1-1-1-1 .448-1 1 .448 1 1 1z"></path>
<path d="M12 3c.552 0 1-.448 1-1s-.448-1-1-1-1 .448-1 1 .448 1 1 1z"></path>
<path d="M12 21c.552 0 1-.448 1-1s-.448-1-1-1-1 .448-1 1 .448 1 1 1z"></path>
2025-09-05 11:52:08 +03:30
</svg>
راهنمای پرسیدن سوال خوب
</h3>
2025-09-05 09:37:27 +03:30
</div>
2025-09-05 11:52:08 +03:30
<div class="p-8">
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<div>
<h4 class="text-lg font-semibold text-green-700 mb-4 flex items-center">
<svg class="w-5 h-5 text-green-600 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
</svg>
کارهای درست
</h4>
<ul class="space-y-3">
<li class="flex items-center space-x-3 space-x-reverse">
<svg class="w-5 h-5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
</svg>
<span class="text-gray-700">عنوان واضح و مختصر</span>
</li>
<li class="flex items-center space-x-3 space-x-reverse">
<svg class="w-5 h-5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
</svg>
<span class="text-gray-700">شرح کامل مشکل</span>
</li>
<li class="flex items-center space-x-3 space-x-reverse">
<svg class="w-5 h-5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
</svg>
<span class="text-gray-700">انتخاب تگ‌های مناسب</span>
</li>
<li class="flex items-center space-x-3 space-x-reverse">
<svg class="w-5 h-5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
</svg>
<span class="text-gray-700">استفاده از کلمات کلیدی</span>
</li>
2025-09-05 09:37:27 +03:30
</ul>
</div>
2025-09-05 11:52:08 +03:30
<div>
<h4 class="text-lg font-semibold text-red-700 mb-4 flex items-center">
<svg class="w-5 h-5 text-red-600 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
کارهای نادرست
</h4>
<ul class="space-y-3">
<li class="flex items-center space-x-3 space-x-reverse">
<svg class="w-5 h-5 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
<span class="text-gray-700">عنوان مبهم</span>
</li>
<li class="flex items-center space-x-3 space-x-reverse">
<svg class="w-5 h-5 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
<span class="text-gray-700">شرح ناکافی</span>
</li>
<li class="flex items-center space-x-3 space-x-reverse">
<svg class="w-5 h-5 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
<span class="text-gray-700">عدم انتخاب تگ</span>
</li>
<li class="flex items-center space-x-3 space-x-reverse">
<svg class="w-5 h-5 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
<span class="text-gray-700">سوال تکراری</span>
</li>
2025-09-05 09:37:27 +03:30
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
2025-09-05 11:52:08 +03:30
</main>
2025-09-05 09:37:27 +03:30
2025-09-05 11:52:08 +03:30
<script>
// سیستم مدیریت تگ‌ها
class TagManager {
constructor() {
this.selectedTags = [];
this.maxTags = 5;
this.minTags = 1;
this.init();
}
2025-09-05 09:37:27 +03:30
2025-09-05 11:52:08 +03:30
init() {
this.tagInput = document.getElementById('tag-input');
this.addTagBtn = document.getElementById('add-tag-btn');
this.selectedTagsContainer = document.getElementById('selected-tags');
this.tagSuggestions = document.querySelectorAll('.tag-suggestion');
this.tagCount = document.getElementById('tag-count');
this.showAllTagsBtn = document.getElementById('show-all-tags');
if (!this.tagInput || !this.addTagBtn || !this.selectedTagsContainer) {
console.error('Required elements not found for tag system');
return;
}
2025-09-05 09:37:27 +03:30
2025-09-05 11:52:08 +03:30
this.bindEvents();
this.updateTagCount();
this.renderSelectedTags();
}
2025-09-05 09:37:27 +03:30
2025-09-05 11:52:08 +03:30
bindEvents() {
// افزودن تگ با دکمه
this.addTagBtn.addEventListener('click', () => this.addTagFromInput());
// افزودن تگ با Enter
this.tagInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
e.preventDefault();
this.addTagFromInput();
}
});
2025-09-05 09:37:27 +03:30
2025-09-05 11:52:08 +03:30
// جستجوی تگ‌ها
this.tagInput.addEventListener('input', () => this.filterSuggestions());
2025-09-05 09:37:27 +03:30
2025-09-05 11:52:08 +03:30
// کلیک روی تگ‌های پیشنهادی
this.tagSuggestions.forEach(suggestion => {
suggestion.addEventListener('click', () => this.toggleTagSuggestion(suggestion));
});
2025-09-05 09:37:27 +03:30
2025-09-05 11:52:08 +03:30
// نمایش همه تگ‌ها
if (this.showAllTagsBtn) {
this.showAllTagsBtn.addEventListener('click', () => this.showAllTags());
}
}
2025-09-05 09:37:27 +03:30
2025-09-05 11:52:08 +03:30
addTag(tagId, tagName) {
// بررسی محدودیت تعداد تگ‌ها
if (this.selectedTags.length >= this.maxTags) {
if (window.notification) {
window.notification.warning(`حداکثر ${this.maxTags} تگ می‌توانید انتخاب کنید`);
}
return false;
}
2025-09-05 09:37:27 +03:30
2025-09-05 11:52:08 +03:30
// بررسی وجود تگ
if (this.selectedTags.find(tag => tag.id === tagId)) {
if (window.notification) {
window.notification.info('این تگ قبلاً انتخاب شده است');
}
return false;
}
2025-09-05 09:37:27 +03:30
2025-09-05 11:52:08 +03:30
this.selectedTags.push({ id: tagId, name: tagName });
this.updateTagCount();
this.renderSelectedTags();
this.updateHiddenInput();
this.updateSuggestionState(tagId, true);
if (window.notification) {
window.notification.success(`تگ "${tagName}" اضافه شد`);
}
return true;
}
2025-09-05 09:37:27 +03:30
2025-09-05 11:52:08 +03:30
removeTag(tagId) {
const tagIndex = this.selectedTags.findIndex(tag => tag.id === tagId);
if (tagIndex === -1) return false;
2025-09-05 09:37:27 +03:30
2025-09-05 11:52:08 +03:30
const removedTag = this.selectedTags[tagIndex];
this.selectedTags.splice(tagIndex, 1);
this.updateTagCount();
this.renderSelectedTags();
this.updateHiddenInput();
this.updateSuggestionState(tagId, false);
if (window.notification) {
window.notification.info(`تگ "${removedTag.name}" حذف شد`);
}
return true;
}
2025-09-05 09:37:27 +03:30
2025-09-05 11:52:08 +03:30
addTagFromInput() {
const tagName = this.tagInput.value.trim();
if (!tagName) {
if (window.notification) {
window.notification.warning('لطفاً نام تگ را وارد کنید');
}
return;
}
2025-09-05 09:37:27 +03:30
2025-09-05 11:52:08 +03:30
// بررسی تگ موجود
const existingTag = Array.from(this.tagSuggestions).find(suggestion =>
suggestion.dataset.tagName.toLowerCase() === tagName.toLowerCase()
);
2025-09-05 09:37:27 +03:30
2025-09-05 11:52:08 +03:30
if (existingTag) {
const tagId = existingTag.dataset.tagId;
const tagName = existingTag.dataset.tagName;
this.addTag(tagId, tagName);
this.tagInput.value = '';
2025-09-05 09:37:27 +03:30
return;
}
2025-09-05 11:52:08 +03:30
// ایجاد تگ جدید
this.createNewTag(tagName);
}
createNewTag(tagName) {
// نمایش حالت بارگذاری
const originalContent = this.addTagBtn.innerHTML;
this.addTagBtn.innerHTML = '<div class="loading-spinner"></div>';
this.addTagBtn.disabled = true;
fetch('/qa/tag/create', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest'
},
body: `name=${encodeURIComponent(tagName)}&_token={{ csrf_token('vote') }}`
})
.then(response => response.json())
.then(data => {
if (data.error) {
if (window.notification) {
window.notification.error(data.error);
}
return;
}
// افزودن تگ جدید
if (this.addTag(data.id, data.name)) {
this.tagInput.value = '';
// افزودن به لیست پیشنهادی
this.addToSuggestions(data.id, data.name);
}
})
.catch(error => {
console.error('Error creating tag:', error);
if (window.notification) {
window.notification.error('خطا در ایجاد تگ جدید. لطفاً دوباره تلاش کنید.');
}
})
.finally(() => {
// بازگردانی دکمه
this.addTagBtn.innerHTML = originalContent;
this.addTagBtn.disabled = false;
});
}
addToSuggestions(tagId, tagName) {
const suggestionElement = document.createElement('button');
suggestionElement.type = 'button';
suggestionElement.className = 'inline-flex items-center px-3 py-2 bg-white text-gray-700 text-sm font-medium rounded-full border border-gray-300 hover:bg-blue-50 hover:border-blue-300 hover:text-blue-700 cursor-pointer transition-all duration-200 tag-suggestion';
suggestionElement.dataset.tagId = tagId;
suggestionElement.dataset.tagName = tagName;
suggestionElement.innerHTML = `
<svg class="w-3 h-3 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
${tagName}
`;
suggestionElement.addEventListener('click', () => this.toggleTagSuggestion(suggestionElement));
2025-09-05 09:37:27 +03:30
2025-09-05 11:52:08 +03:30
const container = document.getElementById('tag-suggestions');
if (container) {
container.appendChild(suggestionElement);
this.tagSuggestions = document.querySelectorAll('.tag-suggestion');
}
2025-09-05 09:37:27 +03:30
}
2025-09-05 11:52:08 +03:30
toggleTagSuggestion(suggestion) {
const tagId = suggestion.dataset.tagId;
const tagName = suggestion.dataset.tagName;
if (this.selectedTags.find(tag => tag.id === tagId)) {
this.removeTag(tagId);
} else {
this.addTag(tagId, tagName);
}
2025-09-05 09:37:27 +03:30
}
2025-09-05 11:52:08 +03:30
updateSuggestionState(tagId, isSelected) {
const suggestion = document.querySelector(`[data-tag-id="${tagId}"]`);
if (!suggestion) return;
if (isSelected) {
suggestion.classList.remove('bg-white', 'text-gray-700', 'border-gray-300');
suggestion.classList.add('bg-blue-600', 'text-white', 'border-blue-600');
} else {
suggestion.classList.remove('bg-blue-600', 'text-white', 'border-blue-600');
suggestion.classList.add('bg-white', 'text-gray-700', 'border-gray-300');
}
}
renderSelectedTags() {
this.selectedTagsContainer.innerHTML = '';
if (this.selectedTags.length === 0) {
this.selectedTagsContainer.innerHTML = `
<div class="flex items-center text-gray-400 text-sm">
<svg class="w-4 h-4 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
هیچ تگی انتخاب نشده است
</div>
`;
return;
}
this.selectedTags.forEach(tag => {
const tagElement = document.createElement('div');
tagElement.className = 'inline-flex items-center px-3 py-2 bg-blue-600 text-white text-sm font-medium rounded-full shadow-sm';
2025-09-05 09:37:27 +03:30
tagElement.innerHTML = `
2025-09-05 11:52:08 +03:30
<svg class="w-3 h-3 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"></path>
</svg>
2025-09-05 09:37:27 +03:30
${tag.name}
2025-09-05 11:52:08 +03:30
<button type="button"
class="tag-remove mr-2 text-white hover:text-red-200 transition-colors duration-200"
data-tag-id="${tag.id}">
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2025-09-05 09:37:27 +03:30
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
`;
2025-09-05 11:52:08 +03:30
// رویداد حذف تگ
2025-09-05 09:37:27 +03:30
const removeBtn = tagElement.querySelector('.tag-remove');
2025-09-05 11:52:08 +03:30
removeBtn.addEventListener('click', () => this.removeTag(tag.id));
this.selectedTagsContainer.appendChild(tagElement);
2025-09-05 09:37:27 +03:30
});
}
2025-09-05 11:52:08 +03:30
updateTagCount() {
if (this.tagCount) {
this.tagCount.textContent = `${this.selectedTags.length} تگ انتخاب شده`;
}
}
updateHiddenInput() {
// حذف input های قبلی
2025-09-05 09:37:27 +03:30
const existingInputs = document.querySelectorAll('input[name="question[tags][]"]');
existingInputs.forEach(input => input.remove());
2025-09-05 11:52:08 +03:30
// افزودن input های جدید
this.selectedTags.forEach(tag => {
2025-09-05 09:37:27 +03:30
const input = document.createElement('input');
input.type = 'hidden';
input.name = 'question[tags][]';
input.value = tag.id;
document.querySelector('form').appendChild(input);
});
}
2025-09-05 11:52:08 +03:30
filterSuggestions() {
const searchTerm = this.tagInput.value.toLowerCase();
this.tagSuggestions.forEach(suggestion => {
const tagName = suggestion.dataset.tagName.toLowerCase();
if (tagName.includes(searchTerm)) {
suggestion.style.display = 'inline-flex';
2025-09-05 09:37:27 +03:30
} else {
2025-09-05 11:52:08 +03:30
suggestion.style.display = 'none';
2025-09-05 09:37:27 +03:30
}
});
2025-09-05 11:52:08 +03:30
}
showAllTags() {
this.tagSuggestions.forEach(suggestion => {
suggestion.style.display = 'inline-flex';
});
this.tagInput.value = '';
}
validateTags() {
if (this.selectedTags.length < this.minTags) {
if (window.notification) {
window.notification.error(`حداقل ${this.minTags} تگ باید انتخاب کنید`);
2025-09-05 09:37:27 +03:30
}
2025-09-05 11:52:08 +03:30
return false;
2025-09-05 09:37:27 +03:30
}
2025-09-05 11:52:08 +03:30
return true;
}
}
// ادیتور متن
class TextEditor {
constructor() {
this.textarea = document.querySelector('textarea[name="question[content]"]');
}
formatText(command) {
if (!this.textarea) return;
const start = this.textarea.selectionStart;
const end = this.textarea.selectionEnd;
const selectedText = this.textarea.value.substring(start, end);
let formattedText = '';
switch(command) {
case 'bold':
formattedText = `**${selectedText}**`;
break;
case 'italic':
formattedText = `*${selectedText}*`;
break;
case 'code':
formattedText = `\`${selectedText}\``;
break;
2025-09-05 09:37:27 +03:30
}
2025-09-05 11:52:08 +03:30
this.textarea.value = this.textarea.value.substring(0, start) + formattedText + this.textarea.value.substring(end);
this.textarea.focus();
this.textarea.setSelectionRange(start + formattedText.length, start + formattedText.length);
2025-09-05 09:37:27 +03:30
}
2025-09-05 11:52:08 +03:30
insertList() {
if (!this.textarea) return;
const start = this.textarea.selectionStart;
const end = this.textarea.selectionEnd;
const selectedText = this.textarea.value.substring(start, end);
const listText = selectedText.split('\n').map(line => `- ${line}`).join('\n');
this.textarea.value = this.textarea.value.substring(0, start) + listText + this.textarea.value.substring(end);
this.textarea.focus();
2025-09-05 09:37:27 +03:30
}
}
2025-09-05 11:52:08 +03:30
// متغیرهای سراسری
let tagManager;
let textEditor;
// توابع سراسری برای HTML
window.formatText = function(command) {
if (textEditor) {
textEditor.formatText(command);
}
};
window.insertList = function() {
if (textEditor) {
textEditor.insertList();
}
};
// مقداردهی اولیه
function initializeQuestionForm() {
if (typeof window.notification === 'undefined') {
setTimeout(initializeQuestionForm, 100);
return;
}
tagManager = new TagManager();
textEditor = new TextEditor();
2025-09-05 09:37:27 +03:30
2025-09-05 11:52:08 +03:30
// اعتبارسنجی فرم
const form = document.querySelector('form');
if (form) {
form.addEventListener('submit', function(e) {
if (!tagManager.validateTags()) {
e.preventDefault();
return false;
}
});
}
2025-09-05 09:37:27 +03:30
}
2025-09-05 11:52:08 +03:30
// اجرا در بارگذاری صفحه
2025-09-05 09:37:27 +03:30
document.addEventListener('DOMContentLoaded', initializeQuestionForm);
document.addEventListener('turbo:load', initializeQuestionForm);
</script>
{% endblock %}