balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

quicktags.js (22601B)


      1 
      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  * @output wp-includes/js/quicktags.js
     21  */
     22 
     23 // New edit toolbar used with permission
     24 // by Alex King
     25 // http://www.alexking.org/
     26 
     27 /* global adminpage, wpActiveEditor, quicktagsL10n, wpLink, prompt, edButtons */
     28 
     29 window.edButtons = [];
     30 
     31 /* jshint ignore:start */
     32 
     33 /**
     34  * Back-compat
     35  *
     36  * Define all former global functions so plugins that hack quicktags.js directly don't cause fatal errors.
     37  */
     38 window.edAddTag = function(){};
     39 window.edCheckOpenTags = function(){};
     40 window.edCloseAllTags = function(){};
     41 window.edInsertImage = function(){};
     42 window.edInsertLink = function(){};
     43 window.edInsertTag = function(){};
     44 window.edLink = function(){};
     45 window.edQuickLink = function(){};
     46 window.edRemoveTag = function(){};
     47 window.edShowButton = function(){};
     48 window.edShowLinks = function(){};
     49 window.edSpell = function(){};
     50 window.edToolbar = function(){};
     51 
     52 /* jshint ignore:end */
     53 
     54 (function(){
     55 	// Private stuff is prefixed with an underscore.
     56 	var _domReady = function(func) {
     57 		var t, i, DOMContentLoaded, _tryReady;
     58 
     59 		if ( typeof jQuery !== 'undefined' ) {
     60 			jQuery( func );
     61 		} else {
     62 			t = _domReady;
     63 			t.funcs = [];
     64 
     65 			t.ready = function() {
     66 				if ( ! t.isReady ) {
     67 					t.isReady = true;
     68 					for ( i = 0; i < t.funcs.length; i++ ) {
     69 						t.funcs[i]();
     70 					}
     71 				}
     72 			};
     73 
     74 			if ( t.isReady ) {
     75 				func();
     76 			} else {
     77 				t.funcs.push(func);
     78 			}
     79 
     80 			if ( ! t.eventAttached ) {
     81 				if ( document.addEventListener ) {
     82 					DOMContentLoaded = function(){document.removeEventListener('DOMContentLoaded', DOMContentLoaded, false);t.ready();};
     83 					document.addEventListener('DOMContentLoaded', DOMContentLoaded, false);
     84 					window.addEventListener('load', t.ready, false);
     85 				} else if ( document.attachEvent ) {
     86 					DOMContentLoaded = function(){if (document.readyState === 'complete'){ document.detachEvent('onreadystatechange', DOMContentLoaded);t.ready();}};
     87 					document.attachEvent('onreadystatechange', DOMContentLoaded);
     88 					window.attachEvent('onload', t.ready);
     89 
     90 					_tryReady = function() {
     91 						try {
     92 							document.documentElement.doScroll('left');
     93 						} catch(e) {
     94 							setTimeout(_tryReady, 50);
     95 							return;
     96 						}
     97 
     98 						t.ready();
     99 					};
    100 					_tryReady();
    101 				}
    102 
    103 				t.eventAttached = true;
    104 			}
    105 		}
    106 	},
    107 
    108 	_datetime = (function() {
    109 		var now = new Date(), zeroise;
    110 
    111 		zeroise = function(number) {
    112 			var str = number.toString();
    113 
    114 			if ( str.length < 2 ) {
    115 				str = '0' + str;
    116 			}
    117 
    118 			return str;
    119 		};
    120 
    121 		return now.getUTCFullYear() + '-' +
    122 			zeroise( now.getUTCMonth() + 1 ) + '-' +
    123 			zeroise( now.getUTCDate() ) + 'T' +
    124 			zeroise( now.getUTCHours() ) + ':' +
    125 			zeroise( now.getUTCMinutes() ) + ':' +
    126 			zeroise( now.getUTCSeconds() ) +
    127 			'+00:00';
    128 	})();
    129 
    130 	var qt = window.QTags = function(settings) {
    131 		if ( typeof(settings) === 'string' ) {
    132 			settings = {id: settings};
    133 		} else if ( typeof(settings) !== 'object' ) {
    134 			return false;
    135 		}
    136 
    137 		var t = this,
    138 			id = settings.id,
    139 			canvas = document.getElementById(id),
    140 			name = 'qt_' + id,
    141 			tb, onclick, toolbar_id, wrap, setActiveEditor;
    142 
    143 		if ( !id || !canvas ) {
    144 			return false;
    145 		}
    146 
    147 		t.name = name;
    148 		t.id = id;
    149 		t.canvas = canvas;
    150 		t.settings = settings;
    151 
    152 		if ( id === 'content' && typeof(adminpage) === 'string' && ( adminpage === 'post-new-php' || adminpage === 'post-php' ) ) {
    153 			// Back compat hack :-(
    154 			window.edCanvas = canvas;
    155 			toolbar_id = 'ed_toolbar';
    156 		} else {
    157 			toolbar_id = name + '_toolbar';
    158 		}
    159 
    160 		tb = document.getElementById( toolbar_id );
    161 
    162 		if ( ! tb ) {
    163 			tb = document.createElement('div');
    164 			tb.id = toolbar_id;
    165 			tb.className = 'quicktags-toolbar';
    166 		}
    167 
    168 		canvas.parentNode.insertBefore(tb, canvas);
    169 		t.toolbar = tb;
    170 
    171 		// Listen for click events.
    172 		onclick = function(e) {
    173 			e = e || window.event;
    174 			var target = e.target || e.srcElement, visible = target.clientWidth || target.offsetWidth, i;
    175 
    176 			// Don't call the callback on pressing the accesskey when the button is not visible.
    177 			if ( !visible ) {
    178 				return;
    179 			}
    180 
    181 			// As long as it has the class ed_button, execute the callback.
    182 			if ( / ed_button /.test(' ' + target.className + ' ') ) {
    183 				// We have to reassign canvas here.
    184 				t.canvas = canvas = document.getElementById(id);
    185 				i = target.id.replace(name + '_', '');
    186 
    187 				if ( t.theButtons[i] ) {
    188 					t.theButtons[i].callback.call(t.theButtons[i], target, canvas, t);
    189 				}
    190 			}
    191 		};
    192 
    193 		setActiveEditor = function() {
    194 			window.wpActiveEditor = id;
    195 		};
    196 
    197 		wrap = document.getElementById( 'wp-' + id + '-wrap' );
    198 
    199 		if ( tb.addEventListener ) {
    200 			tb.addEventListener( 'click', onclick, false );
    201 
    202 			if ( wrap ) {
    203 				wrap.addEventListener( 'click', setActiveEditor, false );
    204 			}
    205 		} else if ( tb.attachEvent ) {
    206 			tb.attachEvent( 'onclick', onclick );
    207 
    208 			if ( wrap ) {
    209 				wrap.attachEvent( 'onclick', setActiveEditor );
    210 			}
    211 		}
    212 
    213 		t.getButton = function(id) {
    214 			return t.theButtons[id];
    215 		};
    216 
    217 		t.getButtonElement = function(id) {
    218 			return document.getElementById(name + '_' + id);
    219 		};
    220 
    221 		t.init = function() {
    222 			_domReady( function(){ qt._buttonsInit( id ); } );
    223 		};
    224 
    225 		t.remove = function() {
    226 			delete qt.instances[id];
    227 
    228 			if ( tb && tb.parentNode ) {
    229 				tb.parentNode.removeChild( tb );
    230 			}
    231 		};
    232 
    233 		qt.instances[id] = t;
    234 		t.init();
    235 	};
    236 
    237 	function _escape( text ) {
    238 		text = text || '';
    239 		text = text.replace( /&([^#])(?![a-z1-4]{1,8};)/gi, '&#038;$1' );
    240 		return text.replace( /</g, '&lt;' ).replace( />/g, '&gt;' ).replace( /"/g, '&quot;' ).replace( /'/g, '&#039;' );
    241 	}
    242 
    243 	qt.instances = {};
    244 
    245 	qt.getInstance = function(id) {
    246 		return qt.instances[id];
    247 	};
    248 
    249 	qt._buttonsInit = function( id ) {
    250 		var t = this;
    251 
    252 		function _init( instanceId ) {
    253 			var canvas, name, settings, theButtons, html, ed, id, i, use,
    254 				defaults = ',strong,em,link,block,del,ins,img,ul,ol,li,code,more,close,';
    255 
    256 			ed = t.instances[instanceId];
    257 			canvas = ed.canvas;
    258 			name = ed.name;
    259 			settings = ed.settings;
    260 			html = '';
    261 			theButtons = {};
    262 			use = '';
    263 
    264 			// Set buttons.
    265 			if ( settings.buttons ) {
    266 				use = ','+settings.buttons+',';
    267 			}
    268 
    269 			for ( i in edButtons ) {
    270 				if ( ! edButtons[i] ) {
    271 					continue;
    272 				}
    273 
    274 				id = edButtons[i].id;
    275 				if ( use && defaults.indexOf( ',' + id + ',' ) !== -1 && use.indexOf( ',' + id + ',' ) === -1 ) {
    276 					continue;
    277 				}
    278 
    279 				if ( ! edButtons[i].instance || edButtons[i].instance === instanceId ) {
    280 					theButtons[id] = edButtons[i];
    281 
    282 					if ( edButtons[i].html ) {
    283 						html += edButtons[i].html( name + '_' );
    284 					}
    285 				}
    286 			}
    287 
    288 			if ( use && use.indexOf(',dfw,') !== -1 ) {
    289 				theButtons.dfw = new qt.DFWButton();
    290 				html += theButtons.dfw.html( name + '_' );
    291 			}
    292 
    293 			if ( 'rtl' === document.getElementsByTagName( 'html' )[0].dir ) {
    294 				theButtons.textdirection = new qt.TextDirectionButton();
    295 				html += theButtons.textdirection.html( name + '_' );
    296 			}
    297 
    298 			ed.toolbar.innerHTML = html;
    299 			ed.theButtons = theButtons;
    300 
    301 			if ( typeof jQuery !== 'undefined' ) {
    302 				jQuery( document ).triggerHandler( 'quicktags-init', [ ed ] );
    303 			}
    304 		}
    305 
    306 		if ( id ) {
    307 			_init( id );
    308 		} else {
    309 			for ( id in t.instances ) {
    310 				_init( id );
    311 			}
    312 		}
    313 
    314 		t.buttonsInitDone = true;
    315 	};
    316 
    317 	/**
    318 	 * Main API function for adding a button to Quicktags
    319 	 *
    320 	 * Adds qt.Button or qt.TagButton depending on the args. The first three args are always required.
    321 	 * To be able to add button(s) to Quicktags, your script should be enqueued as dependent
    322 	 * on "quicktags" and outputted in the footer. If you are echoing JS directly from PHP,
    323 	 * use add_action( 'admin_print_footer_scripts', 'output_my_js', 100 ) or add_action( 'wp_footer', 'output_my_js', 100 )
    324 	 *
    325 	 * Minimum required to add a button that calls an external function:
    326 	 *     QTags.addButton( 'my_id', 'my button', my_callback );
    327 	 *     function my_callback() { alert('yeah!'); }
    328 	 *
    329 	 * Minimum required to add a button that inserts a tag:
    330 	 *     QTags.addButton( 'my_id', 'my button', '<span>', '</span>' );
    331 	 *     QTags.addButton( 'my_id2', 'my button', '<br />' );
    332 	 *
    333 	 * @param string id Required. Button HTML ID
    334 	 * @param string display Required. Button's value="..."
    335 	 * @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.
    336 	 * @param string arg2 Optional. Ending tag like "</span>"
    337 	 * @param string access_key Deprecated Not used
    338 	 * @param string title Optional. Button's title="..."
    339 	 * @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.
    340 	 * @param string instance Optional. Limit the button to a specific instance of Quicktags, add to all instances if not present.
    341 	 * @param attr object Optional. Used to pass additional attributes. Currently supports `ariaLabel` and `ariaLabelClose` (for "close tag" state)
    342 	 * @return mixed null or the button object that is needed for back-compat.
    343 	 */
    344 	qt.addButton = function( id, display, arg1, arg2, access_key, title, priority, instance, attr ) {
    345 		var btn;
    346 
    347 		if ( !id || !display ) {
    348 			return;
    349 		}
    350 
    351 		priority = priority || 0;
    352 		arg2 = arg2 || '';
    353 		attr = attr || {};
    354 
    355 		if ( typeof(arg1) === 'function' ) {
    356 			btn = new qt.Button( id, display, access_key, title, instance, attr );
    357 			btn.callback = arg1;
    358 		} else if ( typeof(arg1) === 'string' ) {
    359 			btn = new qt.TagButton( id, display, arg1, arg2, access_key, title, instance, attr );
    360 		} else {
    361 			return;
    362 		}
    363 
    364 		if ( priority === -1 ) { // Back-compat.
    365 			return btn;
    366 		}
    367 
    368 		if ( priority > 0 ) {
    369 			while ( typeof(edButtons[priority]) !== 'undefined' ) {
    370 				priority++;
    371 			}
    372 
    373 			edButtons[priority] = btn;
    374 		} else {
    375 			edButtons[edButtons.length] = btn;
    376 		}
    377 
    378 		if ( this.buttonsInitDone ) {
    379 			this._buttonsInit(); // Add the button HTML to all instances toolbars if addButton() was called too late.
    380 		}
    381 	};
    382 
    383 	qt.insertContent = function(content) {
    384 		var sel, startPos, endPos, scrollTop, text, canvas = document.getElementById(wpActiveEditor), event;
    385 
    386 		if ( !canvas ) {
    387 			return false;
    388 		}
    389 
    390 		if ( document.selection ) { // IE.
    391 			canvas.focus();
    392 			sel = document.selection.createRange();
    393 			sel.text = content;
    394 			canvas.focus();
    395 		} else if ( canvas.selectionStart || canvas.selectionStart === 0 ) { // FF, WebKit, Opera.
    396 			text = canvas.value;
    397 			startPos = canvas.selectionStart;
    398 			endPos = canvas.selectionEnd;
    399 			scrollTop = canvas.scrollTop;
    400 
    401 			canvas.value = text.substring(0, startPos) + content + text.substring(endPos, text.length);
    402 
    403 			canvas.selectionStart = startPos + content.length;
    404 			canvas.selectionEnd = startPos + content.length;
    405 			canvas.scrollTop = scrollTop;
    406 			canvas.focus();
    407 		} else {
    408 			canvas.value += content;
    409 			canvas.focus();
    410 		}
    411 
    412 		if ( document.createEvent ) {
    413 			event = document.createEvent( 'HTMLEvents' );
    414 			event.initEvent( 'change', false, true );
    415 			canvas.dispatchEvent( event );
    416 		} else if ( canvas.fireEvent ) {
    417 			canvas.fireEvent( 'onchange' );
    418 		}
    419 
    420 		return true;
    421 	};
    422 
    423 	// A plain, dumb button.
    424 	qt.Button = function( id, display, access, title, instance, attr ) {
    425 		this.id = id;
    426 		this.display = display;
    427 		this.access = '';
    428 		this.title = title || '';
    429 		this.instance = instance || '';
    430 		this.attr = attr || {};
    431 	};
    432 	qt.Button.prototype.html = function(idPrefix) {
    433 		var active, on, wp,
    434 			title = this.title ? ' title="' + _escape( this.title ) + '"' : '',
    435 			ariaLabel = this.attr && this.attr.ariaLabel ? ' aria-label="' + _escape( this.attr.ariaLabel ) + '"' : '',
    436 			val = this.display ? ' value="' + _escape( this.display ) + '"' : '',
    437 			id = this.id ? ' id="' + _escape( idPrefix + this.id ) + '"' : '',
    438 			dfw = ( wp = window.wp ) && wp.editor && wp.editor.dfw;
    439 
    440 		if ( this.id === 'fullscreen' ) {
    441 			return '<button type="button"' + id + ' class="ed_button qt-dfw qt-fullscreen"' + title + ariaLabel + '></button>';
    442 		} else if ( this.id === 'dfw' ) {
    443 			active = dfw && dfw.isActive() ? '' : ' disabled="disabled"';
    444 			on = dfw && dfw.isOn() ? ' active' : '';
    445 
    446 			return '<button type="button"' + id + ' class="ed_button qt-dfw' + on + '"' + title + ariaLabel + active + '></button>';
    447 		}
    448 
    449 		return '<input type="button"' + id + ' class="ed_button button button-small"' + title + ariaLabel + val + ' />';
    450 	};
    451 	qt.Button.prototype.callback = function(){};
    452 
    453 	// A button that inserts HTML tag.
    454 	qt.TagButton = function( id, display, tagStart, tagEnd, access, title, instance, attr ) {
    455 		var t = this;
    456 		qt.Button.call( t, id, display, access, title, instance, attr );
    457 		t.tagStart = tagStart;
    458 		t.tagEnd = tagEnd;
    459 	};
    460 	qt.TagButton.prototype = new qt.Button();
    461 	qt.TagButton.prototype.openTag = function( element, ed ) {
    462 		if ( ! ed.openTags ) {
    463 			ed.openTags = [];
    464 		}
    465 
    466 		if ( this.tagEnd ) {
    467 			ed.openTags.push( this.id );
    468 			element.value = '/' + element.value;
    469 
    470 			if ( this.attr.ariaLabelClose ) {
    471 				element.setAttribute( 'aria-label', this.attr.ariaLabelClose );
    472 			}
    473 		}
    474 	};
    475 	qt.TagButton.prototype.closeTag = function( element, ed ) {
    476 		var i = this.isOpen(ed);
    477 
    478 		if ( i !== false ) {
    479 			ed.openTags.splice( i, 1 );
    480 		}
    481 
    482 		element.value = this.display;
    483 
    484 		if ( this.attr.ariaLabel ) {
    485 			element.setAttribute( 'aria-label', this.attr.ariaLabel );
    486 		}
    487 	};
    488 	// Whether a tag is open or not. Returns false if not open, or current open depth of the tag.
    489 	qt.TagButton.prototype.isOpen = function (ed) {
    490 		var t = this, i = 0, ret = false;
    491 		if ( ed.openTags ) {
    492 			while ( ret === false && i < ed.openTags.length ) {
    493 				ret = ed.openTags[i] === t.id ? i : false;
    494 				i ++;
    495 			}
    496 		} else {
    497 			ret = false;
    498 		}
    499 		return ret;
    500 	};
    501 	qt.TagButton.prototype.callback = function(element, canvas, ed) {
    502 		var t = this, startPos, endPos, cursorPos, scrollTop, v = canvas.value, l, r, i, sel, endTag = v ? t.tagEnd : '', event;
    503 
    504 		if ( document.selection ) { // IE.
    505 			canvas.focus();
    506 			sel = document.selection.createRange();
    507 			if ( sel.text.length > 0 ) {
    508 				if ( !t.tagEnd ) {
    509 					sel.text = sel.text + t.tagStart;
    510 				} else {
    511 					sel.text = t.tagStart + sel.text + endTag;
    512 				}
    513 			} else {
    514 				if ( !t.tagEnd ) {
    515 					sel.text = t.tagStart;
    516 				} else if ( t.isOpen(ed) === false ) {
    517 					sel.text = t.tagStart;
    518 					t.openTag(element, ed);
    519 				} else {
    520 					sel.text = endTag;
    521 					t.closeTag(element, ed);
    522 				}
    523 			}
    524 			canvas.focus();
    525 		} else if ( canvas.selectionStart || canvas.selectionStart === 0 ) { // FF, WebKit, Opera.
    526 			startPos = canvas.selectionStart;
    527 			endPos = canvas.selectionEnd;
    528 
    529 			if ( startPos < endPos && v.charAt( endPos - 1 ) === '\n' ) {
    530 				endPos -= 1;
    531 			}
    532 
    533 			cursorPos = endPos;
    534 			scrollTop = canvas.scrollTop;
    535 			l = v.substring(0, startPos);      // Left of the selection.
    536 			r = v.substring(endPos, v.length); // Right of the selection.
    537 			i = v.substring(startPos, endPos); // Inside the selection.
    538 			if ( startPos !== endPos ) {
    539 				if ( !t.tagEnd ) {
    540 					canvas.value = l + i + t.tagStart + r; // Insert self-closing tags after the selection.
    541 					cursorPos += t.tagStart.length;
    542 				} else {
    543 					canvas.value = l + t.tagStart + i + endTag + r;
    544 					cursorPos += t.tagStart.length + endTag.length;
    545 				}
    546 			} else {
    547 				if ( !t.tagEnd ) {
    548 					canvas.value = l + t.tagStart + r;
    549 					cursorPos = startPos + t.tagStart.length;
    550 				} else if ( t.isOpen(ed) === false ) {
    551 					canvas.value = l + t.tagStart + r;
    552 					t.openTag(element, ed);
    553 					cursorPos = startPos + t.tagStart.length;
    554 				} else {
    555 					canvas.value = l + endTag + r;
    556 					cursorPos = startPos + endTag.length;
    557 					t.closeTag(element, ed);
    558 				}
    559 			}
    560 
    561 			canvas.selectionStart = cursorPos;
    562 			canvas.selectionEnd = cursorPos;
    563 			canvas.scrollTop = scrollTop;
    564 			canvas.focus();
    565 		} else { // Other browsers?
    566 			if ( !endTag ) {
    567 				canvas.value += t.tagStart;
    568 			} else if ( t.isOpen(ed) !== false ) {
    569 				canvas.value += t.tagStart;
    570 				t.openTag(element, ed);
    571 			} else {
    572 				canvas.value += endTag;
    573 				t.closeTag(element, ed);
    574 			}
    575 			canvas.focus();
    576 		}
    577 
    578 		if ( document.createEvent ) {
    579 			event = document.createEvent( 'HTMLEvents' );
    580 			event.initEvent( 'change', false, true );
    581 			canvas.dispatchEvent( event );
    582 		} else if ( canvas.fireEvent ) {
    583 			canvas.fireEvent( 'onchange' );
    584 		}
    585 	};
    586 
    587 	// Removed.
    588 	qt.SpellButton = function() {};
    589 
    590 	// The close tags button.
    591 	qt.CloseButton = function() {
    592 		qt.Button.call( this, 'close', quicktagsL10n.closeTags, '', quicktagsL10n.closeAllOpenTags );
    593 	};
    594 
    595 	qt.CloseButton.prototype = new qt.Button();
    596 
    597 	qt._close = function(e, c, ed) {
    598 		var button, element, tbo = ed.openTags;
    599 
    600 		if ( tbo ) {
    601 			while ( tbo.length > 0 ) {
    602 				button = ed.getButton(tbo[tbo.length - 1]);
    603 				element = document.getElementById(ed.name + '_' + button.id);
    604 
    605 				if ( e ) {
    606 					button.callback.call(button, element, c, ed);
    607 				} else {
    608 					button.closeTag(element, ed);
    609 				}
    610 			}
    611 		}
    612 	};
    613 
    614 	qt.CloseButton.prototype.callback = qt._close;
    615 
    616 	qt.closeAllTags = function( editor_id ) {
    617 		var ed = this.getInstance( editor_id );
    618 
    619 		if ( ed ) {
    620 			qt._close( '', ed.canvas, ed );
    621 		}
    622 	};
    623 
    624 	// The link button.
    625 	qt.LinkButton = function() {
    626 		var attr = {
    627 			ariaLabel: quicktagsL10n.link
    628 		};
    629 
    630 		qt.TagButton.call( this, 'link', 'link', '', '</a>', '', '', '', attr );
    631 	};
    632 	qt.LinkButton.prototype = new qt.TagButton();
    633 	qt.LinkButton.prototype.callback = function(e, c, ed, defaultValue) {
    634 		var URL, t = this;
    635 
    636 		if ( typeof wpLink !== 'undefined' ) {
    637 			wpLink.open( ed.id );
    638 			return;
    639 		}
    640 
    641 		if ( ! defaultValue ) {
    642 			defaultValue = 'http://';
    643 		}
    644 
    645 		if ( t.isOpen(ed) === false ) {
    646 			URL = prompt( quicktagsL10n.enterURL, defaultValue );
    647 			if ( URL ) {
    648 				t.tagStart = '<a href="' + URL + '">';
    649 				qt.TagButton.prototype.callback.call(t, e, c, ed);
    650 			}
    651 		} else {
    652 			qt.TagButton.prototype.callback.call(t, e, c, ed);
    653 		}
    654 	};
    655 
    656 	// The img button.
    657 	qt.ImgButton = function() {
    658 		var attr = {
    659 			ariaLabel: quicktagsL10n.image
    660 		};
    661 
    662 		qt.TagButton.call( this, 'img', 'img', '', '', '', '', '', attr );
    663 	};
    664 	qt.ImgButton.prototype = new qt.TagButton();
    665 	qt.ImgButton.prototype.callback = function(e, c, ed, defaultValue) {
    666 		if ( ! defaultValue ) {
    667 			defaultValue = 'http://';
    668 		}
    669 		var src = prompt(quicktagsL10n.enterImageURL, defaultValue), alt;
    670 		if ( src ) {
    671 			alt = prompt(quicktagsL10n.enterImageDescription, '');
    672 			this.tagStart = '<img src="' + src + '" alt="' + alt + '" />';
    673 			qt.TagButton.prototype.callback.call(this, e, c, ed);
    674 		}
    675 	};
    676 
    677 	qt.DFWButton = function() {
    678 		qt.Button.call( this, 'dfw', '', 'f', quicktagsL10n.dfw );
    679 	};
    680 	qt.DFWButton.prototype = new qt.Button();
    681 	qt.DFWButton.prototype.callback = function() {
    682 		var wp;
    683 
    684 		if ( ! ( wp = window.wp ) || ! wp.editor || ! wp.editor.dfw ) {
    685 			return;
    686 		}
    687 
    688 		window.wp.editor.dfw.toggle();
    689 	};
    690 
    691 	qt.TextDirectionButton = function() {
    692 		qt.Button.call( this, 'textdirection', quicktagsL10n.textdirection, '', quicktagsL10n.toggleTextdirection );
    693 	};
    694 	qt.TextDirectionButton.prototype = new qt.Button();
    695 	qt.TextDirectionButton.prototype.callback = function(e, c) {
    696 		var isRTL = ( 'rtl' === document.getElementsByTagName('html')[0].dir ),
    697 			currentDirection = c.style.direction;
    698 
    699 		if ( ! currentDirection ) {
    700 			currentDirection = ( isRTL ) ? 'rtl' : 'ltr';
    701 		}
    702 
    703 		c.style.direction = ( 'rtl' === currentDirection ) ? 'ltr' : 'rtl';
    704 		c.focus();
    705 	};
    706 
    707 	// Ensure backward compatibility.
    708 	edButtons[10]  = new qt.TagButton( 'strong', 'b', '<strong>', '</strong>', '', '', '', { ariaLabel: quicktagsL10n.strong, ariaLabelClose: quicktagsL10n.strongClose } );
    709 	edButtons[20]  = new qt.TagButton( 'em', 'i', '<em>', '</em>', '', '', '', { ariaLabel: quicktagsL10n.em, ariaLabelClose: quicktagsL10n.emClose } );
    710 	edButtons[30]  = new qt.LinkButton(); // Special case.
    711 	edButtons[40]  = new qt.TagButton( 'block', 'b-quote', '\n\n<blockquote>', '</blockquote>\n\n', '', '', '', { ariaLabel: quicktagsL10n.blockquote, ariaLabelClose: quicktagsL10n.blockquoteClose } );
    712 	edButtons[50]  = new qt.TagButton( 'del', 'del', '<del datetime="' + _datetime + '">', '</del>', '', '', '', { ariaLabel: quicktagsL10n.del, ariaLabelClose: quicktagsL10n.delClose } );
    713 	edButtons[60]  = new qt.TagButton( 'ins', 'ins', '<ins datetime="' + _datetime + '">', '</ins>', '', '', '', { ariaLabel: quicktagsL10n.ins, ariaLabelClose: quicktagsL10n.insClose } );
    714 	edButtons[70]  = new qt.ImgButton();  // Special case.
    715 	edButtons[80]  = new qt.TagButton( 'ul', 'ul', '<ul>\n', '</ul>\n\n', '', '', '', { ariaLabel: quicktagsL10n.ul, ariaLabelClose: quicktagsL10n.ulClose } );
    716 	edButtons[90]  = new qt.TagButton( 'ol', 'ol', '<ol>\n', '</ol>\n\n', '', '', '', { ariaLabel: quicktagsL10n.ol, ariaLabelClose: quicktagsL10n.olClose } );
    717 	edButtons[100] = new qt.TagButton( 'li', 'li', '\t<li>', '</li>\n', '', '', '', { ariaLabel: quicktagsL10n.li, ariaLabelClose: quicktagsL10n.liClose } );
    718 	edButtons[110] = new qt.TagButton( 'code', 'code', '<code>', '</code>', '', '', '', { ariaLabel: quicktagsL10n.code, ariaLabelClose: quicktagsL10n.codeClose } );
    719 	edButtons[120] = new qt.TagButton( 'more', 'more', '<!--more-->\n\n', '', '', '', '', { ariaLabel: quicktagsL10n.more } );
    720 	edButtons[140] = new qt.CloseButton();
    721 
    722 })();
    723 
    724 /**
    725  * Initialize new instance of the Quicktags editor
    726  */
    727 window.quicktags = function(settings) {
    728 	return new window.QTags(settings);
    729 };
    730 
    731 /**
    732  * Inserts content at the caret in the active editor (textarea)
    733  *
    734  * Added for back compatibility
    735  * @see QTags.insertContent()
    736  */
    737 window.edInsertContent = function(bah, txt) {
    738 	return window.QTags.insertContent(txt);
    739 };
    740 
    741 /**
    742  * Adds a button to all instances of the editor
    743  *
    744  * Added for back compatibility, use QTags.addButton() as it gives more flexibility like type of button, button placement, etc.
    745  * @see QTags.addButton()
    746  */
    747 window.edButton = function(id, display, tagStart, tagEnd, access) {
    748 	return window.QTags.addButton( id, display, tagStart, tagEnd, access, '', -1 );
    749 };