gemini_prompter / history.js
SenY's picture
管理方法変更
3e76749
function saveToHistory(title) {
if(!title) {
title = document.getElementById('query').value.slice(0, 10);
}
const historyItem = {
query: document.getElementById('query').value,
promptEn: document.getElementById('promptEn').value,
promptMyLanguage: document.getElementById('promptMyLanguage').value,
danbooruTags: document.getElementById('danbooruTags').value,
timestamp: new Date().toISOString(),
title: title
};
let history = JSON.parse(localStorage.getItem('gemini_prompt_history') || '[]');
history.unshift(historyItem);
// 履歴の合計サイズが3MB以下になるまで古い項目を削除
while (JSON.stringify(history).length > 3 * 1024 * 1024) {
history.pop();
}
localStorage.setItem('gemini_prompt_history', JSON.stringify(history));
updateHistoryList();
}
function updateHistoryList() {
const historyList = document.getElementById('historyList');
const noHistoryMessage = document.getElementById('noHistoryMessage');
historyList.innerHTML = '';
const history = JSON.parse(localStorage.getItem('gemini_prompt_history') || '[]');
if (history.length === 0) {
noHistoryMessage.classList.remove('d-none');
historyList.classList.add('d-none');
} else {
noHistoryMessage.classList.add('d-none');
historyList.classList.remove('d-none');
// 容量プログレスバーを追加
const storageUsage = JSON.stringify(history).length;
const storageLimit = 3 * 1024 * 1024; // 3MB
const usagePercentage = (storageUsage / storageLimit) * 100;
const progressBarContainer = document.createElement('div');
progressBarContainer.className = 'mb-3';
progressBarContainer.innerHTML = `
<div class="progress" style="height: 24px; border: 1px solid #dee2e6; position: relative;">
<div class="progress-bar ${usagePercentage > 90 ? 'bg-danger' : 'bg-primary'}" role="progressbar"
style="width: ${usagePercentage}%;" aria-valuenow="${usagePercentage}" aria-valuemin="0" aria-valuemax="100"></div>
<div class="position-absolute w-100 h-100 d-flex align-items-center justify-content-center" style="top: 0; left: 0;">
<span style="color: white; text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;">
${(storageUsage / 1024 / 1024).toFixed(2)}MB / ${storageLimit / 1024 / 1024}MB
</span>
</div>
</div>
`;
historyList.appendChild(progressBarContainer);
// 検索フォームを追加
const searchForm = document.createElement('div');
searchForm.className = 'mb-3';
searchForm.innerHTML = `
<input type="text" class="form-control" id="historySearchInput" placeholder="履歴を検索...">
`;
historyList.appendChild(searchForm);
history.forEach((item, index) => {
const li = document.createElement('li');
li.className = 'list-group-item list-group-item-action d-flex justify-content-between align-items-start';
li.dataset.item = JSON.stringify(item);
const contentDiv = document.createElement('div');
contentDiv.className = 'ms-2 me-auto';
contentDiv.style.cursor = 'pointer';
contentDiv.onclick = () => loadHistoryItem(index);
const titleDiv = document.createElement('div');
titleDiv.className = 'fw-bold text-truncate';
titleDiv.textContent = item.title || item.query.slice(0, 10);
const dateDiv = document.createElement('div');
dateDiv.className = 'small text-muted';
dateDiv.textContent = new Date(item.timestamp).toLocaleString();
contentDiv.appendChild(titleDiv);
contentDiv.appendChild(dateDiv);
const buttonsContainer = document.createElement('div');
buttonsContainer.className = 'd-flex';
const editButton = document.createElement('button');
editButton.className = 'btn btn-secondary btn-sm me-2';
editButton.innerHTML = '<i class="fas fa-pencil-alt"></i>';
editButton.onclick = (e) => {
e.stopPropagation();
editHistoryItemTitle(index, titleDiv);
};
const deleteButton = document.createElement('button');
deleteButton.className = 'btn btn-danger btn-sm';
deleteButton.innerHTML = '<i class="fas fa-trash"></i>';
deleteButton.onclick = (e) => {
e.stopPropagation();
deleteHistoryItem(index);
};
buttonsContainer.appendChild(editButton);
buttonsContainer.appendChild(deleteButton);
li.appendChild(contentDiv);
li.appendChild(buttonsContainer);
historyList.appendChild(li);
contentDiv.style.width = `calc(100% - ${buttonsContainer.offsetWidth}px)`;
});
// 検索機能を追加
const searchInput = document.getElementById('historySearchInput');
searchInput.addEventListener('input', filterHistory);
}
}
function deleteHistoryItem(index) {
if (confirm('Are you sure you want to delete this history item?')) {
let history = JSON.parse(localStorage.getItem('gemini_prompt_history') || '[]');
history.splice(index, 1);
localStorage.setItem('gemini_prompt_history', JSON.stringify(history));
updateHistoryList();
}
}
function loadHistoryItem(index) {
const history = JSON.parse(localStorage.getItem('gemini_prompt_history') || '[]');
const item = history[index];
document.getElementById('query').value = item.query;
document.getElementById('promptEn').value = item.promptEn;
document.getElementById('promptMyLanguage').value = item.promptMyLanguage;
document.getElementById('danbooruTags').value = item.danbooruTags;
saveToUserStorage(true);
}
function clearHistory() {
if (confirm('Are you sure you want to delete all history items?')) {
localStorage.removeItem('gemini_prompt_history');
updateHistoryList();
}
}
function createHistoryItem(item, index) {
const li = document.createElement('li');
li.className = 'list-group-item d-flex justify-content-between align-items-center';
const titleSpan = document.createElement('span');
titleSpan.textContent = item.title || item.query.slice(0, 10);
titleSpan.className = 'me-2';
li.appendChild(titleSpan);
const buttonsContainer = document.createElement('div');
const editButton = document.createElement('button');
editButton.className = 'btn btn-sm btn-secondary me-2';
editButton.innerHTML = '<i class="fas fa-pencil-alt"></i>';
editButton.onclick = () => editHistoryItemTitle(index, titleSpan);
const useButton = document.createElement('button');
useButton.className = 'btn btn-sm btn-primary me-2';
useButton.innerHTML = '<i class="fas fa-redo"></i>';
useButton.onclick = () => useHistoryItem(index);
const deleteButton = document.createElement('button');
deleteButton.className = 'btn btn-sm btn-danger';
deleteButton.innerHTML = '<i class="fas fa-trash"></i>';
deleteButton.onclick = () => {
if (confirm('Are you sure you want to delete this history item?')) {
deleteHistoryItem(index);
}
};
buttonsContainer.appendChild(editButton);
buttonsContainer.appendChild(useButton);
buttonsContainer.appendChild(deleteButton);
li.appendChild(buttonsContainer);
return li;
}
function editHistoryItemTitle(index, titleDiv) {
const history = JSON.parse(localStorage.getItem('gemini_prompt_history') || '[]');
const item = history[index];
const currentTitle = item.title || item.query.slice(0, 10);
const newTitle = prompt('New title:', currentTitle);
if (newTitle !== null && newTitle.trim() !== '') {
item.title = newTitle.trim();
history[index] = item;
localStorage.setItem('gemini_prompt_history', JSON.stringify(history));
titleDiv.textContent = newTitle.trim();
}
}
function filterHistory() {
const searchInput = document.getElementById('historySearchInput');
const searchTerm = searchInput.value.toLowerCase();
const historyItems = document.querySelectorAll('#historyList li[data-item]');
historyItems.forEach(item => {
const itemData = JSON.parse(item.dataset.item);
const searchableText = `${itemData.title} ${itemData.query} ${itemData.promptEn} ${itemData.promptMyLanguage} ${itemData.danbooruTags}`.toLowerCase();
if (searchableText.includes(searchTerm)) {
item.classList.remove('d-none');
} else {
item.classList.add('d-none');
}
});
}