]> git.ipfire.org Git - ipfire.org.git/blame - src/static/js/editor.js
wiki: editor: Set focus on textarea when launching
[ipfire.org.git] / src / static / js / editor.js
CommitLineData
feeace6e
MT
1class Editor {
2 constructor(parent) {
3 this.parent = $(parent);
4
5 // Get the textarea
6 this.textarea = this.parent.find("textarea");
7
8eff1fbe
MT
8 // Initialise selection
9 this.selection = {
10 start : 0,
11 end : 0,
12 text : "",
13 length : 0,
14 };
15
feeace6e
MT
16 // Make the textarea magic
17 this.activateTextArea();
18
19 // Bind all keys
20 this.bindKeys();
21
22 console.log("Editor initialised for " + this.parent);
717811a7
MT
23
24 // Set focus on the textarea
25 this.textarea.focus();
feeace6e
MT
26 }
27
28 activateTextArea() {
29 var editor = this;
30
31 // Remember any selected text
18c36357 32 this.textarea.on("select keyup click", function(e) {
eea47e20
MT
33 // Ignore any keyboard shortcuts
34 if (e.ctrlKey)
35 return;
36
37 // Save selected text
feeace6e
MT
38 editor.selection = {
39 start : this.selectionStart,
40 end : this.selectionEnd,
18c36357
MT
41 text : this.value.slice(this.selectionStart, this.selectionEnd),
42 length: this.selectionEnd - this.selectionStart,
feeace6e
MT
43 };
44
45 console.debug("Something got selected:");
46 console.debug(editor.selection);
47 })
eea47e20
MT
48
49 // Bind keyboard shortcuts
50 this.textarea.on("keyup", function(e) {
51 // If Ctrl wasn't pressed this isn't for us
52 if (!e.ctrlKey)
53 return;
54
55 switch (e.which) {
56 // B - Bold
57 case 66:
58 editor.bold();
59 break;
60
61 // I - Italic
62 case 73:
63 editor.italic();
64 break;
65
8dea0e28
MT
66 // C - Code
67 case 67:
68 editor.code();
69 break;
70
eea47e20
MT
71 // H - Headline
72 case 72:
73 editor.headline();
74 break;
7b7e6981
MT
75
76 // L - Link
77 case 76:
78 editor.link();
79 break;
eea47e20
MT
80 }
81 });
feeace6e
MT
82 }
83
84 bindKeys() {
18c36357 85 // Typography
feeace6e
MT
86 this.parent.find("#bold").click(this.bold.bind(this));
87 this.parent.find("#italic").click(this.italic.bind(this));
8dea0e28 88 this.parent.find("#code").click(this.code.bind(this));
18c36357
MT
89
90 // Headlines
91 this.parent.find("#headline").click(this.headline.bind(this));
92 this.parent.find("#headline-down").click(this.headline_down.bind(this));
93 this.parent.find("#headline-up").click(this.headline_up.bind(this));
7b7e6981
MT
94
95 // Links
96 this.parent.find("#link").click(this.link.bind(this));
feeace6e
MT
97 }
98
99 // Functions to modify the text
100
101 replaceSelection(replacement) {
6eb53879
MT
102 // Get the DOM element
103 var textarea = this.textarea.get(0);
feeace6e 104
6eb53879
MT
105 // Write text to textarea and move the cursor to the end
106 textarea.setRangeText(replacement,
107 this.selection.start, this.selection.end, "end");
feeace6e
MT
108 }
109
18c36357
MT
110 insertAtCursor(insertion) {
111 this.replaceSelection(insertion);
112 }
113
feeace6e
MT
114 bold() {
115 console.debug("Converting into bold: " + this.selection.text);
116 this.replaceSelection("**" + this.selection.text + "**");
117 }
118
119 italic() {
120 console.debug("Converting into italic: " + this.selection.text);
121 this.replaceSelection("*" + this.selection.text + "*");
122 }
18c36357 123
8dea0e28
MT
124 code() {
125 var multiline = this.selection.text.indexOf("\n");
126
127 if (multiline >= 0) {
128 this.replaceSelection("```\n" + this.selection.text + "\n```\n\n");
129 } else {
130 this.replaceSelection("`" + this.selection.text + "`");
131 }
132 }
133
7b7e6981
MT
134 link() {
135 // Handle URLs
136 if (this.selection.text.startsWith("https://") || this.selection.text.startsWith("http://")) {
137 this.replaceSelection("[" + this.selection.text + "](" + this.selection.text + ")");
138 // Handle selected text
139 } else {
140 this.replaceSelection("[" + this.selection.text + "]()")
141 }
142 }
143
18c36357
MT
144 // Headlines
145
146 findLevel() {
147 // Get all text between start and cursor position
148 var text = this.textarea.val().slice(0, this.selection.start);
149
150 // Split it in lines and reverse
151 var lines = text.split("\n");
152 lines.reverse();
153
154 for (var line of lines) {
155 console.debug(line);
156
157 // Return the number of # found in the nearest headline
158 var match = line.match("^(#+)");
159 if (match) {
160 return match[1].length;
161 }
162 }
163
164 // If nothing was found, we are on level one
165 return 1;
166 }
167
168 insertHeadline(offset) {
169 // Find level of headlines
170 var level = Math.max(this.findLevel() + offset, 1);
171
172 console.debug("Adding headline (" + level + ")");
173 var headline = "#".repeat(level);
174
175 if (this.selection.length == 0) {
176 headline += " ...";
177 } else {
178 // Add some space if we don't have any, yet
179 if (!this.selection.text.startsWith(" "))
180 headline += " ";
181
182 headline += this.selection.text + "\n\n";
183 }
184
185 this.replaceSelection(headline);
186 }
187
188 headline() {
189 return this.insertHeadline(0);
190 }
191
192 headline_down() {
193 return this.insertHeadline(1);
194 }
195
196 headline_up() {
197 return this.insertHeadline(-1);
198 }
feeace6e
MT
199}
200
201$(document).ready(function() {
202 // Initialise all editors
203 $(".editor").each(function(i, e) {
204 new Editor(e);
205 });
206});