470 lines
21 KiB
Twig
470 lines
21 KiB
Twig
{% extends 'base.html.twig' %}
|
|
|
|
{% block title %}پرسیدن سوال جدید - پرسش و پاسخ{% endblock %}
|
|
|
|
{% block body %}
|
|
<div class="container my-4">
|
|
<div class="row justify-content-center">
|
|
<div class="col-lg-8">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h3 class="mb-0">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="me-2">
|
|
<circle cx="12" cy="12" r="10"></circle>
|
|
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path>
|
|
<line x1="12" y1="17" x2="12.01" y2="17"></line>
|
|
</svg>پرسیدن سوال جدید
|
|
</h3>
|
|
</div>
|
|
<div class="card-body">
|
|
{{ form_start(form, {'attr': {'novalidate': 'novalidate'}}) }}
|
|
|
|
<div class="mb-4">
|
|
{{ form_label(form.title) }}
|
|
{{ form_widget(form.title) }}
|
|
{{ form_errors(form.title) }}
|
|
<div class="form-text">
|
|
عنوان سوال باید واضح و مختصر باشد. سعی کنید مشکل خود را در یک جمله خلاصه کنید.
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-4">
|
|
{{ form_label(form.content) }}
|
|
<div class="editor-toolbar mb-2">
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="formatText('bold')" title="پررنگ">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"></path>
|
|
<path d="M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"></path>
|
|
</svg>
|
|
</button>
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="formatText('italic')" title="کج">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<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>
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="formatText('code')" title="کد">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<polyline points="16,18 22,12 16,6"></polyline>
|
|
<polyline points="8,6 2,12 8,18"></polyline>
|
|
</svg>
|
|
</button>
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="insertList()" title="لیست">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<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>
|
|
{{ form_widget(form.content, {'attr': {'class': 'form-control editor-textarea', 'rows': 10}}) }}
|
|
{{ form_errors(form.content) }}
|
|
<div class="form-text">
|
|
سوال خود را به تفصیل شرح دهید. هرچه جزئیات بیشتری ارائه دهید، پاسخهای بهتری دریافت خواهید کرد.
|
|
<br><small class="text-muted">میتوانید از دکمههای بالا برای فرمت کردن متن استفاده کنید.</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-4">
|
|
<label class="form-label">تگها</label>
|
|
<div class="tags-container">
|
|
<div class="selected-tags mb-2" id="selected-tags"></div>
|
|
<div class="input-group">
|
|
<input type="text" class="form-control" id="tag-input" placeholder="تگ جدید را وارد کنید یا از لیست انتخاب کنید...">
|
|
<button class="btn btn-outline-primary" type="button" id="add-tag-btn">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<line x1="12" y1="5" x2="12" y2="19"></line>
|
|
<line x1="5" y1="12" x2="19" y2="12"></line>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
<div class="available-tags mt-2" id="available-tags">
|
|
<small class="text-muted">تگهای موجود:</small>
|
|
<div class="tag-suggestions mt-1">
|
|
{% for tag in availableTags %}
|
|
<span class="badge bg-light text-dark me-1 mb-1 tag-suggestion" data-tag-id="{{ tag.id }}" data-tag-name="{{ tag.name }}">
|
|
{{ tag.name }}
|
|
</span>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-text">
|
|
تگهای مرتبط را انتخاب کنید تا دیگران راحتتر بتوانند سوال شما را پیدا کنند.
|
|
<br><small class="text-muted">میتوانید تگ جدید ایجاد کنید یا از تگهای موجود انتخاب کنید.</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-flex justify-content-between">
|
|
<a href="{{ path('qa_index') }}" class="btn btn-outline-secondary">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="me-2">
|
|
<path d="M19 12H5"></path>
|
|
<polyline points="12,19 5,12 12,5"></polyline>
|
|
</svg>انصراف
|
|
</a>
|
|
<button type="submit" class="btn btn-primary">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="me-2">
|
|
<line x1="22" y1="2" x2="11" y2="13"></line>
|
|
<polygon points="22,2 15,22 11,13 2,9 22,2"></polygon>
|
|
</svg>ارسال سوال
|
|
</button>
|
|
</div>
|
|
|
|
{{ form_end(form) }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- راهنمای پرسیدن سوال -->
|
|
<div class="card mt-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="me-2">
|
|
<path d="M9 12l2 2 4-4"></path>
|
|
<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>
|
|
</svg>راهنمای پرسیدن سوال خوب
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<h6 class="text-success">✅ کارهای درست:</h6>
|
|
<ul class="list-unstyled">
|
|
<li><i class="fas fa-check text-success me-2"></i>عنوان واضح و مختصر</li>
|
|
<li><i class="fas fa-check text-success me-2"></i>شرح کامل مشکل</li>
|
|
<li><i class="fas fa-check text-success me-2"></i>انتخاب تگهای مناسب</li>
|
|
<li><i class="fas fa-check text-success me-2"></i>استفاده از کلمات کلیدی</li>
|
|
</ul>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<h6 class="text-danger">❌ کارهای نادرست:</h6>
|
|
<ul class="list-unstyled">
|
|
<li><i class="fas fa-times text-danger me-2"></i>عنوان مبهم</li>
|
|
<li><i class="fas fa-times text-danger me-2"></i>شرح ناکافی</li>
|
|
<li><i class="fas fa-times text-danger me-2"></i>عدم انتخاب تگ</li>
|
|
<li><i class="fas fa-times text-danger me-2"></i>سوال تکراری</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.form-control:focus, .form-select:focus {
|
|
border-color: #0d6efd;
|
|
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
|
|
}
|
|
|
|
.card {
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
border: none;
|
|
}
|
|
|
|
.card-header {
|
|
background-color: #f8f9fa;
|
|
border-bottom: 1px solid #dee2e6;
|
|
}
|
|
|
|
.form-text {
|
|
font-size: 0.9rem;
|
|
color: #6c757d;
|
|
}
|
|
|
|
.list-unstyled li {
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.editor-toolbar {
|
|
border: 1px solid #dee2e6;
|
|
border-bottom: none;
|
|
border-radius: 0.375rem 0.375rem 0 0;
|
|
padding: 0.5rem;
|
|
background-color: #f8f9fa;
|
|
}
|
|
|
|
.editor-textarea {
|
|
border-radius: 0 0 0.375rem 0.375rem;
|
|
border-top: none;
|
|
}
|
|
|
|
.tags-container {
|
|
border: 1px solid #dee2e6;
|
|
border-radius: 0.375rem;
|
|
padding: 1rem;
|
|
background-color: #f8f9fa;
|
|
}
|
|
|
|
.selected-tags {
|
|
min-height: 40px;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0.5rem;
|
|
align-items: center;
|
|
}
|
|
|
|
.tag-item {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
background-color: #0d6efd;
|
|
color: white;
|
|
padding: 0.25rem 0.5rem;
|
|
border-radius: 0.375rem;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.tag-remove {
|
|
background: none;
|
|
border: none;
|
|
color: white;
|
|
margin-left: 0.5rem;
|
|
cursor: pointer;
|
|
padding: 0;
|
|
width: 16px;
|
|
height: 16px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.tag-suggestion {
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.tag-suggestion:hover {
|
|
background-color: #0d6efd !important;
|
|
color: white !important;
|
|
}
|
|
|
|
.tag-suggestion.selected {
|
|
background-color: #0d6efd !important;
|
|
color: white !important;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
let selectedTags = [];
|
|
|
|
function initializeQuestionForm() {
|
|
// ادیتور متن
|
|
const textarea = document.querySelector('.editor-textarea');
|
|
|
|
// سیستم تگها
|
|
const tagInput = document.getElementById('tag-input');
|
|
const addTagBtn = document.getElementById('add-tag-btn');
|
|
const selectedTagsContainer = document.getElementById('selected-tags');
|
|
const tagSuggestions = document.querySelectorAll('.tag-suggestion');
|
|
|
|
// اضافه کردن تگ
|
|
function addTag(tagId, tagName) {
|
|
if (selectedTags.find(tag => tag.id === tagId)) {
|
|
return;
|
|
}
|
|
|
|
selectedTags.push({ id: tagId, name: tagName });
|
|
renderSelectedTags();
|
|
updateHiddenInput();
|
|
console.log('Tag added:', { id: tagId, name: tagName });
|
|
}
|
|
|
|
// حذف تگ
|
|
window.removeTag = function(tagId) {
|
|
selectedTags = selectedTags.filter(tag => tag.id !== tagId);
|
|
renderSelectedTags();
|
|
updateHiddenInput();
|
|
}
|
|
|
|
// نمایش تگهای انتخاب شده
|
|
function renderSelectedTags() {
|
|
selectedTagsContainer.innerHTML = '';
|
|
selectedTags.forEach(tag => {
|
|
const tagElement = document.createElement('span');
|
|
tagElement.className = 'tag-item';
|
|
tagElement.innerHTML = `
|
|
${tag.name}
|
|
<button type="button" class="tag-remove" data-tag-id="${tag.id}">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
</svg>
|
|
</button>
|
|
`;
|
|
|
|
// اضافه کردن event listener برای دکمه حذف
|
|
const removeBtn = tagElement.querySelector('.tag-remove');
|
|
removeBtn.addEventListener('click', function() {
|
|
const tagId = this.dataset.tagId;
|
|
window.removeTag(tagId);
|
|
|
|
// حذف کلاس selected از تگ پیشنهادی
|
|
const suggestion = document.querySelector(`[data-tag-id="${tagId}"]`);
|
|
if (suggestion) {
|
|
suggestion.classList.remove('selected');
|
|
}
|
|
});
|
|
selectedTagsContainer.appendChild(tagElement);
|
|
});
|
|
}
|
|
|
|
// بهروزرسانی input مخفی
|
|
function updateHiddenInput() {
|
|
// حذف تمام input های قبلی
|
|
const existingInputs = document.querySelectorAll('input[name="question[tags][]"]');
|
|
existingInputs.forEach(input => input.remove());
|
|
|
|
// اضافه کردن input های جدید
|
|
selectedTags.forEach(tag => {
|
|
const input = document.createElement('input');
|
|
input.type = 'hidden';
|
|
input.name = 'question[tags][]';
|
|
input.value = tag.id;
|
|
document.querySelector('form').appendChild(input);
|
|
});
|
|
|
|
console.log('Selected tags:', selectedTags);
|
|
}
|
|
|
|
// کلیک روی تگهای پیشنهادی
|
|
tagSuggestions.forEach(suggestion => {
|
|
suggestion.addEventListener('click', function() {
|
|
const tagId = this.dataset.tagId;
|
|
const tagName = this.dataset.tagName;
|
|
|
|
if (selectedTags.find(tag => tag.id === tagId)) {
|
|
window.removeTag(tagId);
|
|
this.classList.remove('selected');
|
|
} else {
|
|
addTag(tagId, tagName);
|
|
this.classList.add('selected');
|
|
}
|
|
});
|
|
});
|
|
|
|
// اضافه کردن تگ جدید
|
|
addTagBtn.addEventListener('click', function() {
|
|
const tagName = tagInput.value.trim();
|
|
if (tagName) {
|
|
// بررسی وجود تگ
|
|
const existingTag = Array.from(tagSuggestions).find(suggestion =>
|
|
suggestion.dataset.tagName.toLowerCase() === tagName.toLowerCase()
|
|
);
|
|
|
|
if (existingTag) {
|
|
const tagId = existingTag.dataset.tagId;
|
|
const tagName = existingTag.dataset.tagName;
|
|
addTag(tagId, tagName);
|
|
existingTag.classList.add('selected');
|
|
} else {
|
|
// ایجاد تگ جدید
|
|
createNewTag(tagName);
|
|
}
|
|
|
|
tagInput.value = '';
|
|
}
|
|
});
|
|
|
|
// Enter برای اضافه کردن تگ
|
|
tagInput.addEventListener('keypress', function(e) {
|
|
if (e.key === 'Enter') {
|
|
e.preventDefault();
|
|
addTagBtn.click();
|
|
}
|
|
});
|
|
|
|
// ایجاد تگ جدید
|
|
function createNewTag(tagName) {
|
|
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) {
|
|
alert(data.error);
|
|
return;
|
|
}
|
|
|
|
// اضافه کردن تگ به لیست انتخاب شده
|
|
addTag(data.id, data.name);
|
|
|
|
// اضافه کردن تگ به لیست پیشنهادی
|
|
const suggestionElement = document.createElement('span');
|
|
suggestionElement.className = 'badge bg-light text-dark me-1 mb-1 tag-suggestion selected';
|
|
suggestionElement.dataset.tagId = data.id;
|
|
suggestionElement.dataset.tagName = data.name;
|
|
suggestionElement.textContent = data.name;
|
|
suggestionElement.addEventListener('click', function() {
|
|
if (selectedTags.find(tag => tag.id === data.id)) {
|
|
removeTag(data.id);
|
|
this.classList.remove('selected');
|
|
} else {
|
|
addTag(data.id, data.name);
|
|
this.classList.add('selected');
|
|
}
|
|
});
|
|
|
|
document.querySelector('.tag-suggestions').appendChild(suggestionElement);
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
alert('خطا در ایجاد تگ جدید');
|
|
});
|
|
}
|
|
});
|
|
|
|
// توابع ادیتور متن
|
|
function formatText(command) {
|
|
const textarea = document.querySelector('.editor-textarea');
|
|
const start = textarea.selectionStart;
|
|
const end = textarea.selectionEnd;
|
|
const selectedText = textarea.value.substring(start, end);
|
|
|
|
let formattedText = '';
|
|
|
|
switch(command) {
|
|
case 'bold':
|
|
formattedText = `**${selectedText}**`;
|
|
break;
|
|
case 'italic':
|
|
formattedText = `*${selectedText}*`;
|
|
break;
|
|
case 'code':
|
|
formattedText = `\`${selectedText}\``;
|
|
break;
|
|
}
|
|
|
|
textarea.value = textarea.value.substring(0, start) + formattedText + textarea.value.substring(end);
|
|
textarea.focus();
|
|
textarea.setSelectionRange(start + formattedText.length, start + formattedText.length);
|
|
}
|
|
|
|
function insertList() {
|
|
const textarea = document.querySelector('.editor-textarea');
|
|
const start = textarea.selectionStart;
|
|
const end = textarea.selectionEnd;
|
|
const selectedText = textarea.value.substring(start, end);
|
|
|
|
const listText = selectedText.split('\n').map(line => `- ${line}`).join('\n');
|
|
textarea.value = textarea.value.substring(0, start) + listText + textarea.value.substring(end);
|
|
textarea.focus();
|
|
}
|
|
|
|
// اجرا در هر دو حالت
|
|
document.addEventListener('DOMContentLoaded', initializeQuestionForm);
|
|
document.addEventListener('turbo:load', initializeQuestionForm);
|
|
</script>
|
|
{% endblock %}
|