function _internal_joinPaths(path1, path2) { if (path2[0] == "/") { return _internal_sanitizePath(path2); } else if (path2[0] == "~" && (path2.length == 1 || path2[1] == "/")) { return _internal_sanitizePath(HOME_DIR + path2.slice(1)); } else { return _internal_sanitizePath(path1 + "/" + path2); } } function _internal_sanitizePath(path) { while (path.includes("//")) { path = path.replaceAll("//", "/"); } while (path[path.length - 1] == "/") { path = path.slice(0, path.length - 1); } let newPath = []; for (const dir of path.split("/")) { if (dir == ".") { } else if (dir == "..") { if (newPath.length) { newPath = newPath.slice(0, newPath.length - 1); } } else if (dir) { newPath.push(dir); } } return "/" + newPath.join("/"); } function _internal_getFile(path) { function getFile_recursive(files, path) { console.log(files, path); let file = files[path[0]]; if (!file) { return null; } if (path.length == 1) { return file; } if (file.type == "file") { return null; } return getFile_recursive(file.files, path.slice(1)); } if (path == "/") { return { type: "directory", name: "/", files: FILESYSTEM }; } let dirs = path.split("/"); if (dirs[0] == "") { dirs = dirs.slice(1); } return getFile_recursive(FILESYSTEM, dirs); } function _internal_stringifyPath(path) { if (path.startsWith(HOME_DIR)) { return path.replace(HOME_DIR, "~"); } return path; } function _internal_getPS1(winInfo) { return `<b class="green">${winInfo.ps1Override || "trinkey@website"}</b>:<b class="blue">${_internal_stringifyPath(winInfo.PWD)}</b>$ `; } function _internal_getFlags(command) { let flags = []; let newCommand = []; for (const thing of command.split(" ")) { if (thing.startsWith("-")) { flags.push(...thing.slice(1).split("")); } else { newCommand.push(thing); } } return { flags: flags, removed: newCommand.join(" ") }; } function _internal_fileSize(size) { let suffix = ""; let amount = size; const sizes = [ { suffix: "K", amount: 1024, threshold: 10000 }, { suffix: "M", amount: Math.pow(1024, 2), threshold: 1000000 } ]; for (const info of sizes) { if (size > info.threshold) { suffix = info.suffix; amount = Math.round(size / info.amount * 10) / 10; if (String(amount).length > 3) { amount = Math.round(info.amount); } } } return `${amount}${suffix}`.padStart(4, " "); } function cat(path, windowID) { if (!path) { return "<div>cat: You must specify a file</div>"; } path = _internal_joinPaths(windowInformation[windowID].PWD || HOME_DIR, path); let file = _internal_getFile(path); if (!file) { return `<div>cat: ${escapeHTML(path)}: No such file or directory</div>`; } else if (file.type == "directory") { return `<div>cat: ${escapeHTML(path)}: Is a directory</div>`; } else { return file.content; } } function cd(path, windowID) { if (!path) { windowInformation[windowID].PWD = HOME_DIR; return ""; } let newPWD = _internal_joinPaths(windowInformation[windowID].PWD, path); let newFileObj = _internal_getFile(newPWD); if (newFileObj === null) { return `<div>cd: ${escapeHTML(path)}: No such file or directory</div>`; } else if (newFileObj.type == "file") { return `<div>cd: ${escapeHTML(path)}: Not a directory</div>`; } windowInformation[windowID].PWD = newPWD; return ""; } function clear(path, windowID) { WINDOWS[windowID].element.querySelector(".window").innerHTML = ""; return ""; } function exit(path, windowID) { setTimeout(() => { WINDOWS[windowID].element.querySelector(".close").click(); }, 1); return ""; } function help(path, windowID) { return helpText; } function ls(path, windowID) { let { flags, removed } = _internal_getFlags(path); path = _internal_joinPaths(windowInformation[windowID].PWD || HOME_DIR, removed); let file = _internal_getFile(path); let files; if (!file) { return `<div>ls: ${escapeHTML(path)}: No such file or directory</div>`; } else if (file.type == "file") { files = { [file.name]: file }; } else { files = file.files; } let directories = []; let hidden = flags.includes("a") || flags.includes("A"); let long = flags.includes("l"); let out = flags.includes("a") ? (long ? "<div>drwxrwxr-x trinkey trinkey 4096 <span class=\"blue\">.</span></div><div>drwxr-xr-x trinkey trinkey 4096 <span class=\"blue\">..</span></div>" : "<span class=\"blue\">.</span> <span class=\"blue\">..</span> ") : ""; for (const file of Object.keys(files).sort((a, b) => (({ true: 1, false: -1 })[String(flags.includes("r") ? a < b : a > b)]))) { if (file.startsWith(".") && !hidden) { continue; } let fObj = files[file]; if (long) { if (fObj.type == "directory") { directories.push(fObj); out += `<div>drwxrwxr-x trinkey trinkey 4096 <span class=\"blue\">${escapeHTML(file)}</span></div>`; } else { out += `<div>-rw-rw-r-- trinkey trinkey ${_internal_fileSize(fObj.content.length).replaceAll(" ", " ")} ${escapeHTML(file)}</div>`; } } else { if (fObj.type == "directory") { directories.push(fObj); out += `<span class=\"blue\">${escapeHTML(file)}</span> `; } else { out += `${escapeHTML(file)} `; } } } if (!long) { out = out.slice(0, out.length - 7); } if (flags.includes("R")) { for (const dir of directories) { out += `<div><br>${escapeHTML(_internal_stringifyPath(_internal_joinPaths(path, dir.name)))}:</div>${ls(`${_internal_joinPaths(path, dir.name)} -${flags.join("")}`, windowID)}`; } } return out; } function _internal_set_ps1(args, windowID) { windowInformation[windowID].ps1Override = args.split("|")[0]; WINDOWS[windowID].element.querySelector(".window [data-type-area]").innerHTML = args.split("|")[1]; return ""; } function _internal_neofetch(args, windowID) { WINDOWS[windowID].element.querySelector(".window [data-type-area]").innerHTML = "neofetch"; return _internal_neofetchOutputs[args]; } const _internal_commands = { cat: { callback: cat, autocomplete: "file" }, cd: { callback: cd, autocomplete: "dir" }, clear: { callback: clear, autocomplete: null }, help: { callback: help, autocomplete: null }, ls: { callback: ls, autocomplete: "file" }, exit: { callback: exit, autocomplete: null }, _internal_set_ps1: { callback: _internal_set_ps1, autocomplete: null }, _internal_neofetch: { callback: _internal_neofetch, autocomplete: null }, spin: { callback: (args, windowID) => { createBlob(); return ""; }, autocomplete: null }, }; const _internal_defaultFiles = { about: `<div><b>hi there!</b></div> <div>i'm trinkey, but you can call me <b>katie</b> too! <small>(trinkey is more of a username)</small></div> <div>--------------------</div> <div>i'm a silly little cat who lives in the usa (new york time zone).</div> <div>i'm <span class="blue">t</span><span class="pink">r</span>a<span class="pink">n</span><span class="blue">s</span> (she/it, they/them is also fine).</div> <div>i'm not actively in a relationship, however i'm also not looking to get into one either.</div> <div>--------------------</div> <div>i like to code stuff (mostly websites)! some of my programs can be found in projects section. i know a few languages, those being python, javascript/typescript, html/css (if you count those), and a little bit of java.</div> <div>--------------------</div> <div>well, that's about it! i hope you like my website!</div>`, socials: `<div>- fedi - <b>@trinkey@trinkey.com</b> (or @trinkey@is.trinkey.com)</div> <div>- forgejo - <a href="https://git.trinkey.com/trinkey/" target="_blank"><b>trinkey</b></a></div> <div>- github - <a href="https://github.com/trinkey/" target="_blank"><b>trinkey</b></a></div> <div>- git.gay - <a href="https://git.gay/trinkey/" target="_blank"><b>trinkey</b></a> (inactive)</div> <div>- smiggins - <a href="https://smiggins.trinkey.com/u/trinkey/" target="_blank"><b>trinkey</b></a></div> <div>- signal - <b>@trinkey.01</b></div> <div>- email - <b>trinkey [at] proton [dot] me</b></div> <div>- youtube - <a href="https://youtube.com/@trinkey" target="_blank"><b>@trinkey</b></a> (inactive)</div> <div>- discord - <b>@trinkey_</b> (mostly inactive)</div> <div>- <a href="trinkey_gpg.asc" target="_blank">gpg key</a> (1D6E 5D28 BDD4 D7FA 96B8 8799 2B33 C6C6 14F2 591A)</div>`, projects: `<div><b>projects</b> - the things i made</div> <div>- <a href="https://github.com/jerimiah-smiggins/smiggins/" target="_blank"><b>smiggins</b></a> (<a href="https://smiggins.trinkey.com/" target="_blank">website</a>) - a social media platform i made</div> <div>- <a href="https://git.trinkey.com/trinkey/website/" target="_blank"><b>this website</b></a> - check out the code</div> <div>- <a href="https://git.gay/trinkey/dotindex/" target="_blank"><b>dotindex</b></a> (<a href="https://pypi.org/project/DotIndex/" target="_blank">pypi</a>) - a python library that lets you access dicts using the dot notation (dict.key) instead of whatever python does (dict["key"])</div> <div>- <a href="https://git.gay/trinkey/infopage/" target="_blank"><b>infopage</b></a> (<a href="https://infpg.pythonanywhere.com/" target="_blank">website</a>) - my very own pronouns.page clone</div> <div>- <a href="https://git.trinkey.com/t" target="_blank"><b>tSuite</b></a> (<a href="https://auth.trinkey.com/" target="_blank">website</a>) - a collection of services that are all interconnected</div><br> <div>i'll likely add more in the future, these are just the ones i'm most proud of at the moment.</div>`, buttons: `<div><b>my button:</b> (click to copy html)</div> <div><img style="cursor: pointer;" src="img/88x31.png" alt="trinkey's 88x31. image of her cat on the right with the word 'trinkey' taking up the rest of the button." title="trinkey's 88x31. image of her cat on the right with the word 'trinkey' taking up the rest of the button." onclick="copyButton()"></div> <div>--------------------</div> <div class="buttons-88x31"> <a href="https://notfire.cc" target="_blank"><img src="https://notfire.cc/design/images/buttons/notfire-cc-88x31-af.gif" alt="notfire.cc" title="notfire.cc"></a> <a href="https://microspinny.zip" target="_blank"><img src="https://microspinny.zip/static/button_2.png" alt="a non-spinning demigirl blobcat angled slightly with a black border to the left of "Micro"" title="a non-spinning demigirl blobcat angled slightly with a black border to the left of "Micro""></a> <a href="https://w.on-t.work" target="_blank"><img src="https://w.on-t.work/assets/88x31.png" alt="kopper's button" title="kopper's button"></a> <a href="https://synth.download" target="_blank"><img src="https://synth.download/assets/buttons/sneexy.svg" alt="Sneexy" title="Sneexy"></a> <a href="https://beepi.ng" target="_blank"><img src="https://beepi.ng/88x31.png" alt="unnick" title="unnick"></a> <a href="http://autumn.town" target="_blank"><img src="https://autumn.town/assets/buttons/mybutton.webp" alt="Autumn Town Café" title="Autumn Town Café"></a> <a href="https://redcatho.de" target="_blank"><img src="https://redcatho.de/buttons/red.png" alt="the text 'red is purple' on a purple background" title="the text 'red is purple' on a purple background"></a> <a href="https://doskel.net" target="_blank"><img src="https://doskel.net/button.png" alt="doskel" title="doskel"></a> <a href="https://velzie.rip" target="_blank"><img src="https://velzie.rip/88x31.png" alt="velzie" title="velzie"></a> <a href="https://melontini.me" target="_blank"><img src="https://melontini.me/88_31/88_31.png" alt="melontini" title="melontini"></a> <a href="https://sillydomain.name" target="_blank"><img src="https://sillydomain.name/assets/buttons/benjae.png" alt="benjae!!!" title="benjae!!!"></a> </div>`, testimonials: `<div>"warning: this user is trinkey"</div> <div>- <a href="https://booping.synth.download/@breaadyboy" target="_blank">bread</a></div><br> <div>"This user is only slightly crazy once was I. 10/10 would recommend"</div> <div>- <a href="https://lea.pet/@subroutine" target="_blank">subroutine</a></div><br> <div>"the f slur but repeated 36 times"</div> <div>- <a href="https://oomfie.city/@cornfields74" target="_blank">corn fields seventy four</a></div><br> <div>"silly cute kitn"</div> <div>- <a href="https://microspinny.zip" target="_blank">niko</a></div><br> <div>"very bitable <img class="emoji" alt="neodog_bite_neocat" src="img/emoji/neodog_bite_neocat.png">"</div> <div>- <a href="https://booping.synth.download/@strongsand" target="_blank">strongsand</a></div> `, webrings: `<div> <a href="https://ctp-webr.ing/trinkey/previous">←</a> <a href="https://ctp-webr.ing/">catppuccin webring</a> <a href="https://ctp-webr.ing/trinkey/next">→</a> </div> <div> <a href="https://fediring.net/previous?host=trinkey.com">←</a> <a href="https://fediring.net/">fediring</a> <a href="https://fediring.net/next?host=trinkey.com">→</a> </div>`, directory: `<div>there's a lot that goes into this website. here are some links for your usage to help you navigate this hellhole</div><br> <div><b><a href="https://trinkey.com/">trinkey.com</a>:</b></div> <div>this is where you are right now</div><br> <div>*<b><a href="https://akkofe.trinkey.com/">akkofe.trinkey.com</a>:</b></div> <div>*<b><a href="https://akkofe2.trinkey.com/">akkofe2.trinkey.com</a>:</b></div> <div>*<b><a href="https://akkofe3.trinkey.com/">akkofe3.trinkey.com</a>:</b></div> <div>the frontend i use for <a href="https://fediverse.info/" target="_blank">fedi</a> (and two clones)</div><br> <div><b><a href="https://auth.trinkey.com/">auth.trinkey.com</a>:</b></div> <div>authentication manager for tSuite</div><br> <div><b><a href="https://blog.trinkey.com/">blog.trinkey.com</a>:</b></div> <div>tBlog, from tSuite</div><br> <div>*<b><a href="https://chuckya.trinkey.com/">chuckya.trinkey.com</a>:</b></div> <div>chuckya (mastodon) frontend for fedi</div><br> <div><b><a href="https://everyone.trinkey.com/">everyone.trinkey.com</a>:</b></div> <div>frontend to a fedi bot that anyone can post to (@everyonebot@is.trinkey.com)</div><br> <div>*<b><a href="https://git.trinkey.com/">git.trinkey.com</a>:</b></div> <div>holds some of my git projects (older ones on <a href="https://github.com/trinkey/" target="_blank">github</a> or <a href="https://git.gay/trinkey/" target="_blank">git.gay</a>)</div><br> <div>*<b><a href="https://is.trinkey.com/">is.trinkey.com</a>:</b></div> <div>hosts <a href="https://iceshrimp.dev/iceshrimp/iceshrimp.net" target="_blank">iceshrimp.net</a>, which is the fedi backend i use</div><br> <div><b><a href="https://jayflame.trinkey.com/">jayflame.trinkey.com</a>:</b></div> <div>the website of my friend <a href="https://www.youtube.com/@jayflame1">Jayflame</a></div><br> <div><b><a href="https://message.trinkey.com/">message.trinkey.com</a>:</b></div> <div>tMessage, from tSuite</div><br> <div><b><a href="https://music.trinkey.com/">music.trinkey.com</a>:</b></div> <div>has some music. i haven't actually updated the site in a while but i've been meaning to do rewrite it at some point. 100% legal i pinky promise</div><br> <div>*<b><a href="https://outpost.trinkey.com/">outpost.trinkey.com</a>:</b></div> <div>the <a href="https://codeberg.org/KittyShopper/mastoapi-fe">outpost</a> frontend for fedi made by kopper</div><br> <div><b><a href="https://smiggins.trinkey.com/">smiggins.trinkey.com</a>:</b></div> <div>official jerimiah smiggins instance, that being my own social media platform</div><br> <div>there's also a qna for me at *<a href="https://trinkey.com/qna/index.php">trinkey.com/qna</a></div><br> <div>(asterisk (*) means i haven't written the code for it)</div><br>` }; const _internal_neofetchOutputs = { desktop: `<pre> <b>...-:::::-...</b> <b class="green">trinkey</b>@<b class="green">desktop</b> <b>.-MMMMMMMMMMMMMMM-.</b> --------------- <b>.-MMMM<span class="green">\`..-:::::::-..\`</span>MMMM-.</b> <b class="green">OS</b>: Linux Mint 21.3 x86_64 <b>.:MMMM<span class="green">.:MMMMMMMMMMMMMMM:.</span>MMMM:.</b> <b class="green">Host</b>: MS-7E27 1.0 <b>-MMM<span class="green">-M---MMMMMMMMMMMMMMMMMMM.</span>MMM-</b> <b class="green">Resolution</b>: 1680x1050, 2560x1440 <b>\`:MMM<span class="green">:MM\` :MMMM:....::-...-MMMM:</span>MMM:\`</b> <b class="green">DE</b>: Cinnamon 6.0.4 <b>:MMM<span class="green">:MMM\` :MM:\` \`\` \`\` \`:MMM:</span>MMM:</b> <b class="green">WM</b>: Mutter (Muffin) <b>.MMM<span class="green">.MMMM\` :MM. -MM. .MM- \`MMMM.</span>MMM.</b> <b class="green">CPU</b>: AMD Ryzen 9 7950X (32) @ 5.881GHz <b>:MMM<span class="green">:MMMM\` :MM. -MM- .MM: \`MMMM-</span>MMM:</b> <b class="green">GPU</b>: AMD ATI 03:00.0 Device 747e <b>:MMM<span class="green">:MMMM\` :MM. -MM- .MM: \`MMMM:</span>MMM:</b> <b class="green">GPU</b>: AMD ATI 11:00.0 Device 164e <b>:MMM<span class="green">:MMMM\` :MM. -MM- .MM: \`MMMM-</span>MMM:</b> <b class="green">Memory</b>: 1MiB / 127901MiB <b>.MMM<span class="green">.MMMM\` :MM:--:MM:--:MM: \`MMMM.</span>MMM.</b> <b>:MMM<span class="green">:MMM- \`-MMMMMMMMMMMM-\` -MMM-</span>MMM:</b> <b>:MMM<span class="green">:MMM:\` \`:MMM:</span>MMM:</b> <b>.MMM<span class="green">.MMMM:--------------:MMMM.</span>MMM.</b> <b>'-MMMM<span class="green">.-MMMMMMMMMMMMMMM-.</span>MMMM-'</b> <b>'.-MMMM<span class="green">\`\`--:::::--\`\`</span>MMMM-.'</b> <b>'-MMMMMMMMMMMMM-'</b> <b>\`\`-:::::-\`\`</b></pre>`, server: `<pre> <b>...-:::::-...</b> <b class="green">trinkey</b>@<b class="green">server</b> <b>.-MMMMMMMMMMMMMMM-.</b> --------------- <b>.-MMMM<span class="green">\`..-:::::::-..\`</span>MMMM-.</b> <b class="green">OS</b>: Linux Mint 21.2 x86_64 <b>.:MMMM<span class="green">.:MMMMMMMMMMMMMMM:.</span>MMMM:.</b> <b class="green">Host</b>: Macmini7,1 1.0 <b>-MMM<span class="green">-M---MMMMMMMMMMMMMMMMMMM.</span>MMM-</b> <b class="green">CPU</b>: Intel i5-4278U (4) @ 3.100GHz <b>\`:MMM<span class="green">:MM\` :MMMM:....::-...-MMMM:</span>MMM:\`</b> <b class="green">GPU</b>: Intel Haswell-ULT <b>:MMM<span class="green">:MMM\` :MM:\` \`\` \`\` \`:MMM:</span>MMM:</b> <b class="green">Memory</b>: 9011MiB / 15866MiB <b>.MMM<span class="green">.MMMM\` :MM. -MM. .MM- \`MMMM.</span>MMM.</b> <b>:MMM<span class="green">:MMMM\` :MM. -MM- .MM: \`MMMM-</span>MMM:</b> <b>:MMM<span class="green">:MMMM\` :MM. -MM- .MM: \`MMMM:</span>MMM:</b> <b>:MMM<span class="green">:MMMM\` :MM. -MM- .MM: \`MMMM-</span>MMM:</b> <b>.MMM<span class="green">.MMMM\` :MM:--:MM:--:MM: \`MMMM.</span>MMM.</b> <b>:MMM<span class="green">:MMM- \`-MMMMMMMMMMMM-\` -MMM-</span>MMM:</b> <b>:MMM<span class="green">:MMM:\` \`:MMM:</span>MMM:</b> <b>.MMM<span class="green">.MMMM:--------------:MMMM.</span>MMM.</b> <b>'-MMMM<span class="green">.-MMMMMMMMMMMMMMM-.</span>MMMM-'</b> <b>'.-MMMM<span class="green">\`\`--:::::--\`\`</span>MMMM-.'</b> <b>'-MMMMMMMMMMMMM-'</b> <b>\`\`-:::::-\`\`</b></pre>` }; const helpText = ` <div> -=== <b class="pink">tSh help</b> ===-</div> <div>--------------------</div> <div>-= <b class="green">cat</b> =-</div> <div>displays the contents of a file</div> <div>-= <b class="green">cd</b> =-</div> <div>changes the working directory</div> <div>-= <b class="green">clear</b> =-</div> <div>clears the terminal output</div> <div>-= <b class="green">help</b> =-</div> <div>shows this help menu</div> <div>-= <b class="green">ls</b> =-</div> <div>lists all files in a directory</div> <div> -l - displays more information about each file</div> <div> -a - displays all files</div> <div> -A - displays all files except implied . and ..</div> <div> -r - reverses the order of the files</div> <div> -R - recurse through all subdirectories</div> <div>-= <b class="green">spin</b> =-</div> <div>creates a new window with a spinning blobcat wireframe</div> <div>-= <b class="green">exit</b> =-</div> <div>closes the terminal window</div>`; const HOME_DIR = "/home/trinkey"; let FILESYSTEM = { home: { type: "directory", name: "home", files: { trinkey: { type: "directory", name: "trinkey", files: { people: { type: "directory", name: "people", files: { "88x31.txt": { type: "file", name: "88x31.txt", content: _internal_defaultFiles.buttons }, "testimonials.txt": { type: "file", name: "testimonials.txt", content: _internal_defaultFiles.testimonials }, "webrings.txt": { type: "file", name: "webrings.txt", content: _internal_defaultFiles.webrings } } }, "about-me.txt": { type: "file", name: "about-me.txt", content: _internal_defaultFiles.about }, "socials.txt": { type: "file", name: "socials.txt", content: _internal_defaultFiles.socials }, "projects.txt": { type: "file", name: "projects.txt", content: _internal_defaultFiles.projects }, "subdomains.txt": { type: "file", name: "subdomains.txt", content: _internal_defaultFiles.directory } } } } }, bin: { type: "directory", name: "bin", files: { cat: { type: "file", name: "cat", content: "<div>function cat(file: string): string { ... }</div>" }, cd: { type: "file", name: "cd", content: "<div>function cd(directory: string): void { ... }</div>" }, clear: { type: "file", name: "clear", content: "<div>function clear(): void { ... }</div>" }, help: { type: "file", name: "help", content: "<div>function help(): string { ... }</div>" }, ls: { type: "file", name: "ls", content: "<div>function ls(directory?: string): string { ... }</div>" } } }, ".secret-file": { type: "file", name: ".secret-file", content: "<div>meow :3</div>" } }; let windowInformation = {}; function commandManager(windowID, command) { let out; if (_internal_commands[command.split(" ")[0]]) { out = _internal_commands[command.split(" ")[0]].callback(command.split(" ").slice(1).join(" ").trim(), windowID); } else if (command == "") { out = ""; } else { out = `<div class="red">Unknown command '${escapeHTML(command.split(" ")[0])}'.</div><div>Type 'help' for a list of commands</div>`; } addWindowCommand(windowID, out); } function addWindowCommand(windowID, value) { let el = document.createElement("div"); el.innerHTML = value; WINDOWS[windowID].element.querySelector(".window").append(el); let dTE = WINDOWS[windowID].element.querySelector("[data-type-area]"); if (dTE) { dTE.removeAttribute("data-type-area"); if (dTE.querySelector("i.cursor")) { dTE.querySelector("i.cursor").remove(); } else if (dTE.querySelector(".cursor")) { dTE.querySelector(".cursor").classList.remove("cursor"); } } WINDOWS[windowID].element.querySelector(".window-header-title").innerText = `${_internal_stringifyPath(windowInformation[windowID].PWD)} - tSh`; let ps1 = document.createElement("div"); ps1.innerHTML = _internal_getPS1(windowInformation[windowID]); let typeArea = document.createElement("span"); typeArea.dataset.typeArea = ""; typeArea.innerHTML = "<i class=\"cursor\"> </i>"; ps1.append(typeArea); WINDOWS[windowID].element.querySelector(".window").append(ps1); }