<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tag sorter</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
background-color: #f4f4f4;
}
h1 {
color: #333;
}
textarea {
width: 90%;
max-width: 600px;
height: 100px;
margin-bottom: 10px;
padding: 10px;
font-size: 16px;
border: 1px solid #ccc;
border-radius: 5px;
}
.grid {
display: flex;
flex-wrap: wrap;
gap: 10px;
width: 90%;
max-width: 600px;
min-height: 100px;
padding: 10px;
background: #fff;
border: 1px solid #ccc;
border-radius: 5px;
margin-bottom: 10px;
}
.block {
padding: 10px 20px;
background-color: #007BFF;
color: white;
border-radius: 5px;
cursor: grab;
user-select: none;
}
.block.duplicate {
background-color: #FF5733;
}
.placeholder {
width: 40px; /* About 2 characters wide */
height: 20px; /* Matches block height */
background-color: #ffeb3b;
border-radius: 3px;
}
.controls {
display: flex;
gap: 10px;
margin-bottom: 10px;
}
.controls button {
padding: 10px 15px;
background-color: #007BFF;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
.controls button:hover {
background-color: #0056b3;
}
.last-moved {
width: 90%;
max-width: 600px;
padding: 10px;
background: #e8f5e9;
border: 1px solid #a5d6a7;
border-radius: 5px;
font-size: 16px;
color: #388e3c;
}
</style>
</head>
<body>
<h1>Tag sorter</h1>
<textarea id="input" placeholder="Enter comma-separated values here..."></textarea>
<div class="controls">
<button id="copy">Copy to Clipboard</button>
<button id="sort-alpha">Sort Alphabetically</button>
<button id="sort-length">Sort by Length</button>
</div>
<div class="grid" id="grid"></div>
<div class="last-moved" id="lastMoved">Last moved block: <span id="lastMovedText">None</span></div>
<script>
const input = document.getElementById('input');
const grid = document.getElementById('grid');
const copyButton = document.getElementById('copy');
const sortAlphaButton = document.getElementById('sort-alpha');
const sortLengthButton = document.getElementById('sort-length');
const lastMoved = document.getElementById('lastMovedText');
let sortAlphaAscending = true;
let sortLengthAscending = true;
input.addEventListener('input', () => {
const values = input.value.split(',').map(v => v.trim()).filter(v => v);
renderBlocks(values);
});
const renderBlocks = (values) => {
grid.innerHTML = ''; // Clear existing blocks
values.forEach(value => {
const block = document.createElement('div');
block.className = 'block';
block.textContent = value;
block.draggable = true;
// Drag and drop events
block.addEventListener('dragstart', handleDragStart);
block.addEventListener('dragover', handleDragOver);
block.addEventListener('drop', handleDrop);
block.addEventListener('dragend', handleDragEnd);
grid.appendChild(block);
});
updateInput();
};
let draggedElement = null;
let placeholder = null;
let offsetX = 0;
let offsetY = 0;
const handleDragStart = (event) => {
draggedElement = event.target;
// Calculate offset between mouse and block position
const rect = draggedElement.getBoundingClientRect();
offsetX = event.clientX - rect.left;
offsetY = event.clientY - rect.top;
lastMoved.textContent = draggedElement.textContent;
findDuplicates(draggedElement.textContent);
};
const handleDragOver = (event) => {
event.preventDefault(); // Necessary for drop to work
if (!placeholder) {
placeholder = document.createElement('div');
placeholder.className = 'placeholder';
}
const target = event.target;
if (target.className.includes('block') && target !== draggedElement) {
const rect = target.getBoundingClientRect();
const dropPosition = event.clientX - rect.left + offsetX; // Adjust for offset
if (dropPosition < rect.width / 2) {
grid.insertBefore(placeholder, target);
} else {
grid.insertBefore(placeholder, target.nextSibling);
}
}
};
const handleDrop = (event) => {
event.preventDefault();
if (placeholder) {
grid.insertBefore(draggedElement, placeholder);
placeholder.remove();
placeholder = null;
updateInput();
}
};
const handleDragEnd = () => {
if (placeholder) {
placeholder.remove();
placeholder = null;
}
};
const updateInput = () => {
const blocks = Array.from(grid.children).map(block => block.textContent);
input.value = blocks.join(', ');
};
const findDuplicates = (lastMovedText) => {
const words = lastMovedText.split(' ');
const blocks = Array.from(grid.children);
blocks.forEach(block => {
const blockWords = block.textContent.split(' ');
const hasDuplicate = words.some(word => blockWords.includes(word));
block.classList.toggle('duplicate', hasDuplicate);
});
};
// Copy to Clipboard
copyButton.addEventListener('click', () => {
input.select();
document.execCommand('copy');
alert('Copied to clipboard!');
});
// Sort Alphabetically (Toggle between ascending and descending)
sortAlphaButton.addEventListener('click', () => {
const values = input.value.split(',').map(v => v.trim()).filter(v => v);
values.sort((a, b) => sortAlphaAscending ? a.localeCompare(b) : b.localeCompare(a));
sortAlphaAscending = !sortAlphaAscending; // Toggle the sort order
renderBlocks(values);
});
// Sort by Length (Toggle between ascending and descending)
sortLengthButton.addEventListener('click', () => {
const values = input.value.split(',').map(v => v.trim()).filter(v => v);
values.sort((a, b) => sortLengthAscending ? a.length - b.length : b.length - a.length);
sortLengthAscending = !sortLengthAscending; // Toggle the sort order
renderBlocks(values);
});
</script>
</body>
</html>
Comments