Link, bold, italic, strikeout, bullet, numbered list buttons.
[cocanwiki.git] / html / _js / editor.js
1 /* Javascript for OCAMLWIKI.
2  * Copyright (C) 2004 Merjis Ltd.
3  * $Id: editor.js,v 1.2 2004/10/26 17:17:08 rich Exp $
4  */
5
6 var delay = 1000;               // Delay in milliseconds before updating.
7
8 function update_preview (content_id, preview_id)
9 {
10   // Updating is quite expensive, so only update after a period of apparent
11   // inactivity.
12   var preview = document.getElementById (preview_id);
13   if (preview.timer) clearTimeout (preview.timer);
14   preview.timer =
15     setTimeout ("update_preview_now ('" + content_id + "', '" +
16                 preview_id + "')", delay);
17 }
18
19 function update_preview_now (content_id, preview_id)
20 {
21   // Remove the timer.
22   var preview = document.getElementById (preview_id);
23   if (preview.timer) preview.timer = null;
24
25   // Get the Wiki-markup content from the content textarea.
26   var content = document.getElementById (content_id).value;
27
28   // Send the Wiki-markup to the server to be turned into XHTML.
29   var http = document.all ?
30     new ActiveXObject ('Microsoft.XMLHTTP') : new XMLHttpRequest ();
31   if (http)
32     {
33       http.open ('POST', '/_bin/preview.cmo', false);
34       http.setRequestHeader ('Content-Type',
35                              'application/x-www-form-urlencoded');
36       http.send ('content=' + encodeURIComponent (content));
37
38       var xhtml = http.responseText;
39
40       // Next line fails with my copy of IE if the text contains a
41       // link (ie. <a href...>).  It is unclear why.  The error is:
42       // "Unknown runtime error"
43       preview.innerHTML = xhtml;
44     }
45 }
46
47 // Initialise the edit_buttons for a section.
48 // We do this in Javascript so that non-Javascript users won't see
49 // any buttons (they wouldn't be functional for them anyway).
50 function init_edit_buttons (div_id, content_id, preview_id)
51 {
52   // HTML for the edit buttons.
53   var args = "'" + content_id + "', '" + preview_id + "'";
54   var edit_buttons_html =
55     "<a href=\"#\" onmousedown=\"link(" + args + "); return false;\" title=\"Select some text and click this to make a link\"><u>Link</u></a>" +
56     "<span class=\"spacer\"></span>" +
57     "<a href=\"#\" onmousedown=\"bold(" + args + "); return false;\" title=\"Select some text and click this to make it bold\"><strong>Bold</strong></a>" +
58     "<a href=\"#\" onmousedown=\"italic(" + args + "); return false;\" title=\"Select some text and click this to make it italic\"><em>Italic</em></a>" +
59     "<a href=\"#\" onmousedown=\"strikeout(" + args + "); return false;\" title=\"Select some text and click this to strike through it\"><s>Strike</s></a>" +
60     "<span class=\"spacer\"></span>" +
61     "<a href=\"#\" onmousedown=\"bullet(" + args + "); return false;\" title=\"Select lines of text and click this to make it a bullet list\"><big>&#x2219;&#8212;</big></a>" +
62     "<a href=\"#\" onmousedown=\"numbered(" + args + "); return false;\" title=\"Select lines of text and click this to make it a numbered list\">1&#8212;</a>" +
63     "<br/>"
64     ;
65   var div = document.getElementById (div_id);
66   div.innerHTML = edit_buttons_html;
67 }
68
69 function replace_selection (content_id, fn)
70 {
71   var textarea = document.getElementById (content_id);
72
73   if (textarea.setSelectionRange) { // Mozilla
74     var start = textarea.selectionStart;
75     var end = textarea.selectionEnd;
76     if (start != end) {
77       var text = textarea.value.substring (start, end);
78       var replacement = fn (text);
79       textarea.value = textarea.value.substring (0, start) +
80         replacement + textarea.value.substring (end);
81     }
82   } else if (document.selection) { // IE
83     var range = document.selection.createRange ();
84     if (range.parentElement () == textarea && range.text != "") {
85       var text = range.text;
86       var len = text.length;
87
88       // IE6 bug workaround: If the end of the selection is the end of
89       // a line, then we must remember to append a \n character after
90       // doing the replacement.  Note the incredible lengths we have to
91       // go to here because IE is a piece of shit.
92       var dup = range.duplicate ();
93       dup.moveEnd ("character", 2);
94       append =
95         dup.text.substring (dup.text.length-3, dup.text.length-1) == "\r\n";
96
97       // Replace \r\n with just \n.
98       text = text.replace ("\r\n", "\n");
99
100       /*
101       var wtf;
102       for (i = 0; i < len; ++i) {
103         wtf += "," + text.charCodeAt (i);
104         if ((i % 32) == 0) wtf += "\n";
105       }
106       alert (wtf);
107       */
108
109       // IE's selections often include a trailing space or carriage
110       // return.  Ignore this whitespace when calling the replacement
111       // function.
112       var replacement;
113       if ((ar = text.match (/(\s+)$/))) {
114         var ws = ar[1];
115         text = text.substring (0, len - ws.length);
116         replacement = fn (text);
117         replacement = replacement + ws;
118       } else
119         replacement = fn (range.text);
120
121       // See IE bug workaround above.
122       if (append) replacement += "\n";
123
124       range.text = replacement;
125     }
126   }
127 }
128
129 function link (content_id, preview_id)
130 {
131   var fn = function (text) {
132     if (ar = text.match (/^\[\[(.*)\]\]$/))
133       return ar[1];
134     else
135       return "[[" + text + "]]";
136   };
137   replace_selection (content_id, fn);
138   update_preview_now (content_id, preview_id);
139 }
140
141 function bold (content_id, preview_id)
142 {
143   var fn = function (text) {
144     if (ar = text.match (/^<b>(.*)<\/b>$/))
145       return ar[1];
146     else
147       return "<b>" + text + "</b>";
148   };
149   replace_selection (content_id, fn);
150   update_preview_now (content_id, preview_id);
151 }
152
153 function italic (content_id, preview_id)
154 {
155   var fn = function (text) {
156     if (ar = text.match (/^<i>(.*)<\/i>$/))
157       return ar[1];
158     else
159       return "<i>" + text + "</i>";
160   };
161   replace_selection (content_id, fn);
162   update_preview_now (content_id, preview_id);
163 }
164
165 function strikeout (content_id, preview_id)
166 {
167   var fn = function (text) {
168     if (ar = text.match (/^<s>(.*)<\/s>$/))
169       return ar[1];
170     else
171       return "<s>" + text + "</s>";
172   };
173   replace_selection (content_id, fn);
174   update_preview_now (content_id, preview_id);
175 }
176
177 function bullet (content_id, preview_id)
178 {
179   var fn = function (text) {
180     if (text.match (/^\*/))
181       return text.replace (/^\* /gm, "");
182     else
183       return "* " + text.replace (/\n/g, "\n* ");
184   };
185   replace_selection (content_id, fn);
186   update_preview_now (content_id, preview_id);
187 }
188
189 function numbered (content_id, preview_id)
190 {
191   var fn = function (text) {
192     if (text.match (/^#/))
193       return text.replace (/^# /gm, "");
194     else
195       return "# " + text.replace (/\n/g, "\n# ");
196   };
197   replace_selection (content_id, fn);
198   update_preview_now (content_id, preview_id);
199 }