vybe/client/space.js

156 lines
3.3 KiB
JavaScript

let space;
let spaceId;
let scale = 1;
let editing;
let dragging;
let moved;
let offset;
function mousemove(event) {
let left = (event.clientX - space.offsetLeft) * scale - offset.x;
let top = (event.clientY - space.offsetTop) * scale - offset.y;
dragging.style.left = `${left < 0 ? 0 : left}px`;
dragging.style.top = `${top < 0 ? 0 : top}px`;
moved = true;
save(dragging);
}
let saving;
let queue;
function save(span) {
if (saving) {
queue = span;
return;
}
saving = true;
window.emit('save_span', {
thread: spaceId,
id: span.id ? span.id.slice(4) : '',
content: span.innerText,
x: span.style.left.slice(0, -2),
y: span.style.top.slice(0, -2),
scale: span.scale
}, msg => {
if (!msg.success)
console.log('span save failed: ' + msg.message);
if (!span.id)
span.id = 'span' + msg.id;
saving = false;
if (queue) {
save(queue);
queue = null;
}
});
}
function add(s) {
let span = document.createElement('span');
span.classList.add('span');
if (s.id)
span.id = 'span' + s.id;
span.innerText = s.content;
span.contentEditable = true;
span.spellcheck = false;
span.scale = s.scale;
span.style.left = `${s.x}px`;
span.style.top = `${s.y}px`;
span.style.transform = `translate(-50%, -50%) scale(${s.scale})`;
span.onkeydown = function(event) {
if (event.key === 'Enter' && !event.getModifierState('Shift')) {
event.preventDefault();
editing = null;
span.blur();
}
};
span.oninput = function(event) {
save(this);
};
span.onblur = function(event) {
if (this.innerText)
return;
save(this);
this.remove();
};
span.onwheel = function(event) {
event.preventDefault();
this.scale *= 1 - event.deltaY * .001;
this.style.transform = `translate(-50%, -50%) scale(${this.scale})`;
save(this);
};
span.onmousedown = function(event) {
if (dragging || editing === this)
return;
dragging = this;
event.preventDefault();
offset = {
x: event.clientX - (space.offsetLeft + this.offsetLeft),
y: event.clientY - (space.offsetTop + this.offsetTop)
};
moved = false;
document.addEventListener('mousemove', mousemove);
};
span.onmouseup = function(event) {
event.stopPropagation();
document.removeEventListener('mousemove', mousemove);
dragging = null;
if (moved)
return;
this.focus();
editing = this;
};
space.append(span);
return span;
}
window.socket.on('span', msg => {
if (msg.thread !== spaceId)
return;
let span = document.getElementById('span' + msg.id);
if (span) {
span.innerText = msg.content;
span.x = msg.x;
span.y = msg.y;
span.scale = msg.scale;
span.style.transform = `translate(-50%, -50%) scale(${msg.scale})`;
}
else
add(msg);
});
export default function loadSpace() {
if (!space) {
space = document.getElementById('space');
space.onmouseup = event => {
if (dragging) {
dragging.onmouseup(event);
return;
}
if (editing) {
if (event.target !== editing)
editing = null;
return;
}
editing = add({
x: event.offsetX + space.scrollLeft,
y: event.offsetY + space.scrollTop,
scale: 1,
content: ''
});
editing.focus();
};
}
if (spaceId === window.threadId)
return;
spaceId = window.threadId;
space.innerHTML = '';
window.emit('get_space', { thread: window.threadId }, msg => {
if (!msg.success)
console.log('get space failed: ' + msg.message);
for (const span of msg.spans)
add(span);
});
};