adding a new code section
This commit is contained in:
@ -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>
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
320
src/main.ts
320
src/main.ts
@ -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
|
||||
@ -326,7 +337,7 @@ export class Editor {
|
||||
if (event.keyCode === keycode) {
|
||||
event.preventDefault();
|
||||
if (event.ctrlKey) {
|
||||
this.api.script(keycode - 111)
|
||||
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,54 +498,53 @@ 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';
|
||||
document.getElementById("docs_midi")!.addEventListener("click", () => {
|
||||
this.currentDocumentationPane = "midi";
|
||||
this.updateDocumentationContent();
|
||||
});
|
||||
|
||||
document.getElementById('docs_functions')!.addEventListener('click', () => {
|
||||
this.currentDocumentationPane = 'functions';
|
||||
document.getElementById("docs_functions")!.addEventListener("click", () => {
|
||||
this.currentDocumentationPane = "functions";
|
||||
this.updateDocumentationContent();
|
||||
});
|
||||
document.getElementById('docs_reference')!.addEventListener('click', () => {
|
||||
this.currentDocumentationPane = 'reference';
|
||||
document.getElementById("docs_reference")!.addEventListener("click", () => {
|
||||
this.currentDocumentationPane = "reference";
|
||||
this.updateDocumentationContent();
|
||||
});
|
||||
document.getElementById('docs_shortcuts')!.addEventListener('click', () => {
|
||||
this.currentDocumentationPane = 'shortcuts';
|
||||
document.getElementById("docs_shortcuts")!.addEventListener("click", () => {
|
||||
this.currentDocumentationPane = "shortcuts";
|
||||
this.updateDocumentationContent();
|
||||
});
|
||||
document.getElementById('docs_about')!.addEventListener('click', () => {
|
||||
this.currentDocumentationPane = 'about';
|
||||
document.getElementById("docs_about")!.addEventListener("click", () => {
|
||||
this.currentDocumentationPane = "about";
|
||||
this.updateDocumentationContent();
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Passing the API to the User
|
||||
Object.entries(this.api).forEach(([name, value]) => {
|
||||
(globalThis as Record<string, any>)[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) {
|
||||
@ -716,7 +735,6 @@ export class Editor {
|
||||
}
|
||||
|
||||
updateEditorView(): void {
|
||||
|
||||
this.view.dispatch({
|
||||
changes: {
|
||||
from: 0,
|
||||
@ -746,7 +764,6 @@ export class Editor {
|
||||
* @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);
|
||||
@ -865,7 +885,7 @@ function reportMouseCoordinates(event: MouseEvent) {
|
||||
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;
|
||||
});
|
||||
Reference in New Issue
Block a user