adding a new code section

This commit is contained in:
2023-08-19 15:06:32 +02:00
parent fc4107ec02
commit eb6fa8b385
3 changed files with 280 additions and 212 deletions

View File

@ -81,6 +81,7 @@
<div class="flex flex-col">
<p rel="noopener noreferrer" id="docs_introduction" class="pl-2 pr-2 text-xl hover:bg-neutral-800 py-1 my-1 rounded-lg">Introduction </p>
<p rel="noopener noreferrer" id="docs_interface" class="pl-2 pr-2 text-xl hover:bg-neutral-800 py-1 my-1 rounded-lg">Interface</p>
<p rel="noopener noreferrer" id="docs_code" class="pl-2 pr-2 text-xl hover:bg-neutral-800 py-1 my-1 rounded-lg">Code</p>
<p rel="noopener noreferrer" id="docs_time" class="pl-2 pr-2 text-xl hover:bg-neutral-800 py-1 my-1 rounded-lg">Time</p>
<p rel="noopener noreferrer" id="docs_sound" class="pl-2 pr-2 text-xl hover:bg-neutral-800 py-1 my-1 rounded-lg">Sound</p>
<p rel="noopener noreferrer" id="docs_midi" class="pl-2 pr-2 text-xl hover:bg-neutral-800 py-1 my-1 rounded-lg">MIDI</p>

View File

