Hello World!Second Scroll1.2.11.8.2 goes here1.13.3 goes here1.4.14.31.5.4 goes here1.5.31.6.31.5.6 goes here1.7.51.8.38.51.10.31.10.51.13.31.16.131.24.15Message for you, mortrix<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="stylesheet" href="/api/v2/select?p=basic&c=2.2.2/2.2.2/2.2.3&f=style.css">
<script src="/api/v2/select?p=basic&c=2.2.2/2.2.2/2.2.2&f=main.js" defer></script>
</head>
<body>
<div id="grid-container">
<div id="grid"></div>
</div>
<div id="instructions-display">
<ul>
<li>Double-tap to create a scroll.</li>
<li>Tap on a scroll to edit or delete it.</li>
<li>Drag on the grid to move around.</li>
</ul>
</div>
<div id="coordinates-display"></div>
<div id="modal-overlay"></div>
<div id="scroll-modal">
<div id="scroll-coordinates"></div>
<textarea id="scroll-content" rows="20" cols="110"></textarea>
<div class="modal-buttons">
<button onclick="delete_scroll()" class="danger">Delete</button>
<button onclick="close_modal()">Cancel</button>
<button onclick="save_scroll()" class="primary">Save</button>
</div>
</div>
</body>
</html>
const GRID_SIZE = 1000;
const CELL_SIZE = 150;
let grid_offset = { x: 0, y: 0 };
let is_dragging = false;
let start_pos = { x: 0, y: 0 };
let scrolls = new Map();
let current_scroll = null;
function dgid(id) {
return document.getElementById(id);
}
const grid = dgid('grid');
const container = dgid('grid-container');
const modal = dgid('scroll-modal');
const modal_overlay = dgid('modal-overlay');
const coordinates_display = dgid('coordinates-display');
const scroll_content = dgid('scroll-content');
function initialize_grid() {
grid_offset.x = 0;
grid_offset.y = 0;
grid.style.transform = `translate(${grid_offset.x}px, ${grid_offset.y}px)`;
render_visible_cells();
}
function update_grid_position() {
grid.style.transform = `translate(${grid_offset.x}px, ${grid_offset.y}px)`;
}
function render_visible_cells() {
grid.innerHTML = '';
const start_x = Math.floor(-grid_offset.x / CELL_SIZE);
const start_y = Math.floor(-grid_offset.y / CELL_SIZE);
const end_x = start_x + Math.ceil(window.innerWidth / CELL_SIZE) + 1;
const end_y = start_y + Math.ceil(window.innerHeight / CELL_SIZE) + 1;
for (let x = Math.max(start_x, 0); x < Math.min(end_x, GRID_SIZE); x++) {
for (let y = Math.max(start_y, 0); y < Math.min(end_y, GRID_SIZE); y++) {
const scroll_content = scrolls.get(`${x + 1},${y + 1}`);
if (scroll_content) {
render_scroll(x, y, scroll_content);
}
}
}
}
function render_scroll(x, y, content) {
const scroll = document.createElement('div');
scroll.className = 'scroll';
scroll.style.left = `${x * CELL_SIZE}px`;
scroll.style.top = `${y * CELL_SIZE}px`;
scroll.textContent = content;
scroll.onclick = (e) => {
e.stopPropagation();
open_modal(x + 1, y + 1, content);
};
grid.appendChild(scroll);
}
function open_modal(x, y, content = '') {
current_scroll = { x, y };
dgid('scroll-coordinates').innerHTML = `<span style="color: #888">1.1.1/1.1.1/1.</span>${x}.${y}`;
scroll_content.value = content;
if (content.length == 0) {
fetchScroll(x, y);
} else {
modal.style.display = 'block';
modal_overlay.style.display = 'block';
scroll_content.focus();
}
}
async function fetchScroll(x, y) {
try
{
const coordinate = `1.1.1/1.1.1/1.${x}.${y}`;
const select_url = `/api/v2/select?p=basic&c=${coordinate}`;
const response = await fetch(select_url);
const content = await response.text();
console.log(`Content: ${content}`);
scroll_content.value = content;
modal.style.display = 'block';
modal_overlay.style.display = 'block';
scroll_content.focus();
} catch (error) {}
}
function close_modal() {
modal.style.display = 'none';
modal_overlay.style.display = 'none';
current_scroll = null;
}
function save_scroll() {
const content = dgid('scroll-content').value.trim();
if (content && current_scroll) {
scrolls.set(`${current_scroll.x},${current_scroll.y}`, content);
const coordinate = `1.1.1/1.1.1/1.${current_scroll.x}.${current_scroll.y}`;
const push_url = `/api/v2/update?p=basic&c=${coordinate}&s=${content}`;
fetch(push_url);
render_visible_cells();
}
close_modal();
}
function delete_scroll() {
if (current_scroll) {
scrolls.delete(`${current_scroll.x},${current_scroll.y}`);
render_visible_cells();
}
close_modal();
}
container.addEventListener('mousedown', (e) => {
if (e.target === container || e.target === grid) {
is_dragging = true;
container.classList.add('grabbing');
start_pos = {
x: e.clientX - grid_offset.x,
y: e.clientY - grid_offset.y
};
}
});
container.addEventListener('dblclick', (e) => {
if (e.target === container || e.target === grid) {
const rect = container.getBoundingClientRect();
const x = Math.floor((e.clientX - rect.left - grid_offset.x) / CELL_SIZE);
const y = Math.floor((e.clientY - rect.top - grid_offset.y) / CELL_SIZE);
if (x >= 0 && x < GRID_SIZE && y >= 0 && y < GRID_SIZE) {
open_modal(x + 1, y + 1);
}
}
});
window.addEventListener('mousemove', (e) => {
if (is_dragging) {
grid_offset.x = e.clientX - start_pos.x;
grid_offset.y = e.clientY - start_pos.y;
const min_x = -GRID_SIZE * CELL_SIZE + window.innerWidth;
const min_y = -GRID_SIZE * CELL_SIZE + window.innerHeight;
grid_offset.x = Math.min(0, Math.max(min_x, grid_offset.x));
grid_offset.y = Math.min(0, Math.max(min_y, grid_offset.y));
update_grid_position();
render_visible_cells();
}
});
window.addEventListener('mouseup', () => {
is_dragging = false;
container.classList.remove('grabbing');
});
window.addEventListener('resize', () => {
render_visible_cells();
});
container.addEventListener('mousemove', (e) => {
const rect = container.getBoundingClientRect();
const x = Math.floor((e.clientX - rect.left - grid_offset.x) / CELL_SIZE);
const y = Math.floor((e.clientY - rect.top - grid_offset.y) / CELL_SIZE);
if (x >= 0 && x < GRID_SIZE && y >= 0 && y < GRID_SIZE) {
coordinates_display.innerHTML = `<span style="color: #888">1.1.1/1.1.1/1.</span>${x + 1}.${y + 1}`;
} else {
coordinates_display.textContent = 'Out of bounds';
}
});
container.addEventListener('touchstart', (e) => {
if (e.target === container || e.target === grid) {
is_dragging = true;
container.classList.add('grabbing');
const touch = e.touches[0];
start_pos = {
x: touch.clientX - grid_offset.x,
y: touch.clientY - grid_offset.y
};
}
});
container.addEventListener('touchmove', (e) => {
e.preventDefault();
const touch = e.touches[0];
if (is_dragging) {
grid_offset.x = touch.clientX - start_pos.x;
grid_offset.y = touch.clientY - start_pos.y;
const min_x = -GRID_SIZE * CELL_SIZE + window.innerWidth;
const min_y = -GRID_SIZE * CELL_SIZE + window.innerHeight;
grid_offset.x = Math.min(0, Math.max(min_x, grid_offset.x));
grid_offset.y = Math.min(0, Math.max(min_y, grid_offset.y));
update_grid_position();
render_visible_cells();
}
});
let last_tap = 0;
container.addEventListener('touchend', (e) => {
const current_time = new Date().getTime();
const tap_length = current_time - last_tap;
if (tap_length < 500 && tap_length > 0) {
if (e.target === container || e.target === grid) {
const touch = e.changedTouches[0];
const rect = container.getBoundingClientRect();
const x = Math.floor((touch.clientX - rect.left - grid_offset.x) / CELL_SIZE);
const y = Math.floor((touch.clientY - rect.top - grid_offset.y) / CELL_SIZE);
if (x >= 0 && x < GRID_SIZE && y >= 0 && y < GRID_SIZE) {
open_modal(x + 1, y + 1);
}
}
}
last_tap = current_time;
is_dragging = false;
container.classList.remove('grabbing');
});
container.addEventListener('touchcancel', () => {
is_dragging = false;
container.classList.remove('grabbing');
});
initialize_grid();
body {
margin: 0;
overflow: hidden;
font-family: Arial, sans-serif;
}
ul {
margin: 0;
padding-left: 1rem;
}
#grid-container {
position: relative;
width: 100vw;
height: 100vh;
overflow: hidden;
cursor: grab;
background: #242429;
}
#grid-container.grabbing {
cursor: grabbing;
}
#grid {
position: absolute;
transform-origin: 0 0;
width: 150000px; /* GRID_SIZE * CELL_SIZE */
height: 150000px;
background-image:
linear-gradient(to right, #eee 1px, transparent 1px),
linear-gradient(to bottom, #eee 1px, transparent 1px);
background-size: 150px 150px;
background-position: -1px -1px;
user-select: none;
}
.scroll {
position: absolute;
width: 280px;
height: 280px;
background: #f9f3e6;
border: 1px solid #dcc;
border-radius: 5px;
padding: 5px;
cursor: pointer;
overflow: hidden;
word-break: break-all;
box-sizing: border-box;
margin: 2px;
}
#scroll-modal {
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #fff;
padding: 1rem;
border-radius: 0.5rem;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
box-sizing: border-box;
}
#scroll-content {
overflow-y: scroll;
resize: none;
padding: .5rem;
font-family: inherit;
font-size: 1.5em;
}
#modal-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
}
.modal-buttons {
margin-top: 1rem;
display: flex;
gap: .5rem;
justify-content: flex-end;
}
button {
padding: .5rem 1.5rem;
border-radius: .2rem;
border: none;
cursor: pointer;
}
button.primary {
background: #4a90e2;
color: #fff;
}
button.danger {
background: #e74c3c;
color: #fff;
}
#instructions-display, #coordinates-display {
position: fixed;
background: rgba(255,255,255,0.8);
padding: .5rem 1rem;
border-radius: 4px;
}
#instructions-display {
bottom: 1rem;
left: 1rem;
}
#coordinates-display {
top: 1rem;
left: 1rem;
}