1 import {onChildEvent, onEnterPress, onSelect} from "../services/dom";
2 import {Component} from "./component";
5 export class CodeEditor extends Component {
8 this.container = this.$refs.container;
10 this.editorInput = this.$refs.editor;
11 this.languageButtons = this.$manyRefs.languageButton;
12 this.languageOptionsContainer = this.$refs.languageOptionsContainer;
13 this.saveButton = this.$refs.saveButton;
14 this.languageInput = this.$refs.languageInput;
15 this.historyDropDown = this.$refs.historyDropDown;
16 this.historyList = this.$refs.historyList;
17 this.favourites = new Set(this.$opts.favourites.split(','));
22 this.historyKey = 'code_history';
23 this.setupListeners();
24 this.setupFavourites();
28 this.container.addEventListener('keydown', event => {
29 if (event.ctrlKey && event.key === 'Enter') {
34 onSelect(this.languageButtons, event => {
35 const language = event.target.dataset.lang;
36 this.languageInput.value = language;
37 this.languageInputChange(language);
40 onEnterPress(this.languageInput, e => this.save());
41 this.languageInput.addEventListener('input', e => this.languageInputChange(this.languageInput.value));
42 onSelect(this.saveButton, e => this.save());
44 onChildEvent(this.historyList, 'button', 'click', (event, elem) => {
45 event.preventDefault();
46 const historyTime = elem.dataset.time;
48 this.editor.setValue(this.history[historyTime]);
54 for (const button of this.languageButtons) {
55 this.setupFavouritesForButton(button);
58 this.sortLanguageList();
62 * @param {HTMLButtonElement} button
64 setupFavouritesForButton(button) {
65 const language = button.dataset.lang;
66 let isFavorite = this.favourites.has(language);
67 button.setAttribute('data-favourite', isFavorite ? 'true' : 'false');
69 onChildEvent(button.parentElement, '.lang-option-favorite-toggle', 'click', () => {
70 isFavorite = !isFavorite;
71 isFavorite ? this.favourites.add(language) : this.favourites.delete(language);
72 button.setAttribute('data-favourite', isFavorite ? 'true' : 'false');
74 window.$http.patch('/preferences/update-code-language-favourite', {
79 this.sortLanguageList();
81 button.scrollIntoView({block: "center", behavior: "smooth"});
87 const sortedParents = this.languageButtons.sort((a, b) => {
88 const aFav = a.dataset.favourite === 'true';
89 const bFav = b.dataset.favourite === 'true';
93 } else if (bFav && !aFav) {
97 return a.dataset.lang > b.dataset.lang ? 1 : -1;
98 }).map(button => button.parentElement);
100 for (const parent of sortedParents) {
101 this.languageOptionsContainer.append(parent);
107 this.callback(this.editor.getValue(), this.languageInput.value);
112 open(code, language, callback) {
113 this.languageInput.value = language;
114 this.callback = callback;
117 .then(() => this.languageInputChange(language))
118 .then(() => window.importVersioned('code'))
119 .then(Code => Code.setContent(this.editor, code));
123 const Code = await window.importVersioned('code');
125 this.editor = Code.popupEditor(this.editorInput, this.languageInput.value);
129 this.popup.components.popup.show(() => {
130 Code.updateLayout(this.editor);
138 this.popup.components.popup.hide();
142 async updateEditorMode(language) {
143 const Code = await window.importVersioned('code');
144 Code.setMode(this.editor, language, this.editor.getValue());
147 languageInputChange(language) {
148 this.updateEditorMode(language);
149 const inputLang = language.toLowerCase();
151 for (const link of this.languageButtons) {
152 const lang = link.dataset.lang.toLowerCase().trim();
153 const isMatch = inputLang === lang;
154 link.classList.toggle('active', isMatch);
156 link.scrollIntoView({block: "center", behavior: "smooth"});
162 this.history = JSON.parse(window.sessionStorage.getItem(this.historyKey) || '{}');
163 const historyKeys = Object.keys(this.history).reverse();
164 this.historyDropDown.classList.toggle('hidden', historyKeys.length === 0);
165 this.historyList.innerHTML = historyKeys.map(key => {
166 const localTime = (new Date(parseInt(key))).toLocaleTimeString();
167 return `<li><button type="button" data-time="${key}" class="text-item">${localTime}</button></li>`;
172 if (!this.editor) return;
173 const code = this.editor.getValue();
176 // Stop if we'd be storing the same as the last item
177 const lastHistoryKey = Object.keys(this.history).pop();
178 if (this.history[lastHistoryKey] === code) return;
180 this.history[String(Date.now())] = code;
181 const historyString = JSON.stringify(this.history);
182 window.sessionStorage.setItem(this.historyKey, historyString);