206 lines
5.3 KiB
JavaScript
206 lines
5.3 KiB
JavaScript
let spaceContainer, space;
|
|
|
|
let editing;
|
|
let dragging;
|
|
let moved;
|
|
let movedFrom;
|
|
let offset;
|
|
let clicked;
|
|
|
|
document.addEventListener('mouseup', function(event) {
|
|
clicked = false;
|
|
});
|
|
|
|
document.addEventListener('mousemove', function(event) {
|
|
moved = true;
|
|
if (dragging) {
|
|
let left = event.clientX - spaceContainer.offsetLeft - offset.x;
|
|
let top = event.clientY - spaceContainer.offsetTop - offset.y;
|
|
dragging.style.left = `${left < 0 ? 0 : left}px`;
|
|
dragging.style.top = `${top < 0 ? 0 : top}px`;
|
|
save(dragging);
|
|
}
|
|
else if (clicked) {
|
|
spaceContainer.scrollLeft -= event.movementX;
|
|
spaceContainer.scrollTop -= event.movementY;
|
|
}
|
|
});
|
|
|
|
let saving;
|
|
let queue;
|
|
|
|
function save(span) {
|
|
if (saving) {
|
|
queue = span;
|
|
return;
|
|
}
|
|
saving = true;
|
|
window.currentInstance.emit('save_span', {
|
|
thread: window.currentThread.id,
|
|
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;
|
|
this.remove();
|
|
if (this.id)
|
|
save(this);
|
|
};
|
|
span.onwheel = function(event) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.scale *= 1 - event.deltaY * .001;
|
|
if (this.scale > 100)
|
|
this.scale = 100;
|
|
this.style.transform = `translate(-50%, -50%) scale(${this.scale})`;
|
|
save(this);
|
|
};
|
|
span.onmousedown = function(event) {
|
|
if (dragging || editing === this)
|
|
return;
|
|
event.preventDefault();
|
|
if (event.button !== 0)
|
|
return;
|
|
dragging = this;
|
|
offset = {
|
|
x: event.clientX - (spaceContainer.offsetLeft + this.offsetLeft),
|
|
y: event.clientY - (spaceContainer.offsetTop + this.offsetTop)
|
|
};
|
|
};
|
|
span.onmouseup = function(event) {
|
|
if (event.button !== 0)
|
|
return;
|
|
dragging = null;
|
|
if (moved)
|
|
return;
|
|
this.focus();
|
|
editing = this;
|
|
};
|
|
space.append(span);
|
|
return span;
|
|
}
|
|
|
|
export default function loadSpace(callback) {
|
|
let instance = window.currentInstance;
|
|
|
|
let scale = 1;
|
|
|
|
if (!instance.spaced) {
|
|
spaceContainer = document.getElementById('space');
|
|
space = document.getElementById('spacediv');
|
|
|
|
spaceContainer.onwheel = function(event) {
|
|
if (event.getModifierState('Shift'))
|
|
return;
|
|
event.preventDefault();
|
|
scale *= 1 - event.deltaY * .001;
|
|
if (scale < .5)
|
|
scale = .5;
|
|
space.style.transform = `scale(${scale})`;
|
|
spaceContainer.scrollLeft += event.offsetX * (scale - scale / (1 - event.deltaY * .001));
|
|
spaceContainer.scrollTop += event.offsetY * (scale - scale / (1 - event.deltaY * .001));
|
|
//spaceContainer.scrollLeft += spaceContainer.clientWidth * (1 - spaceContainer.clientWidth / spaceContainer.scrollWidth + event.offsetX / spaceContainer.clientWidth) * (scale - scale / (1 - event.deltaY * .001));
|
|
//spaceContainer.scrollTop += spaceContainer.clientHeight * (1 - spaceContainer.clientHeight / spaceContainer.scrollHeight + event.offsetY / spaceContainer.clientHeight) * (scale - scale / (1 - event.deltaY * .001));
|
|
};
|
|
spaceContainer.onmousedown = function(event) {
|
|
if (event.button !== 0)
|
|
return;
|
|
clicked = true;
|
|
moved = false;
|
|
movedFrom = { x: event.offsetX, y: event.offsetY };
|
|
};
|
|
spaceContainer.onmouseup = function(event) {
|
|
if (event.button !== 0)
|
|
return;
|
|
if (dragging) {
|
|
dragging.onmouseup(event);
|
|
return;
|
|
}
|
|
if (editing) {
|
|
if (event.target !== editing)
|
|
editing = null;
|
|
return;
|
|
}
|
|
if (moved && (event.offsetX - movedFrom.x) * (event.offsetX - movedFrom.x)
|
|
+ (event.offsetY - movedFrom.y) * (event.offsetY - movedFrom.y) > 100)
|
|
return;
|
|
editing = add({
|
|
x: (event.offsetX + spaceContainer.scrollLeft) / scale,
|
|
y: (event.offsetY + spaceContainer.scrollTop) / scale,
|
|
scale: 1,
|
|
content: ''
|
|
});
|
|
editing.focus();
|
|
};
|
|
|
|
instance.socket.on('span', msg => {
|
|
if (msg.thread !== window.currentSpace.id || window.currentInstance !== instance)
|
|
return;
|
|
let span = document.getElementById('span' + msg.id);
|
|
if (span) {
|
|
span.innerText = msg.content;
|
|
span.style.left = `${msg.x}px`;
|
|
span.style.top = `${msg.y}px`;
|
|
span.scale = msg.scale;
|
|
span.style.transform = `translate(-50%, -50%) scale(${msg.scale})`;
|
|
}
|
|
else
|
|
add(msg);
|
|
});
|
|
instance.spaced = true;
|
|
}
|
|
else if (window.currentSpace === window.currentThread)
|
|
return;
|
|
window.currentSpace = window.currentThread;
|
|
space.innerHTML = '';
|
|
space.style.transform = '';
|
|
instance.emit('get_space', {
|
|
thread: window.currentSpace.id
|
|
}, msg => {
|
|
if (!msg.success) {
|
|
console.log('get space failed: ' + msg.message);
|
|
return;
|
|
}
|
|
callback && callback(msg.spans);
|
|
msg.spans.forEach(add);
|
|
});
|
|
};
|