320 lines
11 KiB
JavaScript
320 lines
11 KiB
JavaScript
await dv.view("scripts/timeline");
|
||
await dv.view("scripts/locations");
|
||
|
||
// Уровень видимости "глобальный" для этого файла
|
||
let locationCounter = 0; // счётчик, если нужно что-то уникальное
|
||
|
||
async function updateTimeline(dv) {
|
||
// Удаляем предыдущую диаграмму
|
||
const oldContainer = dv.container.querySelector(".mermaid-timeline");
|
||
if (oldContainer) {
|
||
oldContainer.remove();
|
||
}
|
||
|
||
const locations = Array.from(dv.container.querySelectorAll(".location")).map(
|
||
(input) => input.value
|
||
);
|
||
const characters = Array.from(
|
||
dv.container.querySelectorAll(".character")
|
||
).map((input) => input.value);
|
||
const currentDate = dv.container.querySelector(".currentDate").value;
|
||
const startDate = dv.container.querySelector(".startDate").value;
|
||
const endDate = dv.container.querySelector(".endDate").value;
|
||
const pcsParticipationOnly = dv.container.querySelector(
|
||
".pcsParticipationOnly"
|
||
).checked;
|
||
const includeRegionsParticipants = dv.container.querySelector(
|
||
".includeRegionsParticipants"
|
||
).checked;
|
||
|
||
// Вызываем рендеринг таймлайна (важно, чтобы dv был виден в этой функции)
|
||
dv.timeline.showTimeline(
|
||
dv,
|
||
locations,
|
||
characters,
|
||
currentDate,
|
||
startDate,
|
||
endDate,
|
||
pcsParticipationOnly,
|
||
includeRegionsParticipants
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Заполняем общий <locationsDataList> всеми заметками.
|
||
*/
|
||
function setupAutocomplete(dv, locationsDataList, tag) {
|
||
// Получаем список всех заметок
|
||
const notes = dv.pages(tag).file.name; // это массив названий файлов
|
||
// Очищаем текущие опции (на случай повторных вызовов)
|
||
locationsDataList.innerHTML = "";
|
||
|
||
notes.forEach((note) => {
|
||
const option = document.createElement("option");
|
||
option.value = note;
|
||
locationsDataList.appendChild(option);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Добавляет новый блок с <input> для локации
|
||
*/
|
||
function addListFormField(container, inputName, dataListName) {
|
||
// locationsDataList
|
||
const div = document.createElement("div");
|
||
div.className = "locationContainer";
|
||
|
||
// Обратите внимание, указываем list="locationsDataList", а <datalist id="locationsDataList">
|
||
// будет один на всю форму
|
||
div.innerHTML = `
|
||
<input type="text" class="${inputName}"
|
||
placeholder="Введите название" list="${dataListName}" />
|
||
<button type="button" class="removeDiv">Удалить</button>
|
||
`;
|
||
|
||
container.appendChild(div);
|
||
|
||
// При удалении блока убираем сам <div>
|
||
div.querySelector(".removeDiv").addEventListener("click", () => {
|
||
div.remove();
|
||
});
|
||
}
|
||
|
||
async function run_show_timeline_widget(...args) {
|
||
let dv = args[0].arg1; // Чтобы не путаться, явно назовём dvParam
|
||
let defaultLocations = args[0].arg2 || [];
|
||
let defaultCurrentDate = args[0].arg3 || "";
|
||
let defaultStartDate = args[0].arg4 || "";
|
||
let defaultEndDate = args[0].arg5 || "";
|
||
let defaultPcsParticipationOnly = args[0].arg6 || false;
|
||
let defaultIncludeRegionsParticipants = args[0].arg7 || false;
|
||
let fullWidth = args[0].arg8 || false;
|
||
|
||
// Добавляем стили для полной ширины (чтобы диаграмму можно было растянуть максимально), если fullWidth = true
|
||
const markdownPreviewSizer = dv.container.closest(
|
||
".markdown-preview-view .markdown-preview-sizer"
|
||
);
|
||
if (markdownPreviewSizer) {
|
||
if (fullWidth) {
|
||
markdownPreviewSizer.style.maxWidth = "none";
|
||
markdownPreviewSizer.style.margin = "0 1em";
|
||
} else {
|
||
markdownPreviewSizer.style.maxWidth = "";
|
||
markdownPreviewSizer.style.margin = "";
|
||
}
|
||
}
|
||
|
||
// Сохраним глобально dv, если нужно использовать вне этой функции
|
||
window.dv = dv;
|
||
|
||
// Формируем HTML формы
|
||
dv.container.innerHTML = `
|
||
<style>
|
||
/* Главный контейнер формы */
|
||
.form-container {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||
gap: 0.5rem;
|
||
max-width: 800px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
/* Контейнер для полей ввода */
|
||
.field-container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.3rem;
|
||
}
|
||
|
||
/* Общий стиль для кнопок */
|
||
button {
|
||
padding: 0.3rem 0.8rem;
|
||
font-size: 0.9rem;
|
||
border: 1px solid #ccc;
|
||
border-radius: 4px;
|
||
background-color: #f9f9f9;
|
||
cursor: pointer;
|
||
}
|
||
|
||
button:hover {
|
||
background-color: #e0e0e0;
|
||
}
|
||
|
||
/* Группы полей */
|
||
.form-group {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.55rem;
|
||
padding: 0.5rem;
|
||
border: 1px solid #eee;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.form-group-2 {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.3em;
|
||
}
|
||
|
||
/* Поля ввода */
|
||
.form-input {
|
||
padding: 0.3rem;
|
||
font-size: 0.9rem;
|
||
border: 1px solid #ccc;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
/* Чекбоксы */
|
||
.form-checkbox {
|
||
margin-left: 0.3rem;
|
||
}
|
||
|
||
/* Кнопки добавления */
|
||
.add-button {
|
||
align-self: flex-start;
|
||
margin-top: 0.3rem;
|
||
}
|
||
|
||
/* Добавьте контейнер для кнопки обновления */
|
||
.update-button-container {
|
||
grid-column: 1 / -1;
|
||
display: flex;
|
||
justify-content: center;
|
||
margin: 0.3rem 0 0.8rem 0;
|
||
}
|
||
|
||
.update-button {
|
||
width: 200px;
|
||
}
|
||
|
||
/* Метки полей */
|
||
label {
|
||
font-size: 0.9rem;
|
||
margin-bottom: 0.2rem;
|
||
}
|
||
|
||
.update-button-container {
|
||
grid-column: 1 / -1;
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 2em;
|
||
margin: 0.3rem 0 0.8rem 0;
|
||
}
|
||
</style>
|
||
|
||
<form id="timelineForm" class="form-container">
|
||
<div class="form-group">
|
||
<div class="form-group-2">
|
||
<label>Локации:</label>
|
||
<div class="locationsContainer field-container"></div>
|
||
<button type="button" class="addLocation add-button">Добавить локацию</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<div class="form-group-2">
|
||
<label>Участвующие персонажи:</label>
|
||
<div class="characters field-container"></div>
|
||
<button type="button" class="addCharacter add-button">Добавить персонажа</button>
|
||
</div>
|
||
<div class="form-group-2">
|
||
<label for="pcsParticipationOnly">Только с участием ИП:</label>
|
||
<input type="checkbox" name="pcsParticipationOnly"
|
||
${
|
||
defaultPcsParticipationOnly ? "checked" : ""
|
||
} class="pcsParticipationOnly form-checkbox" />
|
||
</div>
|
||
<div class="form-group-2">
|
||
<label for="includeRegionsParticipants">Включить regions и participants:</label>
|
||
<input type="checkbox" name="includeRegionsParticipants"
|
||
${
|
||
defaultIncludeRegionsParticipants ? "checked" : ""
|
||
} class="includeRegionsParticipants form-checkbox" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<div class="form-group-2">
|
||
<label for="currentDate">Текущая дата:</label>
|
||
<input type="text" name="currentDate" value="${defaultCurrentDate}" class="currentDate form-input" />
|
||
</div>
|
||
<div class="form-group-2">
|
||
<label for="startDate">Дата начала:</label>
|
||
<input type="text" name="startDate" value="${defaultStartDate}" class="startDate form-input" />
|
||
</div>
|
||
<div class="form-group-2">
|
||
<label for="endDate">Дата окончания:</label>
|
||
<input type="text" name="endDate" value="${defaultEndDate}" class="endDate form-input" />
|
||
</div>
|
||
</div>
|
||
|
||
<datalist id="locationsDataList"></datalist>
|
||
<datalist id="charactersDataList"></datalist>
|
||
|
||
<div class="update-button-container">
|
||
<button type="button" class="updateButton update-button">Обновить график</button>
|
||
<button type="button" class="copyMermaidButton update-button">Копировать mermaid</button>
|
||
</div>
|
||
</form>
|
||
<div class="timelineOutput"></div>
|
||
`;
|
||
|
||
const locationsContainer = dv.container.querySelector(".locationsContainer");
|
||
const addLocationButton = dv.container.querySelector(".addLocation");
|
||
const locationsDataList = dv.container.querySelector("#locationsDataList"); // общий datalist
|
||
|
||
const charactersContainer = dv.container.querySelector(".characters");
|
||
const addCharacterButton = dv.container.querySelector(".addCharacter");
|
||
const charactersDataList = dv.container.querySelector("#charactersDataList"); // общий datalist
|
||
|
||
// Заполним общий datalist всеми заметками (автозаполнение)
|
||
setupAutocomplete(dv, locationsDataList, "#location");
|
||
setupAutocomplete(dv, charactersDataList, "#npc");
|
||
|
||
// Инициализируем поля по умолчанию
|
||
defaultLocations.forEach((location) => {
|
||
addListFormField(locationsContainer, "location", "locationsDataList");
|
||
locationsContainer.lastChild.querySelector(".location").value = location;
|
||
});
|
||
|
||
// Добавляем новое поле по кнопке
|
||
addLocationButton.addEventListener("click", () => {
|
||
addListFormField(locationsContainer, "location", "locationsDataList");
|
||
});
|
||
|
||
// Добавляем новое поле по кнопке
|
||
addCharacterButton.addEventListener("click", () => {
|
||
addListFormField(charactersContainer, "character", "charactersDataList");
|
||
});
|
||
|
||
// Обновляем график при нажатии на кнопку
|
||
dv.container
|
||
.querySelector(".updateButton")
|
||
.addEventListener("click", () => updateTimeline(dv));
|
||
|
||
dv.container
|
||
.querySelector(".copyMermaidButton")
|
||
.addEventListener("click", () => {
|
||
if (window.lastGeneratedMermaidCode) {
|
||
navigator.clipboard
|
||
.writeText(window.lastGeneratedMermaidCode)
|
||
.then(() => {
|
||
// Можно добавить визуальную обратную связь
|
||
const button = dv.container.querySelector(".copyMermaidButton");
|
||
const originalText = button.textContent;
|
||
button.textContent = "Скопировано!";
|
||
setTimeout(() => {
|
||
button.textContent = originalText;
|
||
}, 1000);
|
||
})
|
||
.catch((err) => {
|
||
console.error("Ошибка при копировании: ", err);
|
||
});
|
||
}
|
||
});
|
||
|
||
updateTimeline(dv);
|
||
}
|
||
|
||
await run_show_timeline_widget(input);
|