const noteName = document.location.pathname.substring(1); let connection = new signalR.HubConnectionBuilder() .withAutomaticReconnect() .withUrl(`/noteHub?noteName=${noteName}`) .build(); function start() { connection.start().then(function () { console.log('Started websocket listener'); }).catch(function (err) { console.error(err.toString()); return alert('Connection error. Reload page.'); }); } function showToast(selector) { const cssClass = 'show'; // show 'saved' indicator $(selector).addClass(cssClass).delay(800).queue(function (next) { $(this).removeClass(cssClass); next(); }); } function saveContent($textarea) { $textarea = $textarea || $('textarea'); var content = $textarea.val(); connection.invoke('SaveNote', content, noteName).then(function () { showToast('#saved-indicator'); }).catch(function (err) { console.error(err.toString()); setTimeout(start, 2000); }); }; // start the signalr connection start(); $(function () { const $textarea = $('textarea'); // set focus on load $textarea.focus(); // update content upon sync save connection.on('updateNote', function (content) { $textarea.val(content); showToast('#update-indicator'); }); // set dark mode if (window.location.hash == '#dark') { $('body').addClass('dark'); } let timer = null; const ignoredKeyCodes = [17, 18, 20, 27, 37, 38, 39, 40, 91]; // save after a second delay after typing $textarea.keyup(function (e) { // only set timer if key isn't ignored if (!ignoredKeyCodes.includes(e.keyCode)) { clearTimeout(timer); timer = setTimeout(function () { saveContent(); }, 1000); } }); // support tab key in textarea $textarea.keydown(function (e) { if (e.keyCode === 9) { // tab was pressed // get caret position/selection var start = this.selectionStart; end = this.selectionEnd; var $this = $(this); // set textarea value to: text before caret + tab + text after caret $this.val($this.val().substring(0, start) + ' ' + $this.val().substring(end)); // put caret at right position again this.selectionStart = this.selectionEnd = start + 2; // prevent the focus lose return false; } }); });