forked from cory/tildefriends
doc: add JSDoc annotations in the core folder
start documenting a bit, mostly inconsequential changes
This commit is contained in:
269
core/client.js
269
core/client.js
@ -12,7 +12,7 @@ let gOriginalInput;
|
||||
let kErrorColor = "#dc322f";
|
||||
let kStatusColor = "#fff";
|
||||
|
||||
/* Functions that server-side app code can call through the app object. */
|
||||
// Functions that server-side app code can call through the app object.
|
||||
const k_api = {
|
||||
setDocument: {args: ['content'], func: api_setDocument},
|
||||
postMessage: {args: ['message'], func: api_postMessage},
|
||||
@ -24,6 +24,7 @@ const k_api = {
|
||||
setHash: {args: ['hash'], func: api_setHash},
|
||||
};
|
||||
|
||||
// TODO(tasiaiso): this is only used once, move it down ?
|
||||
const k_global_style = css`
|
||||
a:link {
|
||||
color: #268bd2;
|
||||
@ -42,6 +43,9 @@ const k_global_style = css`
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Class that represents the top bar
|
||||
*/
|
||||
class TfNavigationElement extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
@ -63,6 +67,10 @@ class TfNavigationElement extends LitElement {
|
||||
this.spark_lines = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} event
|
||||
*/
|
||||
toggle_edit(event) {
|
||||
event.preventDefault();
|
||||
if (editing()) {
|
||||
@ -72,10 +80,20 @@ class TfNavigationElement extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} key
|
||||
*/
|
||||
reset_permission(key) {
|
||||
send({action: "resetPermission", permission: key});
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} key
|
||||
* @param {*} options
|
||||
* @returns
|
||||
*/
|
||||
get_spark_line(key, options) {
|
||||
if (!this.spark_lines[key]) {
|
||||
let spark_line = document.createElement('tf-sparkline');
|
||||
@ -94,6 +112,10 @@ class TfNavigationElement extends LitElement {
|
||||
return this.spark_lines[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @returns
|
||||
*/
|
||||
render_login() {
|
||||
if (this?.credentials?.session?.name) {
|
||||
return html`<a id="login" href="/login/logout?return=${url() + hash()}">logout ${this.credentials.session.name}</a>`;
|
||||
@ -102,6 +124,10 @@ class TfNavigationElement extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @returns
|
||||
*/
|
||||
render_permissions() {
|
||||
if (this.show_permissions) {
|
||||
return html`
|
||||
@ -122,6 +148,10 @@ class TfNavigationElement extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @returns
|
||||
*/
|
||||
render() {
|
||||
let self = this;
|
||||
return html`
|
||||
@ -157,8 +187,12 @@ class TfNavigationElement extends LitElement {
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('tf-navigation', TfNavigationElement);
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
*/
|
||||
class TfFilesElement extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
@ -174,6 +208,10 @@ class TfFilesElement extends LitElement {
|
||||
this.dropping = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} file
|
||||
*/
|
||||
file_click(file) {
|
||||
this.dispatchEvent(new CustomEvent('file_click', {
|
||||
detail: {
|
||||
@ -184,6 +222,11 @@ class TfFilesElement extends LitElement {
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} file
|
||||
* @returns
|
||||
*/
|
||||
render_file(file) {
|
||||
let classes = ['file'];
|
||||
if (file == this.current) {
|
||||
@ -195,6 +238,10 @@ class TfFilesElement extends LitElement {
|
||||
return html`<div class="${classes.join(' ')}" @click=${x => this.file_click(file)}>${file}</div>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} event
|
||||
*/
|
||||
async drop(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
@ -213,15 +260,27 @@ class TfFilesElement extends LitElement {
|
||||
updateFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} event
|
||||
*/
|
||||
drag_enter(event) {
|
||||
this.dropping++;
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} event
|
||||
*/
|
||||
drag_leave(event) {
|
||||
this.dropping--;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @returns
|
||||
*/
|
||||
render() {
|
||||
let self = this;
|
||||
return html`
|
||||
@ -258,8 +317,12 @@ class TfFilesElement extends LitElement {
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('tf-files', TfFilesElement);
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
*/
|
||||
class TfFilesPaneElement extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
@ -275,11 +338,19 @@ class TfFilesPaneElement extends LitElement {
|
||||
this.files = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} expanded
|
||||
*/
|
||||
set_expanded(expanded) {
|
||||
this.expanded = expanded;
|
||||
window.localStorage.setItem('files', expanded ? '1' : '0');
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @returns
|
||||
*/
|
||||
render() {
|
||||
let self = this;
|
||||
let expander = this.expanded ?
|
||||
@ -302,8 +373,12 @@ class TfFilesPaneElement extends LitElement {
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('tf-files-pane', TfFilesPaneElement);
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
*/
|
||||
class TfSparkLineElement extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
@ -321,6 +396,11 @@ class TfSparkLineElement extends LitElement {
|
||||
this.k_values_max = 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} key
|
||||
* @param {*} value
|
||||
*/
|
||||
append(key, value) {
|
||||
let line = null;
|
||||
for (let it of this.lines) {
|
||||
@ -345,6 +425,11 @@ class TfSparkLineElement extends LitElement {
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} line
|
||||
* @returns
|
||||
*/
|
||||
render_line(line) {
|
||||
if (line?.values?.length >= 2) {
|
||||
let max = Math.max(this.max, ...line.values);
|
||||
@ -353,6 +438,10 @@ class TfSparkLineElement extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @returns
|
||||
*/
|
||||
render() {
|
||||
let max = Math.round(10.0 * Math.max(...this.lines.map(line => line.values[line.values.length - 1]))) / 10.0;
|
||||
return html`
|
||||
@ -363,8 +452,10 @@ class TfSparkLineElement extends LitElement {
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('tf-sparkline', TfSparkLineElement);
|
||||
|
||||
// TODOC
|
||||
window.addEventListener("keydown", function(event) {
|
||||
if (event.keyCode == 83 && (event.altKey || event.ctrlKey)) {
|
||||
if (editing()) {
|
||||
@ -379,6 +470,12 @@ window.addEventListener("keydown", function(event) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} nodes
|
||||
* @param {*} callback
|
||||
* @returns
|
||||
*/
|
||||
function ensureLoaded(nodes, callback) {
|
||||
if (!nodes.length) {
|
||||
callback();
|
||||
@ -416,14 +513,26 @@ function ensureLoaded(nodes, callback) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @returns
|
||||
*/
|
||||
function editing() {
|
||||
return document.getElementById("editPane").style.display != 'none';
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @returns
|
||||
*/
|
||||
function is_edit_only() {
|
||||
return window.location.search == '?editonly=1' || window.innerWidth < 1024;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @returns
|
||||
*/
|
||||
async function edit() {
|
||||
if (editing()) {
|
||||
return;
|
||||
@ -446,16 +555,30 @@ async function edit() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
*/
|
||||
function trace() {
|
||||
window.open(`/speedscope/#profileURL=${encodeURIComponent('/trace')}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} name
|
||||
* @returns
|
||||
*/
|
||||
function guessMode(name) {
|
||||
return name.endsWith(".js") ? "javascript" :
|
||||
name.endsWith(".html") ? "htmlmixed" :
|
||||
null;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} name
|
||||
* @param {*} id
|
||||
* @returns
|
||||
*/
|
||||
function loadFile(name, id) {
|
||||
return fetch('/' + id + '/view').then(function(response) {
|
||||
if (!response.ok) {
|
||||
@ -472,6 +595,11 @@ function loadFile(name, id) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} path
|
||||
* @returns
|
||||
*/
|
||||
async function load(path) {
|
||||
let response = await fetch((path || url()) + 'view');
|
||||
let json;
|
||||
@ -509,16 +637,28 @@ async function load(path) {
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
*/
|
||||
function closeEditor() {
|
||||
window.localStorage.setItem('editing', '0');
|
||||
document.getElementById("editPane").style.display = 'none';
|
||||
document.getElementById('viewPane').style.display = 'flex';
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @returns
|
||||
*/
|
||||
function explodePath() {
|
||||
return /^\/~([^\/]+)\/([^\/]+)(.*)/.exec(window.location.pathname);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} save_to
|
||||
* @returns
|
||||
*/
|
||||
function save(save_to) {
|
||||
document.getElementById("save").disabled = true;
|
||||
if (gCurrentFile) {
|
||||
@ -603,6 +743,9 @@ function save(save_to) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
*/
|
||||
function changeIcon() {
|
||||
let value = prompt('Enter a new app icon emoji:');
|
||||
if (value !== undefined) {
|
||||
@ -611,6 +754,9 @@ function changeIcon() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
*/
|
||||
function deleteApp() {
|
||||
let name = document.getElementById("name");
|
||||
let path = name && name.value ? name.value : url();
|
||||
@ -627,6 +773,10 @@ function deleteApp() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @returns
|
||||
*/
|
||||
function url() {
|
||||
let hash = window.location.href.indexOf('#');
|
||||
let question = window.location.href.indexOf('?');
|
||||
@ -642,20 +792,36 @@ function url() {
|
||||
return end != -1 ? window.location.href.substring(0, end) : window.location.href;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @returns
|
||||
*/
|
||||
function hash() {
|
||||
return window.location.hash != "#" ? window.location.hash : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} content
|
||||
*/
|
||||
function api_setDocument(content) {
|
||||
let iframe = document.getElementById("document");
|
||||
iframe.srcdoc = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} message
|
||||
*/
|
||||
function api_postMessage(message) {
|
||||
let iframe = document.getElementById("document");
|
||||
iframe.contentWindow.postMessage(message, "*");
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} error
|
||||
*/
|
||||
function api_error(error) {
|
||||
if (error) {
|
||||
if (typeof(error) == 'string') {
|
||||
@ -667,14 +833,30 @@ function api_error(error) {
|
||||
console.log('error', error);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} key
|
||||
* @param {*} value
|
||||
*/
|
||||
function api_localStorageSet(key, value) {
|
||||
window.localStorage.setItem('app:' + key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} key
|
||||
* @returns
|
||||
*/
|
||||
function api_localStorageGet(key) {
|
||||
return window.localStorage.getItem('app:' + key);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} permission
|
||||
* @param {*} id
|
||||
* @returns
|
||||
*/
|
||||
function api_requestPermission(permission, id) {
|
||||
let outer = document.createElement('div');
|
||||
outer.classList.add('permissions');
|
||||
@ -739,14 +921,25 @@ function api_requestPermission(permission, id) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
*/
|
||||
function api_print() {
|
||||
console.log('app>', ...arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} hash
|
||||
*/
|
||||
function api_setHash(hash) {
|
||||
window.location.hash = hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} message
|
||||
*/
|
||||
function _receive_websocket_message(message) {
|
||||
if (message && message.action == "session") {
|
||||
setStatusMessage("🟢 Executing...", kStatusColor);
|
||||
@ -827,10 +1020,19 @@ function _receive_websocket_message(message) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} message
|
||||
* @param {*} color
|
||||
*/
|
||||
function setStatusMessage(message, color) {
|
||||
document.getElementsByTagName('tf-navigation')[0].status = {message: message, color: color};
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} value
|
||||
*/
|
||||
function send(value) {
|
||||
try {
|
||||
if (gSocket && gSocket.readyState == gSocket.OPEN) {
|
||||
@ -841,6 +1043,13 @@ function send(value) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} sourceData
|
||||
* @param {*} maxWidth
|
||||
* @param {*} maxHeight
|
||||
* @param {*} callback
|
||||
*/
|
||||
function fixImage(sourceData, maxWidth, maxHeight, callback) {
|
||||
let result = sourceData;
|
||||
let image = new Image();
|
||||
@ -864,16 +1073,26 @@ function fixImage(sourceData, maxWidth, maxHeight, callback) {
|
||||
image.src = sourceData;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} image
|
||||
*/
|
||||
function sendImage(image) {
|
||||
fixImage(image, 320, 240, function(result) {
|
||||
send({image: result});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
*/
|
||||
function hashChange() {
|
||||
send({event: 'hashChange', hash: window.location.hash});
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
*/
|
||||
function focus() {
|
||||
if (gSocket && gSocket.readyState == gSocket.CLOSED) {
|
||||
connectSocket();
|
||||
@ -882,12 +1101,19 @@ function focus() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
*/
|
||||
function blur() {
|
||||
if (gSocket && gSocket.readyState == gSocket.OPEN) {
|
||||
send({event: "blur"});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} event
|
||||
*/
|
||||
function message(event) {
|
||||
if (event.data && event.data.event == "resizeMe" && event.data.width && event.data.height) {
|
||||
let iframe = document.getElementById("iframe_" + event.data.name);
|
||||
@ -916,6 +1142,10 @@ function message(event) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} path
|
||||
*/
|
||||
function reconnect(path) {
|
||||
let oldSocket = gSocket;
|
||||
gSocket = null
|
||||
@ -928,6 +1158,10 @@ function reconnect(path) {
|
||||
connectSocket(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} path
|
||||
*/
|
||||
function connectSocket(path) {
|
||||
if (!gSocket || gSocket.readyState != gSocket.OPEN) {
|
||||
if (gSocket) {
|
||||
@ -979,6 +1213,10 @@ function connectSocket(path) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} name
|
||||
*/
|
||||
function openFile(name) {
|
||||
let newDoc = (name && gFiles[name]) ? gFiles[name].doc : cm6.EditorState.create({doc: "", extensions: cm6.extensions});
|
||||
let oldDoc = gEditor.state;
|
||||
@ -995,6 +1233,9 @@ function openFile(name) {
|
||||
gEditor.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
*/
|
||||
function updateFiles() {
|
||||
let files = document.getElementsByTagName("tf-files-pane")[0];
|
||||
if (files) {
|
||||
@ -1006,6 +1247,10 @@ function updateFiles() {
|
||||
gEditor.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} name
|
||||
*/
|
||||
function makeNewFile(name) {
|
||||
gFiles[name] = {
|
||||
doc: cm6.EditorState.create({extensions: cm6.extensions}),
|
||||
@ -1013,6 +1258,9 @@ function makeNewFile(name) {
|
||||
openFile(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
*/
|
||||
function newFile() {
|
||||
let name = prompt("Name of new file:", "file.js");
|
||||
if (name && !gFiles[name]) {
|
||||
@ -1020,6 +1268,9 @@ function newFile() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
*/
|
||||
function removeFile() {
|
||||
if (confirm("Remove " + gCurrentFile + "?")) {
|
||||
delete gFiles[gCurrentFile];
|
||||
@ -1027,6 +1278,9 @@ function removeFile() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
*/
|
||||
async function appExport() {
|
||||
let JsZip = (await import('/static/jszip.min.js')).default;
|
||||
let owner = window.location.pathname.split('/')[1].replace('~', '');
|
||||
@ -1049,6 +1303,12 @@ async function appExport() {
|
||||
a.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
* @param {*} name
|
||||
* @param {*} file
|
||||
* @returns
|
||||
*/
|
||||
async function save_file_to_blob_id(name, file) {
|
||||
console.log(`Saving ${name}.`);
|
||||
let response = await fetch('/save', {
|
||||
@ -1068,6 +1328,9 @@ async function save_file_to_blob_id(name, file) {
|
||||
return blob_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODOC
|
||||
*/
|
||||
async function appImport() {
|
||||
let JsZip = (await import('/static/jszip.min.js')).default;
|
||||
let input = document.createElement('input');
|
||||
@ -1119,6 +1382,9 @@ async function appImport() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
async function sourcePretty() {
|
||||
let prettier = (await import('/prettier/standalone.mjs')).default;
|
||||
let babel = (await import('/prettier/babel.mjs')).default;
|
||||
@ -1140,6 +1406,7 @@ async function sourcePretty() {
|
||||
}
|
||||
}
|
||||
|
||||
// TODOC
|
||||
window.addEventListener("load", function() {
|
||||
window.addEventListener("hashchange", hashChange);
|
||||
window.addEventListener("focus", focus);
|
||||
|
Reference in New Issue
Block a user