annotate public/javascripts/jstoolbar/jstoolbar.js @ 8:0c83d98252d9 yuya

* Add custom repo prefix and proper auth realm, remove auth cache (seems like an unwise feature), pass DB handle around, various other bits of tidying
author Chris Cannam
date Thu, 12 Aug 2010 15:31:37 +0100
parents 513646585e45
children 433d4f72a19b
rev   line source
Chris@0 1 /* ***** BEGIN LICENSE BLOCK *****
Chris@0 2 * This file is part of DotClear.
Chris@0 3 * Copyright (c) 2005 Nicolas Martin & Olivier Meunier and contributors. All
Chris@0 4 * rights reserved.
Chris@0 5 *
Chris@0 6 * DotClear is free software; you can redistribute it and/or modify
Chris@0 7 * it under the terms of the GNU General Public License as published by
Chris@0 8 * the Free Software Foundation; either version 2 of the License, or
Chris@0 9 * (at your option) any later version.
Chris@0 10 *
Chris@0 11 * DotClear is distributed in the hope that it will be useful,
Chris@0 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@0 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@0 14 * GNU General Public License for more details.
Chris@0 15 *
Chris@0 16 * You should have received a copy of the GNU General Public License
Chris@0 17 * along with DotClear; if not, write to the Free Software
Chris@0 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Chris@0 19 *
Chris@0 20 * ***** END LICENSE BLOCK *****
Chris@0 21 */
Chris@0 22
Chris@0 23 /* Modified by JP LANG for textile formatting */
Chris@0 24
Chris@0 25 function jsToolBar(textarea) {
Chris@0 26 if (!document.createElement) { return; }
Chris@0 27
Chris@0 28 if (!textarea) { return; }
Chris@0 29
Chris@0 30 if ((typeof(document["selection"]) == "undefined")
Chris@0 31 && (typeof(textarea["setSelectionRange"]) == "undefined")) {
Chris@0 32 return;
Chris@0 33 }
Chris@0 34
Chris@0 35 this.textarea = textarea;
Chris@0 36
Chris@0 37 this.editor = document.createElement('div');
Chris@0 38 this.editor.className = 'jstEditor';
Chris@0 39
Chris@0 40 this.textarea.parentNode.insertBefore(this.editor,this.textarea);
Chris@0 41 this.editor.appendChild(this.textarea);
Chris@0 42
Chris@0 43 this.toolbar = document.createElement("div");
Chris@0 44 this.toolbar.className = 'jstElements';
Chris@0 45 this.editor.parentNode.insertBefore(this.toolbar,this.editor);
Chris@0 46
Chris@0 47 // Dragable resizing (only for gecko)
Chris@0 48 if (this.editor.addEventListener)
Chris@0 49 {
Chris@0 50 this.handle = document.createElement('div');
Chris@0 51 this.handle.className = 'jstHandle';
Chris@0 52 var dragStart = this.resizeDragStart;
Chris@0 53 var This = this;
Chris@0 54 this.handle.addEventListener('mousedown',function(event) { dragStart.call(This,event); },false);
Chris@0 55 // fix memory leak in Firefox (bug #241518)
Chris@0 56 window.addEventListener('unload',function() {
Chris@0 57 var del = This.handle.parentNode.removeChild(This.handle);
Chris@0 58 delete(This.handle);
Chris@0 59 },false);
Chris@0 60
Chris@0 61 this.editor.parentNode.insertBefore(this.handle,this.editor.nextSibling);
Chris@0 62 }
Chris@0 63
Chris@0 64 this.context = null;
Chris@0 65 this.toolNodes = {}; // lorsque la toolbar est dessinée , cet objet est garni
Chris@0 66 // de raccourcis vers les éléments DOM correspondants aux outils.
Chris@0 67 }
Chris@0 68
Chris@0 69 function jsButton(title, fn, scope, className) {
Chris@0 70 if(typeof jsToolBar.strings == 'undefined') {
Chris@0 71 this.title = title || null;
Chris@0 72 } else {
Chris@0 73 this.title = jsToolBar.strings[title] || title || null;
Chris@0 74 }
Chris@0 75 this.fn = fn || function(){};
Chris@0 76 this.scope = scope || null;
Chris@0 77 this.className = className || null;
Chris@0 78 }
Chris@0 79 jsButton.prototype.draw = function() {
Chris@0 80 if (!this.scope) return null;
Chris@0 81
Chris@0 82 var button = document.createElement('button');
Chris@0 83 button.setAttribute('type','button');
Chris@0 84 button.tabIndex = 200;
Chris@0 85 if (this.className) button.className = this.className;
Chris@0 86 button.title = this.title;
Chris@0 87 var span = document.createElement('span');
Chris@0 88 span.appendChild(document.createTextNode(this.title));
Chris@0 89 button.appendChild(span);
Chris@0 90
Chris@0 91 if (this.icon != undefined) {
Chris@0 92 button.style.backgroundImage = 'url('+this.icon+')';
Chris@0 93 }
Chris@0 94 if (typeof(this.fn) == 'function') {
Chris@0 95 var This = this;
Chris@0 96 button.onclick = function() { try { This.fn.apply(This.scope, arguments) } catch (e) {} return false; };
Chris@0 97 }
Chris@0 98 return button;
Chris@0 99 }
Chris@0 100
Chris@0 101 function jsSpace(id) {
Chris@0 102 this.id = id || null;
Chris@0 103 this.width = null;
Chris@0 104 }
Chris@0 105 jsSpace.prototype.draw = function() {
Chris@0 106 var span = document.createElement('span');
Chris@0 107 if (this.id) span.id = this.id;
Chris@0 108 span.appendChild(document.createTextNode(String.fromCharCode(160)));
Chris@0 109 span.className = 'jstSpacer';
Chris@0 110 if (this.width) span.style.marginRight = this.width+'px';
Chris@0 111
Chris@0 112 return span;
Chris@0 113 }
Chris@0 114
Chris@0 115 function jsCombo(title, options, scope, fn, className) {
Chris@0 116 this.title = title || null;
Chris@0 117 this.options = options || null;
Chris@0 118 this.scope = scope || null;
Chris@0 119 this.fn = fn || function(){};
Chris@0 120 this.className = className || null;
Chris@0 121 }
Chris@0 122 jsCombo.prototype.draw = function() {
Chris@0 123 if (!this.scope || !this.options) return null;
Chris@0 124
Chris@0 125 var select = document.createElement('select');
Chris@0 126 if (this.className) select.className = className;
Chris@0 127 select.title = this.title;
Chris@0 128
Chris@0 129 for (var o in this.options) {
Chris@0 130 //var opt = this.options[o];
Chris@0 131 var option = document.createElement('option');
Chris@0 132 option.value = o;
Chris@0 133 option.appendChild(document.createTextNode(this.options[o]));
Chris@0 134 select.appendChild(option);
Chris@0 135 }
Chris@0 136
Chris@0 137 var This = this;
Chris@0 138 select.onchange = function() {
Chris@0 139 try {
Chris@0 140 This.fn.call(This.scope, this.value);
Chris@0 141 } catch (e) { alert(e); }
Chris@0 142
Chris@0 143 return false;
Chris@0 144 }
Chris@0 145
Chris@0 146 return select;
Chris@0 147 }
Chris@0 148
Chris@0 149
Chris@0 150 jsToolBar.prototype = {
Chris@0 151 base_url: '',
Chris@0 152 mode: 'wiki',
Chris@0 153 elements: {},
Chris@0 154 help_link: '',
Chris@0 155
Chris@0 156 getMode: function() {
Chris@0 157 return this.mode;
Chris@0 158 },
Chris@0 159
Chris@0 160 setMode: function(mode) {
Chris@0 161 this.mode = mode || 'wiki';
Chris@0 162 },
Chris@0 163
Chris@0 164 switchMode: function(mode) {
Chris@0 165 mode = mode || 'wiki';
Chris@0 166 this.draw(mode);
Chris@0 167 },
Chris@0 168
Chris@0 169 setHelpLink: function(link) {
Chris@0 170 this.help_link = link;
Chris@0 171 },
Chris@0 172
Chris@0 173 button: function(toolName) {
Chris@0 174 var tool = this.elements[toolName];
Chris@0 175 if (typeof tool.fn[this.mode] != 'function') return null;
Chris@0 176 var b = new jsButton(tool.title, tool.fn[this.mode], this, 'jstb_'+toolName);
Chris@0 177 if (tool.icon != undefined) b.icon = tool.icon;
Chris@0 178 return b;
Chris@0 179 },
Chris@0 180 space: function(toolName) {
Chris@0 181 var tool = new jsSpace(toolName)
Chris@0 182 if (this.elements[toolName].width !== undefined)
Chris@0 183 tool.width = this.elements[toolName].width;
Chris@0 184 return tool;
Chris@0 185 },
Chris@0 186 combo: function(toolName) {
Chris@0 187 var tool = this.elements[toolName];
Chris@0 188 var length = tool[this.mode].list.length;
Chris@0 189
Chris@0 190 if (typeof tool[this.mode].fn != 'function' || length == 0) {
Chris@0 191 return null;
Chris@0 192 } else {
Chris@0 193 var options = {};
Chris@0 194 for (var i=0; i < length; i++) {
Chris@0 195 var opt = tool[this.mode].list[i];
Chris@0 196 options[opt] = tool.options[opt];
Chris@0 197 }
Chris@0 198 return new jsCombo(tool.title, options, this, tool[this.mode].fn);
Chris@0 199 }
Chris@0 200 },
Chris@0 201 draw: function(mode) {
Chris@0 202 this.setMode(mode);
Chris@0 203
Chris@0 204 // Empty toolbar
Chris@0 205 while (this.toolbar.hasChildNodes()) {
Chris@0 206 this.toolbar.removeChild(this.toolbar.firstChild)
Chris@0 207 }
Chris@0 208 this.toolNodes = {}; // vide les raccourcis DOM/**/
Chris@0 209
Chris@0 210 var h = document.createElement('div');
Chris@0 211 h.className = 'help'
Chris@0 212 h.innerHTML = this.help_link;
Chris@0 213 '<a href="/help/wiki_syntax.html" onclick="window.open(\'/help/wiki_syntax.html\', \'\', \'resizable=yes, location=no, width=300, height=640, menubar=no, status=no, scrollbars=yes\'); return false;">Aide</a>';
Chris@0 214 this.toolbar.appendChild(h);
Chris@0 215
Chris@0 216 // Draw toolbar elements
Chris@0 217 var b, tool, newTool;
Chris@0 218
Chris@0 219 for (var i in this.elements) {
Chris@0 220 b = this.elements[i];
Chris@0 221
Chris@0 222 var disabled =
Chris@0 223 b.type == undefined || b.type == ''
Chris@0 224 || (b.disabled != undefined && b.disabled)
Chris@0 225 || (b.context != undefined && b.context != null && b.context != this.context);
Chris@0 226
Chris@0 227 if (!disabled && typeof this[b.type] == 'function') {
Chris@0 228 tool = this[b.type](i);
Chris@0 229 if (tool) newTool = tool.draw();
Chris@0 230 if (newTool) {
Chris@0 231 this.toolNodes[i] = newTool; //mémorise l'accès DOM pour usage éventuel ultérieur
Chris@0 232 this.toolbar.appendChild(newTool);
Chris@0 233 }
Chris@0 234 }
Chris@0 235 }
Chris@0 236 },
Chris@0 237
Chris@0 238 singleTag: function(stag,etag) {
Chris@0 239 stag = stag || null;
Chris@0 240 etag = etag || stag;
Chris@0 241
Chris@0 242 if (!stag || !etag) { return; }
Chris@0 243
Chris@0 244 this.encloseSelection(stag,etag);
Chris@0 245 },
Chris@0 246
Chris@0 247 encloseLineSelection: function(prefix, suffix, fn) {
Chris@0 248 this.textarea.focus();
Chris@0 249
Chris@0 250 prefix = prefix || '';
Chris@0 251 suffix = suffix || '';
Chris@0 252
Chris@0 253 var start, end, sel, scrollPos, subst, res;
Chris@0 254
Chris@0 255 if (typeof(document["selection"]) != "undefined") {
Chris@0 256 sel = document.selection.createRange().text;
Chris@0 257 } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") {
Chris@0 258 start = this.textarea.selectionStart;
Chris@0 259 end = this.textarea.selectionEnd;
Chris@0 260 scrollPos = this.textarea.scrollTop;
Chris@0 261 // go to the start of the line
Chris@0 262 start = this.textarea.value.substring(0, start).replace(/[^\r\n]*$/g,'').length;
Chris@0 263 // go to the end of the line
Chris@0 264 end = this.textarea.value.length - this.textarea.value.substring(end, this.textarea.value.length).replace(/^[^\r\n]*/, '').length;
Chris@0 265 sel = this.textarea.value.substring(start, end);
Chris@0 266 }
Chris@0 267
Chris@0 268 if (sel.match(/ $/)) { // exclude ending space char, if any
Chris@0 269 sel = sel.substring(0, sel.length - 1);
Chris@0 270 suffix = suffix + " ";
Chris@0 271 }
Chris@0 272
Chris@0 273 if (typeof(fn) == 'function') {
Chris@0 274 res = (sel) ? fn.call(this,sel) : fn('');
Chris@0 275 } else {
Chris@0 276 res = (sel) ? sel : '';
Chris@0 277 }
Chris@0 278
Chris@0 279 subst = prefix + res + suffix;
Chris@0 280
Chris@0 281 if (typeof(document["selection"]) != "undefined") {
Chris@0 282 document.selection.createRange().text = subst;
Chris@0 283 var range = this.textarea.createTextRange();
Chris@0 284 range.collapse(false);
Chris@0 285 range.move('character', -suffix.length);
Chris@0 286 range.select();
Chris@0 287 } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") {
Chris@0 288 this.textarea.value = this.textarea.value.substring(0, start) + subst +
Chris@0 289 this.textarea.value.substring(end);
Chris@0 290 if (sel) {
Chris@0 291 this.textarea.setSelectionRange(start + subst.length, start + subst.length);
Chris@0 292 } else {
Chris@0 293 this.textarea.setSelectionRange(start + prefix.length, start + prefix.length);
Chris@0 294 }
Chris@0 295 this.textarea.scrollTop = scrollPos;
Chris@0 296 }
Chris@0 297 },
Chris@0 298
Chris@0 299 encloseSelection: function(prefix, suffix, fn) {
Chris@0 300 this.textarea.focus();
Chris@0 301
Chris@0 302 prefix = prefix || '';
Chris@0 303 suffix = suffix || '';
Chris@0 304
Chris@0 305 var start, end, sel, scrollPos, subst, res;
Chris@0 306
Chris@0 307 if (typeof(document["selection"]) != "undefined") {
Chris@0 308 sel = document.selection.createRange().text;
Chris@0 309 } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") {
Chris@0 310 start = this.textarea.selectionStart;
Chris@0 311 end = this.textarea.selectionEnd;
Chris@0 312 scrollPos = this.textarea.scrollTop;
Chris@0 313 sel = this.textarea.value.substring(start, end);
Chris@0 314 }
Chris@0 315
Chris@0 316 if (sel.match(/ $/)) { // exclude ending space char, if any
Chris@0 317 sel = sel.substring(0, sel.length - 1);
Chris@0 318 suffix = suffix + " ";
Chris@0 319 }
Chris@0 320
Chris@0 321 if (typeof(fn) == 'function') {
Chris@0 322 res = (sel) ? fn.call(this,sel) : fn('');
Chris@0 323 } else {
Chris@0 324 res = (sel) ? sel : '';
Chris@0 325 }
Chris@0 326
Chris@0 327 subst = prefix + res + suffix;
Chris@0 328
Chris@0 329 if (typeof(document["selection"]) != "undefined") {
Chris@0 330 document.selection.createRange().text = subst;
Chris@0 331 var range = this.textarea.createTextRange();
Chris@0 332 range.collapse(false);
Chris@0 333 range.move('character', -suffix.length);
Chris@0 334 range.select();
Chris@0 335 // this.textarea.caretPos -= suffix.length;
Chris@0 336 } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") {
Chris@0 337 this.textarea.value = this.textarea.value.substring(0, start) + subst +
Chris@0 338 this.textarea.value.substring(end);
Chris@0 339 if (sel) {
Chris@0 340 this.textarea.setSelectionRange(start + subst.length, start + subst.length);
Chris@0 341 } else {
Chris@0 342 this.textarea.setSelectionRange(start + prefix.length, start + prefix.length);
Chris@0 343 }
Chris@0 344 this.textarea.scrollTop = scrollPos;
Chris@0 345 }
Chris@0 346 },
Chris@0 347
Chris@0 348 stripBaseURL: function(url) {
Chris@0 349 if (this.base_url != '') {
Chris@0 350 var pos = url.indexOf(this.base_url);
Chris@0 351 if (pos == 0) {
Chris@0 352 url = url.substr(this.base_url.length);
Chris@0 353 }
Chris@0 354 }
Chris@0 355
Chris@0 356 return url;
Chris@0 357 }
Chris@0 358 };
Chris@0 359
Chris@0 360 /** Resizer
Chris@0 361 -------------------------------------------------------- */
Chris@0 362 jsToolBar.prototype.resizeSetStartH = function() {
Chris@0 363 this.dragStartH = this.textarea.offsetHeight + 0;
Chris@0 364 };
Chris@0 365 jsToolBar.prototype.resizeDragStart = function(event) {
Chris@0 366 var This = this;
Chris@0 367 this.dragStartY = event.clientY;
Chris@0 368 this.resizeSetStartH();
Chris@0 369 document.addEventListener('mousemove', this.dragMoveHdlr=function(event){This.resizeDragMove(event);}, false);
Chris@0 370 document.addEventListener('mouseup', this.dragStopHdlr=function(event){This.resizeDragStop(event);}, false);
Chris@0 371 };
Chris@0 372
Chris@0 373 jsToolBar.prototype.resizeDragMove = function(event) {
Chris@0 374 this.textarea.style.height = (this.dragStartH+event.clientY-this.dragStartY)+'px';
Chris@0 375 };
Chris@0 376
Chris@0 377 jsToolBar.prototype.resizeDragStop = function(event) {
Chris@0 378 document.removeEventListener('mousemove', this.dragMoveHdlr, false);
Chris@0 379 document.removeEventListener('mouseup', this.dragStopHdlr, false);
Chris@0 380 };