1 <?php
2 require 'core.php';
3
4 require_login();
5
6 $page_name = $_REQUEST['page'];
7 $fname = "${GLOBALS['page_dir']}/${page_name}.html";
8
9 if(strlen($page_name) < 1){
10 echo "Error: No page name specified.";
11 exit;
12 }
13 ?>
14 <!DOCTYPE html>
15 <html lang="<?=$GLOBALS['lang']?>">
16 <head>
17 <title>Wiki</title>
18 <meta charset="utf-8">
19 <meta name="viewport" content="width=device-width, initial-scale=1">
20 <link rel="icon" type="image/png" sizes="32x32" href="icon32x32.png">
21 <style>
22 body {
23 margin: auto;
24 padding: 20px;
25 max-width: 1400px;
26 font-size: 1.2em;
27 background: #FFE;
28 }
29 .toolbar {
30 width: 100%;
31 text-align: right;
32 }
33 .toolbar button {
34 padding: 4px;
35 margin: 4px;
36 font-size: 18px;
37 height: 30px;
38 min-width: 30px;
39 border: 1px solid #000;
40 border-radius: 3px;
41 }
42 #tool_save { background: #B8FFB8; }
43 #tool_cancel { background: #FFDADA; }
44
45 #editor {
46 display: flex;
47 width: 100%;
48 }
49 #html_view {
50 flex: 1;
51 padding: 5px;
52 border: 4px solid #EEC;
53 max-width: 700px;
54 background: #FFF;
55 }
56 #code_view {
57 flex: 1;
58 background: white;
59 }
60 #code_view form { width: 100%; height: 100%; }
61 #code_view textarea {
62 width: 100%;
63 height: 100%;
64 padding: 10px;
65 box-sizing: border-box;
66 background: #333;
67 color: #fdd;
68 font-size: 1.1em;
69 }
70 iframe.link-creator {
71 width: 100%;
72 border: none;
73 height: 160px;
74 overflow: auto;
75 }
76 .help-table {
77 width: 400px;
78 background: #ffe8ce;
79 border: 1px solid black;
80 border-collapse: collapse;
81 float: right;
82 }
83 .help-table td { border-bottom: 1px solid #b7a591; padding: 5px; }
84 .help_code { font-family: monospace; }
85 </style>
86 </head>
87 <body>
88
89 <div class="toolbar">
90 <button id="tool_help">Help</button>
91 <button id="tool_link">Insert Link</button>
92 <button id="tool_cancel">Discard Changes</button>
93 <button id="tool_save">Save Changes</button>
94 </div>
95
96 <div id="syntax_help" style="display: none; ">
97 <table inert="inert" class="help-table">
98 <tr><td class="help_code">= Heading</td>
99 <td style="font-size: 1.3em; font-weight:bold;">Heading</td>
100 </tr>
101 <tr><td class="help_code">== Sub-Heading</td>
102 <td style="font-size: 1.1em; font-weight:bold;">Sub-Heading</td>
103 </tr>
104 <tr><td class="help_code">pagename[]</td>
105 <td><a href="#">pagename</a></td>
106 </tr>
107 <tr><td class="help_code">pagename[Page Name]</td>
108 <td><a href="#">Page Name</a></td>
109 </tr>
110 </table>
111 </div>
112
113 <div id="link_creator" style="display: none;"></div>
114
115 <div id="editor">
116 <!-- the inert attribute keeps the links from being clickable -->
117 <div id="html_view" inert="inert"><?php
118 if(file_exists($fname)){
119 include $fname;
120 }
121 else{
122 echo "<h1>$page_name</h1>\n\n<p>Edit me!</p>";
123 }
124 ?></div>
125 <div id="code_view">
126 <textarea name="body"></textarea>
127 </div>
128 </div>
129 <form id="my_form" action="save.php?page=<?=$page_name?>" method="post">
130 <input id="my_body" type="hidden" name="body">
131 </form>
132
133 <script>
134 var link_prefix = '<?=$GLOBALS['wiki_link_path']?>';
135
136 function debounce(ms, callback){
137 var timer;
138 return function () {
139 clearTimeout(timer);
140 timer = setTimeout(callback, ms);
141 }
142 }
143
144 var html_view = document.getElementById('html_view');
145 var code_area = document.querySelector('#code_view textarea');
146
147
148 // Keep the two panes in sync.
149 code_area.addEventListener('input', debounce(500, c2h));
150 //html_view.addEventListener('input', debounce(500, h2c));
151
152 // One-time conversion of extremely limited subset of HTML
153 // to a light markup alternative:
154 function h2c(){
155 var i,j,e,e2,p,href;
156
157 // We *always* start with the title on the first line
158 var title_tag = html_view.querySelector('h1');
159 var txt = title_tag ? title_tag.textContent : 'Untitled';
160 if(txt.length < 1){ txt = 'Untitled'; }
161 txt += "\n\n";
162
163 // old skool 'for' loop required for element collection
164 for(var i=0; i<html_view.children.length; i++){
165 e = html_view.children[i];
166 switch(e.nodeName){
167 case 'H1': continue; // We've already taken care of the title
168 case 'H2': p = '# ' + e.textContent + "\n\n"; break;
169 case 'H3': p = '## ' + e.textContent + "\n\n"; break;
170 case 'img': p = 'img:' + e.getAttribute('src') + "\n"; break;
171 case 'P':
172 p='';
173 for(j=0; j<e.childNodes.length; j++){
174 e2 = e.childNodes[j];
175 if(e2.nodeType === Node.TEXT_NODE){
176 p += e2.textContent;
177 }
178
179 if(e2.nodeType === Node.ELEMENT_NODE){
180 if(e2.nodeName === 'A'){
181 href = e2.getAttribute('href');
182 if(href.startsWith(link_prefix)){
183 href = href.replace(link_prefix,"");
184 }
185 p += href + '[' + e2.textContent + ']\n';
186 }
187 }
188 }
189 p += "\n";
190 break;
191 default: p = '<html>\n' + e.outerHTML + '\n</html>\n\n';
192 }
193 txt += p;
194 }
195
196 code_area.value = txt;// + html_view.innerHTML;
197 }
198
199 var rx_h2=/^# (.*)$/;
200 var rx_h3=/^## (.*)$/;
201 var rx_img=/^img:(.*)$/;
202 var rx_a=/^([^[]+)\[(.*)\]/;
203 var rx_html=/^\<html\>$/;
204 var rx_end_html=/^\<\/html\>$/;
205 var rx_blank=/^\s*$/;
206
207 function c2h(){
208 var line, m, link_title;
209 var lines = code_area.value.split(/\r\n|\r|\n/);
210 var para_open = false;
211
212 // Title always first
213 var title = lines[0];
214 if(title.length < 1){ title = "Untitled"; }
215 var html = "<h1>" + title + "</h1>\n";
216
217 for(var i=1; i<lines.length; i++){
218 line = lines[i];
219 if(m = rx_h2.exec(line)){ close_p(); html += '<h2>' + m[1] + '</h2>\n'; continue; }
220 if(m = rx_h3.exec(line)){ close_p(); html += '<h3>' + m[1] + '</h3>\n'; continue; }
221
222 if(m = rx_a.exec(line)){
223 open_p();
224 link_title = m[2];
225 if(link_title.length < 1){
226 link_title = m[1];
227 }
228 html += '<a href="' + link_prefix + m[1] + '">' + link_title + '</a>';
229 continue;
230 }
231 if(rx_html.exec(line)){
232 close_p();
233 while(i<lines.length && !rx_end_html.exec(line)){
234 line = lines[i];
235 i++;
236 html += line + "\n";
237 }
238 continue;
239 }
240
241 // Blank line ends current p, if we're in one
242 if(rx_blank.test(line)){
243 close_p();
244 continue;
245 }
246
247 // Else, we've got paragraph content
248 open_p();
249 html += line + "\n";
250 }
251
252 function open_p(){
253 if(!para_open){
254 html += "<p>";
255 para_open = true;
256 }
257 }
258 function close_p(){
259 if(para_open){
260 html += "</p>";
261 para_open = false;
262
263 }
264 }
265
266 close_p();
267 html_view.innerHTML = html;
268
269 }
270
271 var myform = document.getElementById('my_form');
272 var mybody = document.getElementById('my_body');
273 document.getElementById('tool_save').addEventListener('click', function(){
274 mybody.value = html_view.innerHTML;
275 myform.submit();
276 });
277 document.getElementById('tool_cancel').addEventListener('click', function(){
278 if(confirm("Are you sure?")){
279 location.assign('index.php?page=<?=$page_name?>');
280 }
281 });
282
283 function insertText(text){
284 console.log("inserting: ",text);
285 var start = code_area.selectionStart;
286 var end = code_area.selectionEnd;
287 code_area.setRangeText(text, start, end, 'end');
288 c2h();
289 }
290
291 // The link creator iframe and helper functions
292 var link_creator = document.getElementById('link_creator');
293 var tool_link = document.getElementById('tool_link');
294 tool_link.addEventListener('click', function(){
295 if(link_creator.style.display === "none"){
296 tool_link.textContent = "Cancel Link";
297 link_creator.style.display = "initial";
298 link_creator.innerHTML =
299 '<iframe class="link-creator" src="link_creator.php" title="Link Creator"></iframe>';
300 }
301 else{
302 close_link_creator();
303 }
304 });
305
306 function close_link_creator(){
307 tool_link.textContent = "Insert Link";
308 link_creator.style.display = "none";
309 }
310
311 function insert_link(url, title){
312 insertText(url + '[' + title + ']\n');
313 }
314
315 // The Help button toggles the syntax help box
316 var syntax_help = document.getElementById('syntax_help');
317 var tool_help = document.getElementById('tool_help');
318 tool_help.addEventListener('click', function(){
319 if(syntax_help.style.display === "none"){
320 tool_help.textContent = "Close Help";
321 syntax_help.style.display = "initial";
322 }
323 else{
324 tool_help.textContent = "Help";
325 syntax_help.style.display = "none";
326 }
327 });
328
329 // Start! Do one-time conversion of HTML to wiki markup
330 h2c();
331 </script>
332
333 </body>
334 </html>