[ Index ] |
WordPress Cross Reference |
[Summary view] [Print] [Text view]
1 /* global adminpage, wpActiveEditor, quicktagsL10n, wpLink, fullscreen, prompt */ 2 /* 3 * Quicktags 4 * 5 * This is the HTML editor in WordPress. It can be attached to any textarea and will 6 * append a toolbar above it. This script is self-contained (does not require external libraries). 7 * 8 * Run quicktags(settings) to initialize it, where settings is an object containing up to 3 properties: 9 * settings = { 10 * id : 'my_id', the HTML ID of the textarea, required 11 * buttons: '' Comma separated list of the names of the default buttons to show. Optional. 12 * Current list of default button names: 'strong,em,link,block,del,ins,img,ul,ol,li,code,more,close'; 13 * } 14 * 15 * The settings can also be a string quicktags_id. 16 * 17 * quicktags_id string The ID of the textarea that will be the editor canvas 18 * buttons string Comma separated list of the default buttons names that will be shown in that instance. 19 */ 20 21 // new edit toolbar used with permission 22 // by Alex King 23 // http://www.alexking.org/ 24 25 var QTags, edCanvas, 26 edButtons = []; 27 28 /* jshint ignore:start */ 29 30 /** 31 * Back-compat 32 * 33 * Define all former global functions so plugins that hack quicktags.js directly don't cause fatal errors. 34 */ 35 var edAddTag = function(){}, 36 edCheckOpenTags = function(){}, 37 edCloseAllTags = function(){}, 38 edInsertImage = function(){}, 39 edInsertLink = function(){}, 40 edInsertTag = function(){}, 41 edLink = function(){}, 42 edQuickLink = function(){}, 43 edRemoveTag = function(){}, 44 edShowButton = function(){}, 45 edShowLinks = function(){}, 46 edSpell = function(){}, 47 edToolbar = function(){}; 48 49 /** 50 * Initialize new instance of the Quicktags editor 51 */ 52 function quicktags(settings) { 53 return new QTags(settings); 54 } 55 56 /** 57 * Inserts content at the caret in the active editor (textarea) 58 * 59 * Added for back compatibility 60 * @see QTags.insertContent() 61 */ 62 function edInsertContent(bah, txt) { 63 return QTags.insertContent(txt); 64 } 65 66 /** 67 * Adds a button to all instances of the editor 68 * 69 * Added for back compatibility, use QTags.addButton() as it gives more flexibility like type of button, button placement, etc. 70 * @see QTags.addButton() 71 */ 72 function edButton(id, display, tagStart, tagEnd, access) { 73 return QTags.addButton( id, display, tagStart, tagEnd, access, '', -1 ); 74 } 75 76 /* jshint ignore:end */ 77 78 (function(){ 79 // private stuff is prefixed with an underscore 80 var _domReady = function(func) { 81 var t, i, DOMContentLoaded, _tryReady; 82 83 if ( typeof jQuery !== 'undefined' ) { 84 jQuery(document).ready(func); 85 } else { 86 t = _domReady; 87 t.funcs = []; 88 89 t.ready = function() { 90 if ( ! t.isReady ) { 91 t.isReady = true; 92 for ( i = 0; i < t.funcs.length; i++ ) { 93 t.funcs[i](); 94 } 95 } 96 }; 97 98 if ( t.isReady ) { 99 func(); 100 } else { 101 t.funcs.push(func); 102 } 103 104 if ( ! t.eventAttached ) { 105 if ( document.addEventListener ) { 106 DOMContentLoaded = function(){document.removeEventListener('DOMContentLoaded', DOMContentLoaded, false);t.ready();}; 107 document.addEventListener('DOMContentLoaded', DOMContentLoaded, false); 108 window.addEventListener('load', t.ready, false); 109 } else if ( document.attachEvent ) { 110 DOMContentLoaded = function(){if (document.readyState === 'complete'){ document.detachEvent('onreadystatechange', DOMContentLoaded);t.ready();}}; 111 document.attachEvent('onreadystatechange', DOMContentLoaded); 112 window.attachEvent('onload', t.ready); 113 114 _tryReady = function() { 115 try { 116 document.documentElement.doScroll('left'); 117 } catch(e) { 118 setTimeout(_tryReady, 50); 119 return; 120 } 121 122 t.ready(); 123 }; 124 _tryReady(); 125 } 126 127 t.eventAttached = true; 128 } 129 } 130 }, 131 132 _datetime = (function() { 133 var now = new Date(), zeroise; 134 135 zeroise = function(number) { 136 var str = number.toString(); 137 138 if ( str.length < 2 ) { 139 str = '0' + str; 140 } 141 142 return str; 143 }; 144 145 return now.getUTCFullYear() + '-' + 146 zeroise( now.getUTCMonth() + 1 ) + '-' + 147 zeroise( now.getUTCDate() ) + 'T' + 148 zeroise( now.getUTCHours() ) + ':' + 149 zeroise( now.getUTCMinutes() ) + ':' + 150 zeroise( now.getUTCSeconds() ) + 151 '+00:00'; 152 })(), 153 qt; 154 155 qt = QTags = function(settings) { 156 if ( typeof(settings) === 'string' ) { 157 settings = {id: settings}; 158 } else if ( typeof(settings) !== 'object' ) { 159 return false; 160 } 161 162 var t = this, 163 id = settings.id, 164 canvas = document.getElementById(id), 165 name = 'qt_' + id, 166 tb, onclick, toolbar_id; 167 168 if ( !id || !canvas ) { 169 return false; 170 } 171 172 t.name = name; 173 t.id = id; 174 t.canvas = canvas; 175 t.settings = settings; 176 177 if ( id === 'content' && typeof(adminpage) === 'string' && ( adminpage === 'post-new-php' || adminpage === 'post-php' ) ) { 178 // back compat hack :-( 179 edCanvas = canvas; 180 toolbar_id = 'ed_toolbar'; 181 } else { 182 toolbar_id = name + '_toolbar'; 183 } 184 185 tb = document.createElement('div'); 186 tb.id = toolbar_id; 187 tb.className = 'quicktags-toolbar'; 188 189 canvas.parentNode.insertBefore(tb, canvas); 190 t.toolbar = tb; 191 192 // listen for click events 193 onclick = function(e) { 194 e = e || window.event; 195 var target = e.target || e.srcElement, visible = target.clientWidth || target.offsetWidth, i; 196 197 // don't call the callback on pressing the accesskey when the button is not visible 198 if ( !visible ) { 199 return; 200 } 201 202 // as long as it has the class ed_button, execute the callback 203 if ( / ed_button /.test(' ' + target.className + ' ') ) { 204 // we have to reassign canvas here 205 t.canvas = canvas = document.getElementById(id); 206 i = target.id.replace(name + '_', ''); 207 208 if ( t.theButtons[i] ) { 209 t.theButtons[i].callback.call(t.theButtons[i], target, canvas, t); 210 } 211 } 212 }; 213 214 if ( tb.addEventListener ) { 215 tb.addEventListener('click', onclick, false); 216 } else if ( tb.attachEvent ) { 217 tb.attachEvent('onclick', onclick); 218 } 219 220 t.getButton = function(id) { 221 return t.theButtons[id]; 222 }; 223 224 t.getButtonElement = function(id) { 225 return document.getElementById(name + '_' + id); 226 }; 227 228 qt.instances[id] = t; 229 230 if ( !qt.instances[0] ) { 231 qt.instances[0] = qt.instances[id]; 232 _domReady( function(){ qt._buttonsInit(); } ); 233 } 234 }; 235 236 qt.instances = {}; 237 238 qt.getInstance = function(id) { 239 return qt.instances[id]; 240 }; 241 242 qt._buttonsInit = function() { 243 var t = this, canvas, name, settings, theButtons, html, inst, ed, id, i, use, 244 defaults = ',strong,em,link,block,del,ins,img,ul,ol,li,code,more,close,'; 245 246 for ( inst in t.instances ) { 247 if ( inst === 0 ) { 248 continue; 249 } 250 251 ed = t.instances[inst]; 252 canvas = ed.canvas; 253 name = ed.name; 254 settings = ed.settings; 255 html = ''; 256 theButtons = {}; 257 use = ''; 258 259 // set buttons 260 if ( settings.buttons ) { 261 use = ','+settings.buttons+','; 262 } 263 264 for ( i in edButtons ) { 265 if ( !edButtons[i] ) { 266 continue; 267 } 268 269 id = edButtons[i].id; 270 if ( use && defaults.indexOf( ',' + id + ',' ) !== -1 && use.indexOf( ',' + id + ',' ) === -1 ) { 271 continue; 272 } 273 274 if ( !edButtons[i].instance || edButtons[i].instance === inst ) { 275 theButtons[id] = edButtons[i]; 276 277 if ( edButtons[i].html ) { 278 html += edButtons[i].html(name + '_'); 279 } 280 } 281 } 282 283 if ( use && use.indexOf(',fullscreen,') !== -1 ) { 284 theButtons.fullscreen = new qt.FullscreenButton(); 285 html += theButtons.fullscreen.html(name + '_'); 286 } 287 288 289 if ( 'rtl' === document.getElementsByTagName('html')[0].dir ) { 290 theButtons.textdirection = new qt.TextDirectionButton(); 291 html += theButtons.textdirection.html(name + '_'); 292 } 293 294 ed.toolbar.innerHTML = html; 295 ed.theButtons = theButtons; 296 } 297 t.buttonsInitDone = true; 298 }; 299 300 /** 301 * Main API function for adding a button to Quicktags 302 * 303 * Adds qt.Button or qt.TagButton depending on the args. The first three args are always required. 304 * To be able to add button(s) to Quicktags, your script should be enqueued as dependent 305 * on "quicktags" and outputted in the footer. If you are echoing JS directly from PHP, 306 * use add_action( 'admin_print_footer_scripts', 'output_my_js', 100 ) or add_action( 'wp_footer', 'output_my_js', 100 ) 307 * 308 * Minimum required to add a button that calls an external function: 309 * QTags.addButton( 'my_id', 'my button', my_callback ); 310 * function my_callback() { alert('yeah!'); } 311 * 312 * Minimum required to add a button that inserts a tag: 313 * QTags.addButton( 'my_id', 'my button', '<span>', '</span>' ); 314 * QTags.addButton( 'my_id2', 'my button', '<br />' ); 315 * 316 * @param string id Required. Button HTML ID 317 * @param string display Required. Button's value="..." 318 * @param string|function arg1 Required. Either a starting tag to be inserted like "<span>" or a callback that is executed when the button is clicked. 319 * @param string arg2 Optional. Ending tag like "</span>" 320 * @param string access_key Optional. Access key for the button. 321 * @param string title Optional. Button's title="..." 322 * @param int priority Optional. Number representing the desired position of the button in the toolbar. 1 - 9 = first, 11 - 19 = second, 21 - 29 = third, etc. 323 * @param string instance Optional. Limit the button to a specifric instance of Quicktags, add to all instances if not present. 324 * @return mixed null or the button object that is needed for back-compat. 325 */ 326 qt.addButton = function( id, display, arg1, arg2, access_key, title, priority, instance ) { 327 var btn; 328 329 if ( !id || !display ) { 330 return; 331 } 332 333 priority = priority || 0; 334 arg2 = arg2 || ''; 335 336 if ( typeof(arg1) === 'function' ) { 337 btn = new qt.Button(id, display, access_key, title, instance); 338 btn.callback = arg1; 339 } else if ( typeof(arg1) === 'string' ) { 340 btn = new qt.TagButton(id, display, arg1, arg2, access_key, title, instance); 341 } else { 342 return; 343 } 344 345 if ( priority === -1 ) { // back-compat 346 return btn; 347 } 348 349 if ( priority > 0 ) { 350 while ( typeof(edButtons[priority]) !== 'undefined' ) { 351 priority++; 352 } 353 354 edButtons[priority] = btn; 355 } else { 356 edButtons[edButtons.length] = btn; 357 } 358 359 if ( this.buttonsInitDone ) { 360 this._buttonsInit(); // add the button HTML to all instances toolbars if addButton() was called too late 361 } 362 }; 363 364 qt.insertContent = function(content) { 365 var sel, startPos, endPos, scrollTop, text, canvas = document.getElementById(wpActiveEditor); 366 367 if ( !canvas ) { 368 return false; 369 } 370 371 if ( document.selection ) { //IE 372 canvas.focus(); 373 sel = document.selection.createRange(); 374 sel.text = content; 375 canvas.focus(); 376 } else if ( canvas.selectionStart || canvas.selectionStart === 0 ) { // FF, WebKit, Opera 377 text = canvas.value; 378 startPos = canvas.selectionStart; 379 endPos = canvas.selectionEnd; 380 scrollTop = canvas.scrollTop; 381 382 canvas.value = text.substring(0, startPos) + content + text.substring(endPos, text.length); 383 384 canvas.focus(); 385 canvas.selectionStart = startPos + content.length; 386 canvas.selectionEnd = startPos + content.length; 387 canvas.scrollTop = scrollTop; 388 } else { 389 canvas.value += content; 390 canvas.focus(); 391 } 392 return true; 393 }; 394 395 // a plain, dumb button 396 qt.Button = function(id, display, access, title, instance) { 397 var t = this; 398 t.id = id; 399 t.display = display; 400 t.access = access; 401 t.title = title || ''; 402 t.instance = instance || ''; 403 }; 404 qt.Button.prototype.html = function(idPrefix) { 405 var access = this.access ? ' accesskey="' + this.access + '"' : ''; 406 return '<input type="button" id="' + idPrefix + this.id + '"' + access + ' class="ed_button" title="' + this.title + '" value="' + this.display + '" />'; 407 }; 408 qt.Button.prototype.callback = function(){}; 409 410 // a button that inserts HTML tag 411 qt.TagButton = function(id, display, tagStart, tagEnd, access, title, instance) { 412 var t = this; 413 qt.Button.call(t, id, display, access, title, instance); 414 t.tagStart = tagStart; 415 t.tagEnd = tagEnd; 416 }; 417 qt.TagButton.prototype = new qt.Button(); 418 qt.TagButton.prototype.openTag = function(e, ed) { 419 var t = this; 420 421 if ( ! ed.openTags ) { 422 ed.openTags = []; 423 } 424 if ( t.tagEnd ) { 425 ed.openTags.push(t.id); 426 e.value = '/' + e.value; 427 } 428 }; 429 qt.TagButton.prototype.closeTag = function(e, ed) { 430 var t = this, i = t.isOpen(ed); 431 432 if ( i !== false ) { 433 ed.openTags.splice(i, 1); 434 } 435 436 e.value = t.display; 437 }; 438 // whether a tag is open or not. Returns false if not open, or current open depth of the tag 439 qt.TagButton.prototype.isOpen = function (ed) { 440 var t = this, i = 0, ret = false; 441 if ( ed.openTags ) { 442 while ( ret === false && i < ed.openTags.length ) { 443 ret = ed.openTags[i] === t.id ? i : false; 444 i ++; 445 } 446 } else { 447 ret = false; 448 } 449 return ret; 450 }; 451 qt.TagButton.prototype.callback = function(element, canvas, ed) { 452 var t = this, startPos, endPos, cursorPos, scrollTop, v = canvas.value, l, r, i, sel, endTag = v ? t.tagEnd : ''; 453 454 if ( document.selection ) { // IE 455 canvas.focus(); 456 sel = document.selection.createRange(); 457 if ( sel.text.length > 0 ) { 458 if ( !t.tagEnd ) { 459 sel.text = sel.text + t.tagStart; 460 } else { 461 sel.text = t.tagStart + sel.text + endTag; 462 } 463 } else { 464 if ( !t.tagEnd ) { 465 sel.text = t.tagStart; 466 } else if ( t.isOpen(ed) === false ) { 467 sel.text = t.tagStart; 468 t.openTag(element, ed); 469 } else { 470 sel.text = endTag; 471 t.closeTag(element, ed); 472 } 473 } 474 canvas.focus(); 475 } else if ( canvas.selectionStart || canvas.selectionStart === 0 ) { // FF, WebKit, Opera 476 startPos = canvas.selectionStart; 477 endPos = canvas.selectionEnd; 478 cursorPos = endPos; 479 scrollTop = canvas.scrollTop; 480 l = v.substring(0, startPos); // left of the selection 481 r = v.substring(endPos, v.length); // right of the selection 482 i = v.substring(startPos, endPos); // inside the selection 483 if ( startPos !== endPos ) { 484 if ( !t.tagEnd ) { 485 canvas.value = l + i + t.tagStart + r; // insert self closing tags after the selection 486 cursorPos += t.tagStart.length; 487 } else { 488 canvas.value = l + t.tagStart + i + endTag + r; 489 cursorPos += t.tagStart.length + endTag.length; 490 } 491 } else { 492 if ( !t.tagEnd ) { 493 canvas.value = l + t.tagStart + r; 494 cursorPos = startPos + t.tagStart.length; 495 } else if ( t.isOpen(ed) === false ) { 496 canvas.value = l + t.tagStart + r; 497 t.openTag(element, ed); 498 cursorPos = startPos + t.tagStart.length; 499 } else { 500 canvas.value = l + endTag + r; 501 cursorPos = startPos + endTag.length; 502 t.closeTag(element, ed); 503 } 504 } 505 506 canvas.focus(); 507 canvas.selectionStart = cursorPos; 508 canvas.selectionEnd = cursorPos; 509 canvas.scrollTop = scrollTop; 510 } else { // other browsers? 511 if ( !endTag ) { 512 canvas.value += t.tagStart; 513 } else if ( t.isOpen(ed) !== false ) { 514 canvas.value += t.tagStart; 515 t.openTag(element, ed); 516 } else { 517 canvas.value += endTag; 518 t.closeTag(element, ed); 519 } 520 canvas.focus(); 521 } 522 }; 523 524 // removed 525 qt.SpellButton = function() {}; 526 527 // the close tags button 528 qt.CloseButton = function() { 529 qt.Button.call(this, 'close', quicktagsL10n.closeTags, '', quicktagsL10n.closeAllOpenTags); 530 }; 531 532 qt.CloseButton.prototype = new qt.Button(); 533 534 qt._close = function(e, c, ed) { 535 var button, element, tbo = ed.openTags; 536 537 if ( tbo ) { 538 while ( tbo.length > 0 ) { 539 button = ed.getButton(tbo[tbo.length - 1]); 540 element = document.getElementById(ed.name + '_' + button.id); 541 542 if ( e ) { 543 button.callback.call(button, element, c, ed); 544 } else { 545 button.closeTag(element, ed); 546 } 547 } 548 } 549 }; 550 551 qt.CloseButton.prototype.callback = qt._close; 552 553 qt.closeAllTags = function(editor_id) { 554 var ed = this.getInstance(editor_id); 555 qt._close('', ed.canvas, ed); 556 }; 557 558 // the link button 559 qt.LinkButton = function() { 560 qt.TagButton.call(this, 'link', 'link', '', '</a>', 'a'); 561 }; 562 qt.LinkButton.prototype = new qt.TagButton(); 563 qt.LinkButton.prototype.callback = function(e, c, ed, defaultValue) { 564 var URL, t = this; 565 566 if ( typeof(wpLink) !== 'undefined' ) { 567 wpLink.open(); 568 return; 569 } 570 571 if ( ! defaultValue ) { 572 defaultValue = 'http://'; 573 } 574 575 if ( t.isOpen(ed) === false ) { 576 URL = prompt(quicktagsL10n.enterURL, defaultValue); 577 if ( URL ) { 578 t.tagStart = '<a href="' + URL + '">'; 579 qt.TagButton.prototype.callback.call(t, e, c, ed); 580 } 581 } else { 582 qt.TagButton.prototype.callback.call(t, e, c, ed); 583 } 584 }; 585 586 // the img button 587 qt.ImgButton = function() { 588 qt.TagButton.call(this, 'img', 'img', '', '', 'm'); 589 }; 590 qt.ImgButton.prototype = new qt.TagButton(); 591 qt.ImgButton.prototype.callback = function(e, c, ed, defaultValue) { 592 if ( ! defaultValue ) { 593 defaultValue = 'http://'; 594 } 595 var src = prompt(quicktagsL10n.enterImageURL, defaultValue), alt; 596 if ( src ) { 597 alt = prompt(quicktagsL10n.enterImageDescription, ''); 598 this.tagStart = '<img src="' + src + '" alt="' + alt + '" />'; 599 qt.TagButton.prototype.callback.call(this, e, c, ed); 600 } 601 }; 602 603 qt.FullscreenButton = function() { 604 qt.Button.call(this, 'fullscreen', quicktagsL10n.fullscreen, 'f', quicktagsL10n.toggleFullscreen); 605 }; 606 qt.FullscreenButton.prototype = new qt.Button(); 607 qt.FullscreenButton.prototype.callback = function(e, c) { 608 if ( !c.id || typeof(fullscreen) === 'undefined' ) { 609 return; 610 } 611 612 fullscreen.on(); 613 }; 614 615 qt.TextDirectionButton = function() { 616 qt.Button.call(this, 'textdirection', quicktagsL10n.textdirection, '', quicktagsL10n.toggleTextdirection); 617 }; 618 qt.TextDirectionButton.prototype = new qt.Button(); 619 qt.TextDirectionButton.prototype.callback = function(e, c) { 620 var isRTL = ( 'rtl' === document.getElementsByTagName('html')[0].dir ), 621 currentDirection = c.style.direction; 622 623 if ( ! currentDirection ) { 624 currentDirection = ( isRTL ) ? 'rtl' : 'ltr'; 625 } 626 627 c.style.direction = ( 'rtl' === currentDirection ) ? 'ltr' : 'rtl'; 628 c.focus(); 629 }; 630 631 // ensure backward compatibility 632 edButtons[10] = new qt.TagButton('strong','b','<strong>','</strong>','b'); 633 edButtons[20] = new qt.TagButton('em','i','<em>','</em>','i'), 634 edButtons[30] = new qt.LinkButton(), // special case 635 edButtons[40] = new qt.TagButton('block','b-quote','\n\n<blockquote>','</blockquote>\n\n','q'), 636 edButtons[50] = new qt.TagButton('del','del','<del datetime="' + _datetime + '">','</del>','d'), 637 edButtons[60] = new qt.TagButton('ins','ins','<ins datetime="' + _datetime + '">','</ins>','s'), 638 edButtons[70] = new qt.ImgButton(), // special case 639 edButtons[80] = new qt.TagButton('ul','ul','<ul>\n','</ul>\n\n','u'), 640 edButtons[90] = new qt.TagButton('ol','ol','<ol>\n','</ol>\n\n','o'), 641 edButtons[100] = new qt.TagButton('li','li','\t<li>','</li>\n','l'), 642 edButtons[110] = new qt.TagButton('code','code','<code>','</code>','c'), 643 edButtons[120] = new qt.TagButton('more','more','<!--more-->','','t'), 644 edButtons[140] = new qt.CloseButton(); 645 646 })();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Tue Mar 25 01:41:18 2014 | WordPress honlapkészítés: online1.hu |