@ -1,11 +1,13 @@
const key_shortcut = (shortcut: string): string => {
return `<kbd class="px-2 py-1.5 text-sm font-semibold text-gray-800 bg-gray-100 border border-gray-200 rounded-lg dark:bg-gray-600 dark:text-gray-100 dark:border-gray-500">${shortcut}</kbd>`
}
return `<kbd class="px-2 py-1.5 text-sm font-semibold text-gray-800 bg-gray-100 border border-gray-200 rounded-lg dark:bg-gray-600 dark:text-gray-100 dark:border-gray-500">${shortcut}</kbd>`;
};
const introduction: string = `
# Welcome
Welcome to the Topos documentation. This documentation companion is made to help you understand the software and the ideas behind Topos. You can summon it anytime by pressing ${key_shortcut('Ctrl + D')}. Press again to make the documentation disappear.
Welcome to the Topos documentation. This documentation companion is made to help you understand the software and the ideas behind Topos. You can summon it anytime by pressing ${key_shortcut(
"Ctrl + D"
)}. Press again to make the documentation disappear.
## What is Topos?
@ -16,7 +18,11 @@ Topos is deeply inspired by the [Monome Teletype](https://monome.org/). The Tele
## Example
Press ${key_shortcut('Ctrl + G')} to switch to the global file. This is where everything starts! Evaluate the following script there by pasting and pressing ${key_shortcut('Ctrl + Enter')}:
Press ${key_shortcut(
"Ctrl + G"
)} to switch to the global file. This is where everything starts! Evaluate the following script there by pasting and pressing ${key_shortcut(
"Ctrl + Enter"
)}:
<pre><code class="language-javascript">
if (bar() % 4 > 2 ) {
@ -32,7 +38,7 @@ if (bar() % 4 > 2 ) {
mod(24) && euclid($('ba'), 5, 8) && sound('cp').out()
}
</code></pre>
`
`;
const software_interface: string = `
# Interface
@ -43,19 +49,29 @@ The Topos interface is molded around the core concepts at play: _scripts_ and _u
Topos works by linking together several scripts into what is called a _universe_:
- the global script (${key_shortcut('Ctrl + G')}): Evaluated for every clock pulse.
- the local scripts (${key_shortcut('Ctrl + L')}): Evaluated _on demand_. Local scripts are storing musical parts, logic or whatever you need!
- the init script (${key_shortcut('Ctrl + I')}): Evaluated on program load. Used to set up the software (_bpm_, etc...).
- the note file (${key_shortcut('Ctrl + N')}): Not evaluated. Used to store thoughts and ideas about the music you are making.
- the global script (${key_shortcut(
"Ctrl + G"
)}): Evaluated for every clock pulse.
- the local scripts (${key_shortcut(
"Ctrl + L"
)}): Evaluated _on demand_. Local scripts are storing musical parts, logic or whatever you need!
- the init script (${key_shortcut(
"Ctrl + I"
)}): Evaluated on program load. Used to set up the software (_bpm_, etc...).
- the note file (${key_shortcut(
"Ctrl + N"
)}): Not evaluated. Used to store thoughts and ideas about the music you are making.
## Universes
A set of files is called a _universe_. Topos can store several universes and switch immediately from one to another. You can switch between universes by pressing ${key_shortcut('Ctrl + B')}. You can also create a new universe by entering a name that has never been used before. _Universes_ are only known by their names.
A set of files is called a _universe_. Topos can store several universes and switch immediately from one to another. You can switch between universes by pressing ${key_shortcut(
"Ctrl + B"
)}. You can also create a new universe by entering a name that has never been used before. _Universes_ are only known by their names.
Switching between universes will not stop the transport nor reset the clock. You are switching the context but time keeps flowing. This can be useful to prepare immediate transitions between songs and parts. Think of universes as an algorithmic set of music. All scripts in a given universe are aware about how many times they have been runned already. You can reset that value programatically.
You can clear the current universe by pressing the flame button on the top right corner of the interface. This will clear all the scripts and the note file. **Note:** there is no shortcut for clearing a universe. We do not want to loose your work by mistake!
`
`;
const time: string = `
# Time
@ -122,7 +138,7 @@ You can use the time functions as conditionals. The following example will play
mod(24) && sound('jvbass').freq(250).out()
}
\`\`\`
`
`;
const midi: string = `
# MIDI
@ -173,17 +189,21 @@ You can use Topos to play MIDI thanks to the [WebMIDI API](https://developer.moz
## MIDI Output Selection
- <icode>midi_outputs()</icode>: Prints a list of available MIDI outputs. You can then use any output name to select the MIDI output you wish to use. **Note:** this function will print to the console. You can open the console by pressing ${key_shortcut('Ctrl + Shift + I')} in many web browsers.
- <icode>midi_outputs()</icode>: Prints a list of available MIDI outputs. You can then use any output name to select the MIDI output you wish to use. **Note:** this function will print to the console. You can open the console by pressing ${key_shortcut(
"Ctrl + Shift + I"
)} in many web browsers.
- <icode>midi_output(output_name: string)</icode>: Selects the MIDI output to use. You can use the <icode>midi_outputs()</icode> function to get a list of available MIDI outputs first. If the MIDI output is not available, the function will do nothing and keep on with the currently selected MIDI Port.
`
`;
const sound: string = `
# Sample playback
The Topos audio engine is based on the [SuperDough](https://www.npmjs.com/package/superdough) audio backend. It is a very powerful and flexible audio backend. It is based on the [Web Audio API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API) and is capable of playing samples, synths, and effects. It is also capable of playing samples and synths in a polyphonic way. It is a very powerful tool to create complex sounds and textures. A set of default sounds are already provided by default but you can also load your own audio samples. They will be loaded through a special URL scheme using the <icode>sample</icode> function.
I recommended you to run the following scripts in the global script (${key_shortcut('Ctrl + G')}).
I recommended you to run the following scripts in the global script (${key_shortcut(
"Ctrl + G"
)}).
## Audio Engine
@ -257,8 +277,7 @@ No sound will play until you add <icode>.out()</icode> at the end of the chain.
| <icode>size(value: number)</icode>| Sets reverb size. |
| <icode>velocity(value: number)</icode>| Sets velocity. |
| <icode>out()</icode> | Returns an object processed by the <icode>superdough</icode> function, using the current values in the <icode>values</icode> object and the <icode>pulse_duration</icode> from the <icode>app.clock</icode>. |
`
`;
const about: string = `
# About Topos
@ -280,14 +299,36 @@ We welcome all contributions and ideas. You can find the source code on [GitHub]
You can also join us on [Discord](https://discord.gg/8Q2QV6Z6) to discuss about the project and live coding in general.
**Have fun!**
`
`;
const code: string = `
# Code
Topos is using the [JavaScript](https://en.wikipedia.org/wiki/JavaScript) syntax because it lives in a web browser where JS is the default programming language. It is also a language that you can learn to speak quite fast if you are already familiar with other programming lanugages. You are not going to write a lot of code anyway but familiarity with the language can help. Here are some good resources:
- [MDN (Mozilla Web Docs)](https://developer.mozilla.org/): it covers pretty much anything and is considered to be a reliable source to learn how the web currently works. We use it quite a lot to develop Topos.
- [Learn JS in Y Minutes](https://learnxinyminutes.com/docs/javascript/): a good tour of the language. Can be useful as a refresher.
- [The Modern JavaScript Tutorial](https://javascript.info/): another well known source to learn the language.
You **do not need to have any prior knowledge of programming** to use Topos. It can also be used as a **valuable resource** to learn some basic programming.
## How is the code evaluated?
The code you enter in any of the scripts is evaluated in strict mode. This tells your browser that the code you run can be optimized quite agressively. We need this because by default, **the global script is evaluated 48 times per beat**. It also means that you can crash at the speed of light :smile:. The local and initialisation scripts are evaluated on demand, one run at a time. There are some things to keep in mind:
- **about variables:** the state of your variables is not kept between iterations. If you write <icode>let a = 2</icode> and change the value later on, the value will be reset to <icode>2</icode> after each run! There are other ways to deal with variables and to share variables between scripts! Some variables like **iterators** can keep their state between iterations because they are saved **with the file itself**.
- **about errors and printing:** your code will crash! Don't worry, it will hopefully try to crash in the most gracious way possible. To check if your code is erroring, you will have to open the dev console with ${key_shortcut( "Ctrl + Shift + I")}. You cannot directly use <icode>console.log('hello, world')</icode> in the interface. You will have to open the console as well to see your messages being printed there!
`;
const functions: string = `
# Functions
`
`;
const reference: string = `
# Reference
`
`;
const shortcuts: string = `
# Keybindings
@ -296,39 +337,45 @@ Topos is made to be controlled entirely with a keyboard. It is recommanded to st
## Transport
- **Start** the transport: ${key_shortcut('Ctrl + P')}.
- **Pause** the transport: ${key_shortcut('Ctrl + S')}.
- **Rewind** the transport: ${key_shortcut('Ctrl + R')}.
- **Start** the transport: ${key_shortcut("Ctrl + P")}.
- **Pause** the transport: ${key_shortcut("Ctrl + S")}.
- **Rewind** the transport: ${key_shortcut("Ctrl + R")}.
## Moving in the interface
- Switch to a different universe: ${key_shortcut('Ctrl + B')}.
- Switch to the global script: ${key_shortcut('Ctrl + G')} or ${key_shortcut('F10')}.
- Switch to the local scripts: ${key_shortcut('Ctrl + L')} or ${key_shortcut('F11')}.
- Switch to the init script: ${key_shortcut('Ctrl + L')}.
- Switch to the note file: ${key_shortcut('Ctrl + N')}.
- Switch to a local file: ${key_shortcut('F1')} to ${key_shortcut('F9')}.
- Toggle the documentation: ${key_shortcut('Ctrl + D')}.
- Switch to a different universe: ${key_shortcut("Ctrl + B")}.
- Switch to the global script: ${key_shortcut("Ctrl + G")} or ${key_shortcut(
"F10"
)}.
- Switch to the local scripts: ${key_shortcut("Ctrl + L")} or ${key_shortcut(
"F11"
)}.
- Switch to the init script: ${key_shortcut("Ctrl + L")}.
- Switch to the note file: ${key_shortcut("Ctrl + N")}.
- Switch to a local file: ${key_shortcut("F1")} to ${key_shortcut("F9")}.
- Toggle the documentation: ${key_shortcut("Ctrl + D")}.
## Evaluating code
- Evaluate the current script: ${key_shortcut('Ctrl + Enter')}.
- Evaluate a local script: ${key_shortcut('Ctrl + F1')} to ${key_shortcut('Ctrl + F9')}.
- Evaluate the current script: ${key_shortcut("Ctrl + Enter")}.
- Evaluate a local script: ${key_shortcut("Ctrl + F1")} to ${key_shortcut(
"Ctrl + F9"
)}.
## Special
- Switch the editor to Vim Mode: ${key_shortcut('Ctrl + V')}.
`
- Switch the editor to Vim Mode: ${key_shortcut("Ctrl + V")}.
`;
export const documentation = {
introduction: introduction,
interface: software_interface,
time: time,
sound: sound,
midi: midi,
functions: functions,
reference: reference,
shortcuts: shortcuts,
about: about,
}
introduction: introduction,
interface: software_interface,
code: code,
time: time,
sound: sound,
midi: midi,
functions: functions,
reference: reference,
shortcuts: shortcuts,
about: about,
};

View File

@ -7,7 +7,7 @@ import { Extension } from "@codemirror/state";
import { vim } from "@replit/codemirror-vim";
import { AppSettings } from "./AppSettings";
import { editorSetup } from "./EditorSetup";
import { documentation} from './Documentation';
import { documentation } from "./Documentation";
import { EditorView } from "codemirror";
import { Clock } from "./Clock";
import { UserAPI } from "./API";
@ -24,46 +24,46 @@ type Documentation = { [key: string]: string };
const Docs: Documentation = documentation;
// Importing showdown and setting up the markdown converter
import showdown from 'showdown';
showdown.setFlavor('github')
import showdownHighlight from 'showdown-highlight';
import showdown from "showdown";
showdown.setFlavor("github");
import showdownHighlight from "showdown-highlight";
const classMap = {
h1: 'text-4xl text-white ml-4 mx-4 my-4 mb-8',
h2: 'text-3xl text-white mx-4 my-4 mt-12 mb-6',
ul: 'text-underline',
li: 'ml-12 list-disc text-2xl text-white mx-4 my-4 leading-normal',
p: 'text-2xl text-white mx-4 my-4 leading-normal',
a: 'text-2xl text-orange-300',
h1: "text-4xl text-white ml-4 mx-4 my-4 mb-8",
h2: "text-3xl text-white mx-4 my-4 mt-12 mb-6",
ul: "text-underline",
li: "ml-12 list-disc text-2xl text-white mx-4 my-4 leading-normal",
p: "text-2xl text-white mx-4 my-4 leading-normal",
a: "text-2xl text-orange-300",
code: "my-4 block whitespace-pre overflow-x-scroll",
icode: "my-4 text-white font-mono bg-neutral-600",
blockquote: "text-neutral-200 border-l-4 border-neutral-500 pl-4 my-4 mx-4",
table: "justify-center my-8 mx-8 text-2xl w-full text-left text-white border-collapse",
thead: "text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400",
table:
"justify-center my-8 mx-8 text-2xl w-full text-left text-white border-collapse",
thead:
"text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400",
th: "px-6 py-6",
td: "py-2",
tr: "py-0",
}
const bindings = Object.keys(classMap)
.map(key => ({
type: 'output',
regex: new RegExp(`<${key}([^>]*)>`, 'g'),
//@ts-ignore
replace: (match, p1) => `<${key} class="${classMap[key]}" ${p1}>`
}));
};
const bindings = Object.keys(classMap).map((key) => ({
type: "output",
regex: new RegExp(`<${key}([^>]*)>`, "g"),
//@ts-ignore
replace: (match, p1) => `<${key} class="${classMap[key]}" ${p1}>`,
}));
// Importing the documentation from separate files in the ./src/documentation/* folder
export class Editor {
universes: Universes = template_universes;
selected_universe: string;
local_index: number = 1;
editor_mode: "global" | "local" | "init" | "notes" = "local";
fontSize: Compartment;
withLineNumbers: Compartment;
vimModeCompartment : Compartment;
chosenLanguage: Compartment
currentDocumentationPane: string = "introduction"
vimModeCompartment: Compartment;
chosenLanguage: Compartment;
currentDocumentationPane: string = "introduction";
settings = new AppSettings();
editorExtensions: Extension[] = [];
@ -98,7 +98,9 @@ export class Editor {
document.getElementById("clear-button-1") as HTMLButtonElement,
document.getElementById("clear-button-2") as HTMLButtonElement,
];
documentation_button: HTMLButtonElement = document.getElementById("doc-button-1") as HTMLButtonElement;
documentation_button: HTMLButtonElement = document.getElementById(
"doc-button-1"
) as HTMLButtonElement;
// Script selection elements
local_button: HTMLButtonElement = document.getElementById(
@ -117,7 +119,7 @@ export class Editor {
"settings-button"
) as HTMLButtonElement;
close_settings_button: HTMLButtonElement = document.getElementById(
'close-settings-button'
"close-settings-button"
) as HTMLButtonElement;
universe_viewer: HTMLDivElement = document.getElementById(
"universe-viewer"
@ -137,15 +139,25 @@ export class Editor {
) as HTMLDivElement;
// Font Size Slider
font_size_slider: HTMLInputElement = document.getElementById('font-size-slider') as HTMLInputElement;
font_size_witness: HTMLSpanElement = document.getElementById('font-size-witness') as HTMLSpanElement;
font_size_slider: HTMLInputElement = document.getElementById(
"font-size-slider"
) as HTMLInputElement;
font_size_witness: HTMLSpanElement = document.getElementById(
"font-size-witness"
) as HTMLSpanElement;
// Line Numbers checkbox
line_numbers_checkbox: HTMLInputElement = document.getElementById('show-line-numbers') as HTMLInputElement;
line_numbers_checkbox: HTMLInputElement = document.getElementById(
"show-line-numbers"
) as HTMLInputElement;
// Editor mode selection
normal_mode_button: HTMLButtonElement = document.getElementById('normal-mode') as HTMLButtonElement;
vim_mode_button: HTMLButtonElement = document.getElementById('vim-mode') as HTMLButtonElement;
normal_mode_button: HTMLButtonElement = document.getElementById(
"normal-mode"
) as HTMLButtonElement;
vim_mode_button: HTMLButtonElement = document.getElementById(
"vim-mode"
) as HTMLButtonElement;
constructor() {
// ================================================================================
@ -178,22 +190,22 @@ export class Editor {
this.chosenLanguage = new Compartment();
this.fontSize = new Compartment();
const vimPlugin = this.settings.vimMode ? vim() : [];
const lines = this.settings.line_numbers? lineNumbers() : [];
const fontSizeModif = EditorView.theme( {
"&": {
const lines = this.settings.line_numbers ? lineNumbers() : [];
const fontSizeModif = EditorView.theme({
"&": {
fontSize: `${this.settings.font_size}px`,
},
".cm-gutters": {
fontSize: `${this.settings.font_size}px`,
}
})
},
".cm-gutters": {
fontSize: `${this.settings.font_size}px`,
},
});
this.editorExtensions = [
this.withLineNumbers.of(lines),
this.fontSize.of(fontSizeModif),
this.vimModeCompartment.of(vimPlugin),
editorSetup,
oneDark,
oneDark,
this.chosenLanguage.of(javascript()),
EditorView.updateListener.of((v: ViewUpdate) => {
v;
@ -238,7 +250,6 @@ export class Editor {
this.clock.stop();
}
if (event.ctrlKey && event.key === "p") {
event.preventDefault();
this.setButtonHighlighting("play", true);
@ -263,7 +274,7 @@ export class Editor {
if ((event.key === "Enter" || event.key === "Return") && event.ctrlKey) {
event.preventDefault();
this.currentFile().candidate = this.view.state.doc.toString();
this.flashBackground('#2d313d', 200)
this.flashBackground("#2d313d", 200);
}
// Shift + Enter or Ctrl + E: evaluate the line
@ -273,7 +284,7 @@ export class Editor {
) {
event.preventDefault(); // Prevents the addition of a new line
this.currentFile().candidate = this.view.state.doc.toString();
this.flashBackground('#2d313d', 200)
this.flashBackground("#2d313d", 200);
}
// This is the modal to switch between universes
@ -325,8 +336,8 @@ export class Editor {
(keycode, index) => {
if (event.keyCode === keycode) {
event.preventDefault();
if (event.ctrlKey) {
this.api.script(keycode - 111)
if (event.ctrlKey) {
this.api.script(keycode - 111);
} else {
this.changeModeFromInterface("local");
this.changeToLocalBuffer(index);
@ -336,14 +347,14 @@ export class Editor {
}
);
if (event.keyCode == 121) {
this.changeModeFromInterface("global");
this.hideDocumentation();
}
if (event.keyCode == 122) {
this.changeModeFromInterface("init");
this.hideDocumentation();
}
if (event.keyCode == 121) {
this.changeModeFromInterface("global");
this.hideDocumentation();
}
if (event.keyCode == 122) {
this.changeModeFromInterface("init");
this.hideDocumentation();
}
});
// ================================================================================
@ -387,7 +398,7 @@ export class Editor {
this.documentation_button.addEventListener("click", () => {
this.showDocumentation();
})
});
this.pause_buttons.forEach((button) => {
button.addEventListener("click", () => {
@ -416,24 +427,26 @@ export class Editor {
this.changeModeFromInterface("notes")
);
this.settings_button.addEventListener("click", () => {
this.font_size_slider.value = this.settings.font_size.toString();
this.font_size_witness.innerHTML = `Font Size: ${this.settings.font_size}px`
this.font_size_witness?.setAttribute('style', `font-size: ${this.settings.font_size}px;`)
this.font_size_witness.innerHTML = `Font Size: ${this.settings.font_size}px`;
this.font_size_witness?.setAttribute(
"style",
`font-size: ${this.settings.font_size}px;`
);
this.line_numbers_checkbox.checked = this.settings.line_numbers;
let modal_settings = document.getElementById('modal-settings');
let editor = document.getElementById('editor');
modal_settings?.classList.remove('invisible')
editor?.classList.add('invisible')
})
let modal_settings = document.getElementById("modal-settings");
let editor = document.getElementById("editor");
modal_settings?.classList.remove("invisible");
editor?.classList.add("invisible");
});
this.close_settings_button.addEventListener("click", () => {
let modal_settings = document.getElementById('modal-settings');
let editor = document.getElementById('editor');
modal_settings?.classList.add('invisible')
editor?.classList.remove('invisible')
})
let modal_settings = document.getElementById("modal-settings");
let editor = document.getElementById("editor");
modal_settings?.classList.add("invisible");
editor?.classList.remove("invisible");
});
this.font_size_slider.addEventListener("input", () => {
const new_value = this.font_size_slider.value;
@ -442,19 +455,19 @@ export class Editor {
this.font_size_witness.innerHTML = `Font Size: ${new_value}px`;
let new_font_size = EditorView.theme({
"&": { fontSize : new_value + "px", },
".cm-gutters": { fontSize : new_value + "px", },
"&": { fontSize: new_value + "px" },
".cm-gutters": { fontSize: new_value + "px" },
});
this.view.dispatch({
effects: this.fontSize.reconfigure(new_font_size)
effects: this.fontSize.reconfigure(new_font_size),
});
this.settings.font_size = parseInt(new_value);
})
});
this.normal_mode_button.addEventListener("click", () => {
this.settings.vimMode = false;
this.view.dispatch({effects: this.vimModeCompartment.reconfigure([])});
})
this.view.dispatch({ effects: this.vimModeCompartment.reconfigure([]) });
});
this.line_numbers_checkbox.addEventListener("change", () => {
let checked = this.line_numbers_checkbox.checked ? true : false;
@ -462,14 +475,16 @@ export class Editor {
this.view.dispatch({
effects: this.withLineNumbers.reconfigure(
checked ? [lineNumbers()] : []
)
),
});
});
this.vim_mode_button.addEventListener("click", () => {
this.settings.vimMode = true;
this.view.dispatch({effects: this.vimModeCompartment.reconfigure(vim())});
})
this.view.dispatch({
effects: this.vimModeCompartment.reconfigure(vim()),
});
});
this.buffer_search.addEventListener("keydown", (event) => {
if (event.key === "Enter") {
@ -483,53 +498,52 @@ export class Editor {
}
}
});
tryEvaluate(
this,
this.universes[this.selected_universe.toString()].init,
)
tryEvaluate(this, this.universes[this.selected_universe.toString()].init);
// Setting up the documentation page
document.getElementById('docs_introduction')!.addEventListener('click', () => {
this.currentDocumentationPane = 'introduction';
document
.getElementById("docs_introduction")!
.addEventListener("click", () => {
this.currentDocumentationPane = "introduction";
this.updateDocumentationContent();
});
document.getElementById("docs_interface")!.addEventListener("click", () => {
this.currentDocumentationPane = "interface";
this.updateDocumentationContent();
});
document.getElementById('docs_interface')!.addEventListener('click', () => {
this.currentDocumentationPane = 'interface';
document.getElementById("docs_code")!.addEventListener("click", () => {
this.currentDocumentationPane = "code";
this.updateDocumentationContent();
});
document.getElementById('docs_time')!.addEventListener('click', () => {
this.currentDocumentationPane = 'time';
document.getElementById("docs_time")!.addEventListener("click", () => {
this.currentDocumentationPane = "time";
this.updateDocumentationContent();
});
document.getElementById('docs_sound')!.addEventListener('click', () => {
this.currentDocumentationPane = 'sound';
document.getElementById("docs_sound")!.addEventListener("click", () => {
this.currentDocumentationPane = "sound";
this.updateDocumentationContent();
});
document.getElementById('docs_midi')!.addEventListener('click', () => {
this.currentDocumentationPane = 'midi';
this.updateDocumentationContent();
});
document.getElementById('docs_functions')!.addEventListener('click', () => {
this.currentDocumentationPane = 'functions';
this.updateDocumentationContent();
});
document.getElementById('docs_reference')!.addEventListener('click', () => {
this.currentDocumentationPane = 'reference';
this.updateDocumentationContent();
});
document.getElementById('docs_shortcuts')!.addEventListener('click', () => {
this.currentDocumentationPane = 'shortcuts';
this.updateDocumentationContent();
});
document.getElementById('docs_about')!.addEventListener('click', () => {
this.currentDocumentationPane = 'about';
document.getElementById("docs_midi")!.addEventListener("click", () => {
this.currentDocumentationPane = "midi";
this.updateDocumentationContent();
});
document.getElementById("docs_functions")!.addEventListener("click", () => {
this.currentDocumentationPane = "functions";
this.updateDocumentationContent();
});
document.getElementById("docs_reference")!.addEventListener("click", () => {
this.currentDocumentationPane = "reference";
this.updateDocumentationContent();
});
document.getElementById("docs_shortcuts")!.addEventListener("click", () => {
this.currentDocumentationPane = "shortcuts";
this.updateDocumentationContent();
});
document.getElementById("docs_about")!.addEventListener("click", () => {
this.currentDocumentationPane = "about";
this.updateDocumentationContent();
});
// Passing the API to the User
Object.entries(this.api).forEach(([name, value]) => {
@ -550,46 +564,47 @@ export class Editor {
}
get local_buffer() {
return this.universes[this.selected_universe.toString()].locals[this.local_index];
return this.universes[this.selected_universe.toString()].locals[
this.local_index
];
}
showDocumentation() {
if (document.getElementById("app")?.classList.contains("hidden")) {
document.getElementById('app')?.classList.remove('hidden');
document.getElementById('documentation')?.classList.add('hidden');
} else {
document.getElementById('app')?.classList.add('hidden');
document.getElementById('documentation')?.classList.remove('hidden');
if (document.getElementById("app")?.classList.contains("hidden")) {
document.getElementById("app")?.classList.remove("hidden");
document.getElementById("documentation")?.classList.add("hidden");
} else {
document.getElementById("app")?.classList.add("hidden");
document.getElementById("documentation")?.classList.remove("hidden");
// Load and convert Markdown content from the documentation file
this.updateDocumentationContent();
}
// Load and convert Markdown content from the documentation file
this.updateDocumentationContent();
}
}
hideDocumentation() {
if (document.getElementById("app")?.classList.contains("hidden")) {
document.getElementById('app')?.classList.remove('hidden');
document.getElementById('documentation')?.classList.add('hidden');
}
if (document.getElementById("app")?.classList.contains("hidden")) {
document.getElementById("app")?.classList.remove("hidden");
document.getElementById("documentation")?.classList.add("hidden");
}
}
updateDocumentationContent() {
const converter = new showdown.Converter({
emoji: true,
moreStyling: true,
extensions: [
showdownHighlight({auto_detection: true}),
...bindings,
]
extensions: [showdownHighlight({ auto_detection: true }), ...bindings],
});
const converted_markdown = converter.makeHtml(
Docs[this.currentDocumentationPane]
);
function wrapCodeWithPre(inputString: string): string {
let newString = inputString.replace(/<code>/g, '<pre><code>');
newString = newString.replace(/<\/code>/g, '</code></pre>');
let newString = inputString.replace(/<code>/g, "<pre><code>");
newString = newString.replace(/<\/code>/g, "</code></pre>");
return newString;
}
document.getElementById('documentation-content')!.innerHTML = wrapCodeWithPre(converted_markdown);
document.getElementById("documentation-content")!.innerHTML =
wrapCodeWithPre(converted_markdown);
}
changeToLocalBuffer(i: number) {
@ -606,10 +621,11 @@ export class Editor {
}
changeModeFromInterface(mode: "global" | "local" | "init" | "notes") {
const interface_buttons: HTMLElement[] = [
this.local_button, this.global_button,
this.init_button, this.note_button,
this.local_button,
this.global_button,
this.init_button,
this.note_button,
];
let changeColor = (button: HTMLElement) => {
@ -620,18 +636,17 @@ export class Editor {
button.classList.remove("text-orange-300");
}
});
button.children[0].classList.remove('text-white');
button.children[0].classList.remove("text-white");
button.children[0].classList.add("text-orange-300");
button.classList.add("text-orange-300");
};
switch (mode) {
case "local":
if (this.local_script_tabs.classList.contains("hidden")) {
this.local_script_tabs.classList.remove("hidden");
}
this.editor_mode = 'local';
this.editor_mode = "local";
this.local_index = 0;
this.changeToLocalBuffer(this.local_index);
changeColor(this.local_button);
@ -640,21 +655,21 @@ export class Editor {
if (!this.local_script_tabs.classList.contains("hidden")) {
this.local_script_tabs.classList.add("hidden");
}
this.editor_mode = "global"
this.editor_mode = "global";
changeColor(this.global_button);
break;
case "init":
if (!this.local_script_tabs.classList.contains("hidden")) {
this.local_script_tabs.classList.add("hidden");
}
this.editor_mode = "init"
this.editor_mode = "init";
changeColor(this.init_button);
break;
case "notes":
if (!this.local_script_tabs.classList.contains("hidden")) {
this.local_script_tabs.classList.add("hidden");
}
this.editor_mode = "notes"
this.editor_mode = "notes";
changeColor(this.note_button);
break;
}
@ -662,8 +677,10 @@ export class Editor {
// If the editor is in notes mode, we need to update the selectedLanguage
this.view.dispatch({
effects: this.chosenLanguage.reconfigure(this.editor_mode == "notes" ? [markdown()] : [javascript()])
})
effects: this.chosenLanguage.reconfigure(
this.editor_mode == "notes" ? [markdown()] : [javascript()]
),
});
this.updateEditorView();
}
@ -672,10 +689,12 @@ export class Editor {
button: "play" | "pause" | "stop" | "clear",
highlight: boolean
) {
this.flashBackground('#2d313d', 200)
this.flashBackground("#2d313d", 200);
const possible_selectors = [
'[id^="play-button-"]', '[id^="pause-button-"]',
'[id^="clear-button-"]', '[id^="stop-button-"]',
'[id^="play-button-"]',
'[id^="pause-button-"]',
'[id^="clear-button-"]',
'[id^="stop-button-"]',
];
let selector: number;
switch (button) {
@ -688,7 +707,7 @@ export class Editor {
case "clear":
selector = 2;
break;
case "stop":
case "stop":
selector = 3;
break;
}
@ -716,10 +735,9 @@ export class Editor {
}
updateEditorView(): void {
this.view.dispatch({
changes: {
from: 0,
from: 0,
to: this.view.state.doc.toString().length,
insert: this.currentFile().candidate,
},
@ -731,7 +749,7 @@ export class Editor {
*/
currentFile(): File {
switch (this.editor_mode) {
case "global":
case "global":
return this.global_buffer;
case "local":
return this.local_buffer;
@ -743,10 +761,9 @@ export class Editor {
}
/**
* @param universeName: The name of the universe to load
* @param universeName: The name of the universe to load
*/
loadUniverse(universeName: string): void {
// Saving the current file before initiating the switch logic
this.currentFile().candidate = this.view.state.doc.toString();
@ -763,9 +780,7 @@ export class Editor {
this.updateEditorView();
// Evaluating the initialisation script for the selected universe
tryEvaluate(this,
this.universes[this.selected_universe.toString()].init,
)
tryEvaluate(this, this.universes[this.selected_universe.toString()].init);
}
openSettingsModal(): void {
@ -784,7 +799,7 @@ export class Editor {
document.getElementById("modal-settings")!.classList.add("invisible");
}
openBuffersModal():void {
openBuffersModal(): void {
// If the modal is hidden, unhide it and hide the editor
if (
document.getElementById("modal-buffers")!.classList.contains("invisible")
@ -797,7 +812,7 @@ export class Editor {
}
}
closeBuffersModal():void {
closeBuffersModal(): void {
// @ts-ignore
document.getElementById("buffer-search")!.value = "";
document.getElementById("editor")!.classList.remove("invisible");
@ -812,13 +827,19 @@ export class Editor {
flashBackground(color: string, duration: number): void {
// Set the flashing color
this.view.dom.style.backgroundColor = color;
const gutters = this.view.dom.getElementsByClassName("cm-gutter") as HTMLCollectionOf<HTMLElement>;
Array.from(gutters).forEach(gutter => gutter.style.backgroundColor = color);
const gutters = this.view.dom.getElementsByClassName(
"cm-gutter"
) as HTMLCollectionOf<HTMLElement>;
Array.from(gutters).forEach(
(gutter) => (gutter.style.backgroundColor = color)
);
// Reset to original color after duration
setTimeout(() => {
this.view.dom.style.backgroundColor = "";
Array.from(gutters).forEach(gutter => gutter.style.backgroundColor = "");
Array.from(gutters).forEach(
(gutter) => (gutter.style.backgroundColor = "")
);
}, duration);
}
}
@ -836,10 +857,9 @@ function startClock() {
document
.getElementById("start-button")!
.removeEventListener("click", startClock);
document
.removeEventListener("click", startClock);
document.removeEventListener("click", startClock);
document.removeEventListener("keydown", startOnEnter);
document.removeEventListener("click", startOnClick)
document.removeEventListener("click", startOnClick);
app.clock.start();
app.view.focus();
app.setButtonHighlighting("play", true);
@ -864,8 +884,8 @@ function reportMouseCoordinates(event: MouseEvent) {
app._mouseX = event.clientX;
app._mouseY = event.clientY;
}
window.addEventListener('mousemove', reportMouseCoordinates);
window.addEventListener("mousemove", reportMouseCoordinates);
// When the user leaves the page, all the universes should be saved in the localStorage
window.addEventListener("beforeunload", () => {
@ -875,6 +895,6 @@ window.addEventListener("beforeunload", () => {
app.currentFile().candidate = app.view.state.doc.toString();
app.currentFile().committed = app.view.state.doc.toString();
app.settings.saveApplicationToLocalStorage(app.universes, app.settings);
app.clock.stop()
app.clock.stop();
return null;
});
});