##// END OF EJS Templates
Wiki toolbar improvements (mainly for Firefox)....
Jean-Philippe Lang -
r1049:4e1e5985a1a6
parent child
Show More
1 NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: file renamed from public/images/jstoolbar/bt_heading.png to public/images/jstoolbar/bt_img.png, binary diff hidden
@@ -1,468 +1,521
1 1 /* ***** BEGIN LICENSE BLOCK *****
2 2 * This file is part of DotClear.
3 3 * Copyright (c) 2005 Nicolas Martin & Olivier Meunier and contributors. All
4 4 * rights reserved.
5 5 *
6 6 * DotClear is free software; you can redistribute it and/or modify
7 7 * it under the terms of the GNU General Public License as published by
8 8 * the Free Software Foundation; either version 2 of the License, or
9 9 * (at your option) any later version.
10 10 *
11 11 * DotClear is distributed in the hope that it will be useful,
12 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 * GNU General Public License for more details.
15 15 *
16 16 * You should have received a copy of the GNU General Public License
17 17 * along with DotClear; if not, write to the Free Software
18 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 19 *
20 20 * ***** END LICENSE BLOCK *****
21 21 */
22 22
23 23 /* Modified by JP LANG for textile formatting */
24 24
25 25 function jsToolBar(textarea) {
26 26 if (!document.createElement) { return; }
27 27
28 28 if (!textarea) { return; }
29 29
30 30 if ((typeof(document["selection"]) == "undefined")
31 31 && (typeof(textarea["setSelectionRange"]) == "undefined")) {
32 32 return;
33 33 }
34 34
35 35 this.textarea = textarea;
36 36
37 37 this.editor = document.createElement('div');
38 38 this.editor.className = 'jstEditor';
39 39
40 40 this.textarea.parentNode.insertBefore(this.editor,this.textarea);
41 41 this.editor.appendChild(this.textarea);
42 42
43 43 this.toolbar = document.createElement("div");
44 44 this.toolbar.className = 'jstElements';
45 45 this.editor.parentNode.insertBefore(this.toolbar,this.editor);
46 46
47 47 // Dragable resizing (only for gecko)
48 48 if (this.editor.addEventListener)
49 49 {
50 50 this.handle = document.createElement('div');
51 51 this.handle.className = 'jstHandle';
52 52 var dragStart = this.resizeDragStart;
53 53 var This = this;
54 54 this.handle.addEventListener('mousedown',function(event) { dragStart.call(This,event); },false);
55 55 // fix memory leak in Firefox (bug #241518)
56 56 window.addEventListener('unload',function() {
57 57 var del = This.handle.parentNode.removeChild(This.handle);
58 58 delete(This.handle);
59 59 },false);
60 60
61 61 this.editor.parentNode.insertBefore(this.handle,this.editor.nextSibling);
62 62 }
63 63
64 64 this.context = null;
65 65 this.toolNodes = {}; // lorsque la toolbar est dessinée , cet objet est garni
66 66 // de raccourcis vers les éléments DOM correspondants aux outils.
67 67 }
68 68
69 69 function jsButton(title, fn, scope, className) {
70 70 this.title = title || null;
71 71 this.fn = fn || function(){};
72 72 this.scope = scope || null;
73 73 this.className = className || null;
74 74 }
75 75 jsButton.prototype.draw = function() {
76 76 if (!this.scope) return null;
77 77
78 78 var button = document.createElement('button');
79 79 button.setAttribute('type','button');
80 80 if (this.className) button.className = this.className;
81 81 button.title = this.title;
82 82 var span = document.createElement('span');
83 83 span.appendChild(document.createTextNode(this.title));
84 84 button.appendChild(span);
85 85
86 86 if (this.icon != undefined) {
87 87 button.style.backgroundImage = 'url('+this.icon+')';
88 88 }
89 89 if (typeof(this.fn) == 'function') {
90 90 var This = this;
91 91 button.onclick = function() { try { This.fn.apply(This.scope, arguments) } catch (e) {} return false; };
92 92 }
93 93 return button;
94 94 }
95 95
96 96 function jsSpace(id) {
97 97 this.id = id || null;
98 98 this.width = null;
99 99 }
100 100 jsSpace.prototype.draw = function() {
101 101 var span = document.createElement('span');
102 102 if (this.id) span.id = this.id;
103 103 span.appendChild(document.createTextNode(String.fromCharCode(160)));
104 104 span.className = 'jstSpacer';
105 105 if (this.width) span.style.marginRight = this.width+'px';
106 106
107 107 return span;
108 108 }
109 109
110 110 function jsCombo(title, options, scope, fn, className) {
111 111 this.title = title || null;
112 112 this.options = options || null;
113 113 this.scope = scope || null;
114 114 this.fn = fn || function(){};
115 115 this.className = className || null;
116 116 }
117 117 jsCombo.prototype.draw = function() {
118 118 if (!this.scope || !this.options) return null;
119 119
120 120 var select = document.createElement('select');
121 121 if (this.className) select.className = className;
122 122 select.title = this.title;
123 123
124 124 for (var o in this.options) {
125 125 //var opt = this.options[o];
126 126 var option = document.createElement('option');
127 127 option.value = o;
128 128 option.appendChild(document.createTextNode(this.options[o]));
129 129 select.appendChild(option);
130 130 }
131 131
132 132 var This = this;
133 133 select.onchange = function() {
134 134 try {
135 135 This.fn.call(This.scope, this.value);
136 136 } catch (e) { alert(e); }
137 137
138 138 return false;
139 139 }
140 140
141 141 return select;
142 142 }
143 143
144 144
145 145 jsToolBar.prototype = {
146 146 base_url: '',
147 147 mode: 'wiki',
148 148 elements: {},
149 149
150 150 getMode: function() {
151 151 return this.mode;
152 152 },
153 153
154 154 setMode: function(mode) {
155 155 this.mode = mode || 'wiki';
156 156 },
157 157
158 158 switchMode: function(mode) {
159 159 mode = mode || 'wiki';
160 160 this.draw(mode);
161 161 },
162 162
163 163 button: function(toolName) {
164 164 var tool = this.elements[toolName];
165 165 if (typeof tool.fn[this.mode] != 'function') return null;
166 166 var b = new jsButton(tool.title, tool.fn[this.mode], this, 'jstb_'+toolName);
167 167 if (tool.icon != undefined) b.icon = tool.icon;
168 168 return b;
169 169 },
170 170 space: function(toolName) {
171 171 var tool = new jsSpace(toolName)
172 172 if (this.elements[toolName].width !== undefined)
173 173 tool.width = this.elements[toolName].width;
174 174 return tool;
175 175 },
176 176 combo: function(toolName) {
177 177 var tool = this.elements[toolName];
178 178 var length = tool[this.mode].list.length;
179 179
180 180 if (typeof tool[this.mode].fn != 'function' || length == 0) {
181 181 return null;
182 182 } else {
183 183 var options = {};
184 184 for (var i=0; i < length; i++) {
185 185 var opt = tool[this.mode].list[i];
186 186 options[opt] = tool.options[opt];
187 187 }
188 188 return new jsCombo(tool.title, options, this, tool[this.mode].fn);
189 189 }
190 190 },
191 191 draw: function(mode) {
192 192 this.setMode(mode);
193 193
194 194 // Empty toolbar
195 195 while (this.toolbar.hasChildNodes()) {
196 196 this.toolbar.removeChild(this.toolbar.firstChild)
197 197 }
198 198 this.toolNodes = {}; // vide les raccourcis DOM/**/
199 199
200 200 // Draw toolbar elements
201 201 var b, tool, newTool;
202 202
203 203 for (var i in this.elements) {
204 204 b = this.elements[i];
205 205
206 206 var disabled =
207 207 b.type == undefined || b.type == ''
208 208 || (b.disabled != undefined && b.disabled)
209 209 || (b.context != undefined && b.context != null && b.context != this.context);
210 210
211 211 if (!disabled && typeof this[b.type] == 'function') {
212 212 tool = this[b.type](i);
213 213 if (tool) newTool = tool.draw();
214 214 if (newTool) {
215 215 this.toolNodes[i] = newTool; //mémorise l'accès DOM pour usage éventuel ultérieur
216 216 this.toolbar.appendChild(newTool);
217 217 }
218 218 }
219 219 }
220 220 },
221 221
222 222 singleTag: function(stag,etag) {
223 223 stag = stag || null;
224 224 etag = etag || stag;
225 225
226 226 if (!stag || !etag) { return; }
227 227
228 228 this.encloseSelection(stag,etag);
229 229 },
230 230
231 encloseLineSelection: function(prefix, suffix, fn) {
232 this.textarea.focus();
233
234 prefix = prefix || '';
235 suffix = suffix || '';
236
237 var start, end, sel, scrollPos, subst, res;
238
239 if (typeof(document["selection"]) != "undefined") {
240 sel = document.selection.createRange().text;
241 } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") {
242 start = this.textarea.selectionStart;
243 end = this.textarea.selectionEnd;
244 scrollPos = this.textarea.scrollTop;
245 // go to the start of the line
246 start = this.textarea.value.substring(0, start).replace(/[^\r\n]*$/g,'').length;
247 // go to the end of the line
248 end = this.textarea.value.length - this.textarea.value.substring(end, this.textarea.value.length).replace(/^[^\r\n]*/, '').length;
249 sel = this.textarea.value.substring(start, end);
250 }
251
252 if (sel.match(/ $/)) { // exclude ending space char, if any
253 sel = sel.substring(0, sel.length - 1);
254 suffix = suffix + " ";
255 }
256
257 if (typeof(fn) == 'function') {
258 res = (sel) ? fn.call(this,sel) : fn('');
259 } else {
260 res = (sel) ? sel : '';
261 }
262
263 subst = prefix + res + suffix;
264
265 if (typeof(document["selection"]) != "undefined") {
266 document.selection.createRange().text = subst;
267 var range = this.textarea.createTextRange();
268 range.collapse(false);
269 range.move('character', -suffix.length);
270 range.select();
271 } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") {
272 this.textarea.value = this.textarea.value.substring(0, start) + subst +
273 this.textarea.value.substring(end);
274 if (sel) {
275 this.textarea.setSelectionRange(start + subst.length, start + subst.length);
276 } else {
277 this.textarea.setSelectionRange(start + prefix.length, start + prefix.length);
278 }
279 this.textarea.scrollTop = scrollPos;
280 }
281 },
282
231 283 encloseSelection: function(prefix, suffix, fn) {
232 284 this.textarea.focus();
233 285
234 286 prefix = prefix || '';
235 287 suffix = suffix || '';
236 288
237 289 var start, end, sel, scrollPos, subst, res;
238 290
239 291 if (typeof(document["selection"]) != "undefined") {
240 292 sel = document.selection.createRange().text;
241 293 } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") {
242 294 start = this.textarea.selectionStart;
243 295 end = this.textarea.selectionEnd;
244 296 scrollPos = this.textarea.scrollTop;
245 297 sel = this.textarea.value.substring(start, end);
246 298 }
247 299
248 300 if (sel.match(/ $/)) { // exclude ending space char, if any
249 301 sel = sel.substring(0, sel.length - 1);
250 302 suffix = suffix + " ";
251 303 }
252 304
253 305 if (typeof(fn) == 'function') {
254 306 res = (sel) ? fn.call(this,sel) : fn('');
255 307 } else {
256 308 res = (sel) ? sel : '';
257 309 }
258 310
259 311 subst = prefix + res + suffix;
260 312
261 313 if (typeof(document["selection"]) != "undefined") {
262 314 document.selection.createRange().text = subst;
263 315 var range = this.textarea.createTextRange();
264 316 range.collapse(false);
265 317 range.move('character', -suffix.length);
266 318 range.select();
267 319 // this.textarea.caretPos -= suffix.length;
268 320 } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") {
269 321 this.textarea.value = this.textarea.value.substring(0, start) + subst +
270 322 this.textarea.value.substring(end);
271 323 if (sel) {
272 324 this.textarea.setSelectionRange(start + subst.length, start + subst.length);
273 325 } else {
274 326 this.textarea.setSelectionRange(start + prefix.length, start + prefix.length);
275 327 }
276 328 this.textarea.scrollTop = scrollPos;
277 329 }
278 330 },
279 331
280 332 stripBaseURL: function(url) {
281 333 if (this.base_url != '') {
282 334 var pos = url.indexOf(this.base_url);
283 335 if (pos == 0) {
284 336 url = url.substr(this.base_url.length);
285 337 }
286 338 }
287 339
288 340 return url;
289 341 }
290 342 };
291 343
292 344 /** Resizer
293 345 -------------------------------------------------------- */
294 346 jsToolBar.prototype.resizeSetStartH = function() {
295 347 this.dragStartH = this.textarea.offsetHeight + 0;
296 348 };
297 349 jsToolBar.prototype.resizeDragStart = function(event) {
298 350 var This = this;
299 351 this.dragStartY = event.clientY;
300 352 this.resizeSetStartH();
301 353 document.addEventListener('mousemove', this.dragMoveHdlr=function(event){This.resizeDragMove(event);}, false);
302 354 document.addEventListener('mouseup', this.dragStopHdlr=function(event){This.resizeDragStop(event);}, false);
303 355 };
304 356
305 357 jsToolBar.prototype.resizeDragMove = function(event) {
306 358 this.textarea.style.height = (this.dragStartH+event.clientY-this.dragStartY)+'px';
307 359 };
308 360
309 361 jsToolBar.prototype.resizeDragStop = function(event) {
310 362 document.removeEventListener('mousemove', this.dragMoveHdlr, false);
311 363 document.removeEventListener('mouseup', this.dragStopHdlr, false);
312 364 };
313 365
314 366 // Elements definition ------------------------------------
315 367
316 368 // strong
317 369 jsToolBar.prototype.elements.strong = {
318 370 type: 'button',
319 371 title: 'Strong emphasis',
320 372 fn: {
321 373 wiki: function() { this.singleTag('*') }
322 374 }
323 375 }
324 376
325 377 // em
326 378 jsToolBar.prototype.elements.em = {
327 379 type: 'button',
328 380 title: 'Emphasis',
329 381 fn: {
330 382 wiki: function() { this.singleTag("_") }
331 383 }
332 384 }
333 385
334 386 // ins
335 387 jsToolBar.prototype.elements.ins = {
336 388 type: 'button',
337 389 title: 'Inserted',
338 390 fn: {
339 391 wiki: function() { this.singleTag('+') }
340 392 }
341 393 }
342 394
343 395 // del
344 396 jsToolBar.prototype.elements.del = {
345 397 type: 'button',
346 398 title: 'Deleted',
347 399 fn: {
348 400 wiki: function() { this.singleTag('-') }
349 401 }
350 402 }
351 403
352 404 // quote
353 405 jsToolBar.prototype.elements.quote = {
354 406 type: 'button',
355 407 title: 'Inline quote',
356 408 fn: {
357 409 wiki: function() { this.singleTag('??') }
358 410 }
359 411 }
360 412
361 413 // code
362 414 jsToolBar.prototype.elements.code = {
363 415 type: 'button',
364 416 title: 'Code',
365 417 fn: {
366 418 wiki: function() { this.singleTag('@') }
367 419 }
368 420 }
369 421
370 422 // spacer
371 423 jsToolBar.prototype.elements.space1 = {type: 'space'}
372 424
373 // heading
374 jsToolBar.prototype.elements.heading = {
425 // headings
426 jsToolBar.prototype.elements.h1 = {
375 427 type: 'button',
376 title: 'Heading',
428 title: 'Heading 1',
377 429 fn: {
378 wiki: function() {
379 this.encloseSelection('','',function(str) {
380 str = str.replace(/\r/g,'');
381 return 'h2. '+str.replace(/\n/g,"\n* ");
382 });
430 wiki: function() {
431 this.encloseLineSelection('h1. ', '',function(str) {
432 str = str.replace(/^h\d+\.\s+/, '')
433 return str;
434 });
435 }
436 }
437 }
438 jsToolBar.prototype.elements.h2 = {
439 type: 'button',
440 title: 'Heading 2',
441 fn: {
442 wiki: function() {
443 this.encloseLineSelection('h2. ', '',function(str) {
444 str = str.replace(/^h\d+\.\s+/, '')
445 return str;
446 });
447 }
448 }
449 }
450 jsToolBar.prototype.elements.h3 = {
451 type: 'button',
452 title: 'Heading 3',
453 fn: {
454 wiki: function() {
455 this.encloseLineSelection('h3. ', '',function(str) {
456 str = str.replace(/^h\d+\.\s+/, '')
457 return str;
458 });
383 459 }
384 460 }
385 461 }
386
387 // br
388 //jsToolBar.prototype.elements.br = {
389 // type: 'button',
390 // title: 'Line break',
391 // fn: {
392 // wiki: function() { this.encloseSelection("%%%\n",'') }
393 // }
394 //}
395 462
396 463 // spacer
397 464 jsToolBar.prototype.elements.space2 = {type: 'space'}
398 465
399 466 // ul
400 467 jsToolBar.prototype.elements.ul = {
401 468 type: 'button',
402 469 title: 'Unordered list',
403 470 fn: {
404 471 wiki: function() {
405 this.encloseSelection('','',function(str) {
472 this.encloseLineSelection('','',function(str) {
406 473 str = str.replace(/\r/g,'');
407 return '* '+str.replace(/\n/g,"\n* ");
474 return str.replace(/(\n|^)[#-]?\s*/g,"$1* ");
408 475 });
409 476 }
410 477 }
411 478 }
412 479
413 480 // ol
414 481 jsToolBar.prototype.elements.ol = {
415 482 type: 'button',
416 483 title: 'Ordered list',
417 484 fn: {
418 485 wiki: function() {
419 this.encloseSelection('','',function(str) {
486 this.encloseLineSelection('','',function(str) {
420 487 str = str.replace(/\r/g,'');
421 return '# '+str.replace(/\n/g,"\n# ");
488 return str.replace(/(\n|^)[*-]?\s*/g,"$1# ");
422 489 });
423 490 }
424 491 }
425 492 }
426 493
494 // pre
495 jsToolBar.prototype.elements.pre = {
496 type: 'button',
497 title: 'Preformatted text',
498 fn: {
499 wiki: function() { this.encloseLineSelection('<pre>\n', '\n</pre>') }
500 }
501 }
502
427 503 // spacer
428 504 jsToolBar.prototype.elements.space3 = {type: 'space'}
429 505
430 // link
431 /*
506 // wiki page
432 507 jsToolBar.prototype.elements.link = {
433 508 type: 'button',
434 title: 'Link',
435 fn: {},
436 href_prompt: 'Please give page URL:',
437 hreflang_prompt: 'Language of this page:',
438 default_hreflang: '',
439 prompt: function(href,hreflang) {
440 href = href || '';
441 hreflang = hreflang || this.elements.link.default_hreflang;
442
443 href = window.prompt(this.elements.link.href_prompt,href);
444 if (!href) { return false; }
445
446 hreflang = ""
447
448 return { href: this.stripBaseURL(href), hreflang: hreflang };
509 title: 'Wiki Page Link',
510 fn: {
511 wiki: function() { this.encloseSelection("[[", "]]") }
449 512 }
450 513 }
451
452 jsToolBar.prototype.elements.link.fn.wiki = function() {
453 var link = this.elements.link.prompt.call(this);
454 if (link) {
455 var stag = '"';
456 var etag = '":'+link.href;
457 this.encloseSelection(stag,etag);
458 }
459 };
460 */
461 // link or wiki page
462 jsToolBar.prototype.elements.link = {
514 // image
515 jsToolBar.prototype.elements.img = {
463 516 type: 'button',
464 title: 'Link',
517 title: 'Inline image',
465 518 fn: {
466 wiki: function() { this.encloseSelection("[[", "]]") }
519 wiki: function() { this.encloseSelection("!", "!") }
467 520 }
468 521 }
@@ -1,81 +1,93
1 1 .jstEditor {
2 2 padding-left: 0px;
3 3 }
4 4 .jstEditor textarea, .jstEditor iframe {
5 5 margin: 0;
6 6 }
7 7
8 8 .jstHandle {
9 9 height: 10px;
10 10 font-size: 0.1em;
11 11 cursor: s-resize;
12 12 /*background: transparent url(img/resizer.png) no-repeat 45% 50%;*/
13 13 }
14 14
15 15 .jstElements {
16 16 padding: 3px 3px;
17 17 }
18 18
19 19 .jstElements button {
20 20 margin-right : 6px;
21 21 width : 24px;
22 22 height: 24px;
23 23 padding: 4px;
24 24 border-style: solid;
25 25 border-width: 1px;
26 26 border-color: #ddd;
27 27 background-color : #f7f7f7;
28 28 background-position : 50% 50%;
29 29 background-repeat: no-repeat;
30 30 }
31 31 .jstElements button:hover {
32 32 border-color : #000;
33 33 }
34 34 .jstElements button span {
35 35 display : none;
36 36 }
37 37 .jstElements span {
38 38 display : inline;
39 39 }
40 40
41 41 .jstSpacer {
42 42 width : 0px;
43 43 font-size: 1px;
44 44 margin-right: 4px;
45 45 }
46 46
47 47 /* Buttons
48 48 -------------------------------------------------------- */
49 49 .jstb_strong {
50 50 background-image: url(../images/jstoolbar/bt_strong.png);
51 51 }
52 52 .jstb_em {
53 53 background-image: url(../images/jstoolbar/bt_em.png);
54 54 }
55 55 .jstb_ins {
56 56 background-image: url(../images/jstoolbar/bt_ins.png);
57 57 }
58 58 .jstb_del {
59 59 background-image: url(../images/jstoolbar/bt_del.png);
60 60 }
61 61 .jstb_quote {
62 62 background-image: url(../images/jstoolbar/bt_quote.png);
63 63 }
64 64 .jstb_code {
65 65 background-image: url(../images/jstoolbar/bt_code.png);
66 66 }
67 67 .jstb_br {
68 68 background-image: url(../images/jstoolbar/bt_br.png);
69 69 }
70 .jstb_heading {
71 background-image: url(../images/jstoolbar/bt_heading.png);
70 .jstb_h1 {
71 background-image: url(../images/jstoolbar/bt_h1.png);
72 }
73 .jstb_h2 {
74 background-image: url(../images/jstoolbar/bt_h2.png);
75 }
76 .jstb_h3 {
77 background-image: url(../images/jstoolbar/bt_h3.png);
72 78 }
73 79 .jstb_ul {
74 80 background-image: url(../images/jstoolbar/bt_ul.png);
75 81 }
76 82 .jstb_ol {
77 83 background-image: url(../images/jstoolbar/bt_ol.png);
78 84 }
85 .jstb_pre {
86 background-image: url(../images/jstoolbar/bt_pre.png);
87 }
79 88 .jstb_link {
80 89 background-image: url(../images/jstoolbar/bt_link.png);
81 90 }
91 .jstb_img {
92 background-image: url(../images/jstoolbar/bt_img.png);
93 }
General Comments 0
You need to be logged in to leave comments. Login now