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