r54642 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r54641‎ | r54642 | r54643 >
Date:21:29, 8 August 2009
Author:catrope
Status:ok
Tags:
Comment:
EditToolbar: Improve toolbar loading experience by adding tabs immediately instead of after their contents have been generated. This recreates the pre-refactor behavior except for the "Loading..." spinner in the tab contents.
Modified paths:
  • /trunk/extensions/UsabilityInitiative/js/plugins.combined.js (modified) (history)
  • /trunk/extensions/UsabilityInitiative/js/plugins.combined.min.js (modified) (history)
  • /trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.toolbar.js (modified) (history)

Diff [purge]

Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.toolbar.js
@@ -388,7 +388,7 @@
389389 )
390390 );
391391 } else {
392 - sectionQueue[sectionQueue.length] = {
 392+ s = {
393393 'context': context,
394394 '$sections': $sections,
395395 '$tabs': $tabs,
@@ -396,23 +396,7 @@
397397 'config': config[section],
398398 'selected': ( selected == section )
399399 };
400 - }
401 - }
402 - $.eachAsync( sectionQueue, {
403 - 'bulk': 0,
404 - 'end': function() {
405 - // HACK: Opera doesn't seem to want to redraw after these bits
406 - // are added to the DOM, so we can just FORCE it!
407 - $( 'body' ).css( 'position', 'static' );
408 - $( 'body' ).css( 'position', 'relative' );
409 - },
410 - 'loop': function( i, s ) {
411 - s.$sections.append(
412 - $.wikiEditor.modules.toolbar.fn.buildSection(
413 - s.context, s.section, s.config
414 - )
415 - .css( 'display', s.selected ? 'block' : 'none' )
416 - );
 400+ sectionQueue[sectionQueue.length] = s;
417401 s.$tabs.append(
418402 $( '<span></span>' )
419403 .attr( {
@@ -458,6 +442,24 @@
459443 )
460444 );
461445 }
 446+ }
 447+ $.eachAsync( sectionQueue, {
 448+ 'bulk': 0,
 449+ 'end': function() {
 450+ // HACK: Opera doesn't seem to want to redraw after these bits
 451+ // are added to the DOM, so we can just FORCE it!
 452+ $( 'body' ).css( 'position', 'static' );
 453+ $( 'body' ).css( 'position', 'relative' );
 454+ },
 455+ 'loop': function( i, s ) {
 456+ s.$sections.append(
 457+ $.wikiEditor.modules.toolbar.fn.buildSection(
 458+ s.context, s.section, s.config
 459+ )
 460+ .css( 'display', s.selected ? 'block' : 'none' )
 461+ );
 462+
 463+ }
462464 } );
463465 }
464466 }
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.js
@@ -1,638 +1,638 @@
2 -/*
3 - * jQuery Asynchronous Plugin 1.0
4 - *
5 - * Copyright (c) 2008 Vincent Robert (genezys.net)
6 - * Dual licensed under the MIT (MIT-LICENSE.txt)
7 - * and GPL (GPL-LICENSE.txt) licenses.
8 - *
9 - */
10 -(function($){
11 -
12 -// opts.delay : (default 10) delay between async call in ms
13 -// opts.bulk : (default 500) delay during which the loop can continue synchronously without yielding the CPU
14 -// opts.test : (default true) function to test in the while test part
15 -// opts.loop : (default empty) function to call in the while loop part
16 -// opts.end : (default empty) function to call at the end of the while loop
17 -$.whileAsync = function(opts)
18 -{
19 - var delay = Math.abs(opts.delay) || 10,
20 - bulk = isNaN(opts.bulk) ? 500 : Math.abs(opts.bulk),
21 - test = opts.test || function(){ return true; },
22 - loop = opts.loop || function(){},
23 - end = opts.end || function(){};
24 -
25 - (function(){
26 -
27 - var t = false,
28 - begin = new Date();
29 -
30 - while( t = test() )
31 - {
32 - loop();
33 - if( bulk === 0 || (new Date() - begin) > bulk )
34 - {
35 - break;
36 - }
37 - }
38 - if( t )
39 - {
40 - setTimeout(arguments.callee, delay);
41 - }
42 - else
43 - {
44 - end();
45 - }
46 -
47 - })();
48 -}
49 -
50 -// opts.delay : (default 10) delay between async call in ms
51 -// opts.bulk : (default 500) delay during which the loop can continue synchronously without yielding the CPU
52 -// opts.loop : (default empty) function to call in the each loop part, signature: function(index, value) this = value
53 -// opts.end : (default empty) function to call at the end of the each loop
54 -$.eachAsync = function(array, opts)
55 -{
56 - var i = 0,
57 - l = array.length,
58 - loop = opts.loop || function(){};
59 -
60 - $.whileAsync(
61 - $.extend(opts, {
62 - test: function(){ return i < l; },
63 - loop: function()
64 - {
65 - var val = array[i];
66 - return loop.call(val, i++, val);
67 - }
68 - })
69 - );
70 -}
71 -
72 -$.fn.eachAsync = function(opts)
73 -{
74 - $.eachAsync(this, opts);
75 - return this;
76 -}
77 -
78 -})(jQuery);
79 -
80 -/*
81 -
82 -jQuery Browser Plugin
83 - * Version 2.3
84 - * 2008-09-17 19:27:05
85 - * URL: http://jquery.thewikies.com/browser
86 - * Description: jQuery Browser Plugin extends browser detection capabilities and can assign browser selectors to CSS classes.
87 - * Author: Nate Cavanaugh, Minhchau Dang, & Jonathan Neal
88 - * Copyright: Copyright (c) 2008 Jonathan Neal under dual MIT/GPL license.
89 - * JSLint: This javascript file passes JSLint verification.
90 -*//*jslint
91 - bitwise: true,
92 - browser: true,
93 - eqeqeq: true,
94 - forin: true,
95 - nomen: true,
96 - plusplus: true,
97 - undef: true,
98 - white: true
99 -*//*global
100 - jQuery
101 -*/
102 -
103 -(function ($) {
104 - $.browserTest = function (a, z) {
105 - var u = 'unknown', x = 'X', m = function (r, h) {
106 - for (var i = 0; i < h.length; i = i + 1) {
107 - r = r.replace(h[i][0], h[i][1]);
108 - }
109 -
110 - return r;
111 - }, c = function (i, a, b, c) {
112 - var r = {
113 - name: m((a.exec(i) || [u, u])[1], b)
114 - };
115 -
116 - r[r.name] = true;
117 -
118 - r.version = (c.exec(i) || [x, x, x, x])[3];
119 -
120 - if (r.name.match(/safari/) && r.version > 400) {
121 - r.version = '2.0';
122 - }
123 -
124 - if (r.name === 'presto') {
125 - r.version = ($.browser.version > 9.27) ? 'futhark' : 'linear_b';
126 - }
127 - r.versionNumber = parseFloat(r.version, 10) || 0;
128 - r.versionX = (r.version !== x) ? (r.version + '').substr(0, 1) : x;
129 - r.className = r.name + r.versionX;
130 -
131 - return r;
132 - };
133 -
134 - a = (a.match(/Opera|Navigator|Minefield|KHTML|Chrome/) ? m(a, [
135 - [/(Firefox|MSIE|KHTML,\slike\sGecko|Konqueror)/, ''],
136 - ['Chrome Safari', 'Chrome'],
137 - ['KHTML', 'Konqueror'],
138 - ['Minefield', 'Firefox'],
139 - ['Navigator', 'Netscape']
140 - ]) : a).toLowerCase();
141 -
142 - $.browser = $.extend((!z) ? $.browser : {}, c(a, /(camino|chrome|firefox|netscape|konqueror|lynx|msie|opera|safari)/, [], /(camino|chrome|firefox|netscape|netscape6|opera|version|konqueror|lynx|msie|safari)(\/|\s)([a-z0-9\.\+]*?)(\;|dev|rel|\s|$)/));
143 -
144 - $.layout = c(a, /(gecko|konqueror|msie|opera|webkit)/, [
145 - ['konqueror', 'khtml'],
146 - ['msie', 'trident'],
147 - ['opera', 'presto']
148 - ], /(applewebkit|rv|konqueror|msie)(\:|\/|\s)([a-z0-9\.]*?)(\;|\)|\s)/);
149 -
150 - $.os = {
151 - name: (/(win|mac|linux|sunos|solaris|iphone)/.exec(navigator.platform.toLowerCase()) || [u])[0].replace('sunos', 'solaris')
152 - };
153 -
154 - if (!z) {
155 - $('html').addClass([$.os.name, $.browser.name, $.browser.className, $.layout.name, $.layout.className].join(' '));
156 - }
157 - };
158 -
159 - $.browserTest(navigator.userAgent);
160 -})(jQuery);
161 -
162 -/**
163 - * Cookie plugin
164 - *
165 - * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
166 - * Dual licensed under the MIT and GPL licenses:
167 - * http://www.opensource.org/licenses/mit-license.php
168 - * http://www.gnu.org/licenses/gpl.html
169 - *
170 - */
171 -
172 -/**
173 - * Create a cookie with the given name and value and other optional parameters.
174 - *
175 - * @example $.cookie('the_cookie', 'the_value');
176 - * @desc Set the value of a cookie.
177 - * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
178 - * @desc Create a cookie with all available options.
179 - * @example $.cookie('the_cookie', 'the_value');
180 - * @desc Create a session cookie.
181 - * @example $.cookie('the_cookie', null);
182 - * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
183 - * used when the cookie was set.
184 - *
185 - * @param String name The name of the cookie.
186 - * @param String value The value of the cookie.
187 - * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
188 - * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
189 - * If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
190 - * If set to null or omitted, the cookie will be a session cookie and will not be retained
191 - * when the the browser exits.
192 - * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
193 - * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
194 - * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
195 - * require a secure protocol (like HTTPS).
196 - * @type undefined
197 - *
198 - * @name $.cookie
199 - * @cat Plugins/Cookie
200 - * @author Klaus Hartl/klaus.hartl@stilbuero.de
201 - */
202 -
203 -/**
204 - * Get the value of a cookie with the given name.
205 - *
206 - * @example $.cookie('the_cookie');
207 - * @desc Get the value of a cookie.
208 - *
209 - * @param String name The name of the cookie.
210 - * @return The value of the cookie.
211 - * @type String
212 - *
213 - * @name $.cookie
214 - * @cat Plugins/Cookie
215 - * @author Klaus Hartl/klaus.hartl@stilbuero.de
216 - */
217 -jQuery.cookie = function(name, value, options) {
218 - if (typeof value != 'undefined') { // name and value given, set cookie
219 - options = options || {};
220 - if (value === null) {
221 - value = '';
222 - options.expires = -1;
223 - }
224 - var expires = '';
225 - if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
226 - var date;
227 - if (typeof options.expires == 'number') {
228 - date = new Date();
229 - date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
230 - } else {
231 - date = options.expires;
232 - }
233 - expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
234 - }
235 - // CAUTION: Needed to parenthesize options.path and options.domain
236 - // in the following expressions, otherwise they evaluate to undefined
237 - // in the packed version for some reason...
238 - var path = options.path ? '; path=' + (options.path) : '';
239 - var domain = options.domain ? '; domain=' + (options.domain) : '';
240 - var secure = options.secure ? '; secure' : '';
241 - document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
242 - } else { // only name given, get cookie
243 - var cookieValue = null;
244 - if (document.cookie && document.cookie != '') {
245 - var cookies = document.cookie.split(';');
246 - for (var i = 0; i < cookies.length; i++) {
247 - var cookie = jQuery.trim(cookies[i]);
248 - // Does this cookie string begin with the name we want?
249 - if (cookie.substring(0, name.length + 1) == (name + '=')) {
250 - cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
251 - break;
252 - }
253 - }
254 - }
255 - return cookieValue;
256 - }
257 -};
258 -
259 -/**
260 - * These plugins provide extra functionality for interaction with textareas.
261 - */
262 -( function( $ ) { $.fn.extend( {
263 -/**
264 - * Ported from skins/common/edit.js by Trevor Parscal
265 - * (c) 2009 Wikimedia Foundation (GPLv2) - http://www.wikimedia.org
266 - *
267 - * Inserts text at the begining and end of a text selection, optionally
268 - * inserting text at the caret when selection is empty.
269 - *
270 - * @param pre Text to insert before selection
271 - * @param peri Text to insert at caret if selection is empty
272 - * @param post Text to insert after selection
273 - */
274 -encapsulateSelection: function( pre, peri, post ) {
275 - /**
276 - * Check if the selected text is the same as the insert text
277 - */
278 - function checkSelectedText() {
279 - if ( !selText ) {
280 - selText = peri;
281 - isSample = true;
282 - } else if ( selText.charAt( selText.length - 1 ) == ' ' ) {
283 - // Exclude ending space char
284 - selText = selText.substring(0, selText.length - 1);
285 - post += ' '
286 - }
287 - }
288 - var e = this.jquery ? this[0] : this;
289 - var selText;
290 - var isSample = false;
291 - if ( document.selection && document.selection.createRange ) {
292 - // IE/Opera
293 - if ( document.documentElement && document.documentElement.scrollTop ) {
294 - var winScroll = document.documentElement.scrollTop;
295 - } else if ( document.body ) {
296 - var winScroll = document.body.scrollTop;
297 - }
298 - $(this).focus();
299 - var range = document.selection.createRange();
300 - selText = range.text;
301 - checkSelectedText();
302 - range.text = pre + selText + post;
303 - if ( isSample && range.moveStart ) {
304 - if ( window.opera ) {
305 - post = post.replace( /\n/g, '' );
306 - }
307 - range.moveStart( 'character', - post.length - selText.length );
308 - range.moveEnd( 'character', - post.length );
309 - }
310 - range.select();
311 - if ( document.documentElement && document.documentElement.scrollTop ) {
312 - document.documentElement.scrollTop = winScroll
313 - } else if ( document.body ) {
314 - document.body.scrollTop = winScroll;
315 - }
316 - } else if ( e.selectionStart || e.selectionStart == '0' ) {
317 - // Mozilla
318 - var textScroll = e.scrollTop;
319 - $(this).focus();
320 - var startPos = e.selectionStart;
321 - var endPos = e.selectionEnd;
322 - selText = e.value.substring( startPos, endPos );
323 - checkSelectedText();
324 - e.value = e.value.substring( 0, startPos ) + pre + selText + post +
325 - e.value.substring( endPos, e.value.length );
326 - if ( isSample ) {
327 - e.selectionStart = startPos + pre.length;
328 - e.selectionEnd = startPos + pre.length + selText.length;
329 - } else {
330 - e.selectionStart =
331 - startPos + pre.length + selText.length + post.length;
332 - e.selectionEnd = e.selectionStart;
333 - }
334 - e.scrollTop = textScroll;
335 - }
336 - $(this).trigger( 'encapsulateSelection' );
337 -},
338 -/**
339 - * Ported from Wikia's LinkSuggest extension
340 - * https://svn.wikia-code.com/wikia/trunk/extensions/wikia/LinkSuggest
341 - * Some code copied from
342 - * http://www.dedestruct.com/2008/03/22/howto-cross-browser-cursor-position-in-textareas/
343 - *
344 - * Get the position (in resolution of bytes not nessecarily characters)
345 - * in a textarea
346 - */
347 - getCaretPosition: function() {
348 - function getCaret( e ) {
349 - var caretPos = 0;
350 - if($.browser.msie) {
351 - // IE Support
352 - var postFinished = false;
353 - var periFinished = false;
354 - var postFinished = false;
355 - var preText, rawPreText, periText;
356 - var rawPeriText, postText, rawPostText;
357 - // Create range containing text in the selection
358 - var periRange = document.selection.createRange().duplicate();
359 - // Create range containing text before the selection
360 - var preRange = document.body.createTextRange();
361 - // Select all the text
362 - preRange.moveToElementText(e);
363 - // Move the end where we need it
364 - preRange.setEndPoint("EndToStart", periRange);
365 - // Create range containing text after the selection
366 - var postRange = document.body.createTextRange();
367 - // Select all the text
368 - postRange.moveToElementText(e);
369 - // Move the start where we need it
370 - postRange.setEndPoint("StartToEnd", periRange);
371 - // Load the text values we need to compare
372 - preText = rawPreText = preRange.text;
373 - periText = rawPeriText = periRange.text;
374 - postText = rawPostText = postRange.text;
375 - /*
376 - * Check each range for trimmed newlines by shrinking the range by 1
377 - * character and seeing if the text property has changed. If it has
378 - * not changed then we know that IE has trimmed a \r\n from the end.
379 - */
380 - do {
381 - if ( !postFinished ) {
382 - if ( preRange.
383 - compareEndPoints( "StartToEnd", preRange ) == 0 ) {
384 - postFinished = true;
385 - } else {
386 - preRange.moveEnd( "character", -1 )
387 - if ( preRange.text == preText ) {
388 - rawPreText += "\r\n";
389 - } else {
390 - postFinished = true;
391 - }
392 - }
393 - }
394 - if ( !periFinished ) {
395 - if ( periRange.
396 - compareEndPoints( "StartToEnd", periRange ) == 0 ) {
397 - periFinished = true;
398 - } else {
399 - periRange.moveEnd( "character", -1 )
400 - if ( periRange.text == periText ) {
401 - rawPeriText += "\r\n";
402 - } else {
403 - periFinished = true;
404 - }
405 - }
406 - }
407 - if ( !postFinished ) {
408 - if ( postRange.
409 - compareEndPoints("StartToEnd", postRange) == 0 ) {
410 - postFinished = true;
411 - } else {
412 - postRange.moveEnd( "character", -1 )
413 - if ( postRange.text == postText ) {
414 - rawPostText += "\r\n";
415 - } else {
416 - postFinished = true;
417 - }
418 - }
419 - }
420 - } while ( ( !postFinished || !periFinished || !postFinished ) );
421 - caretPos = rawPreText.replace( /\r\n/g, "\n" ).length;
422 - } else if ( e.selectionStart || e.selectionStart == '0' ) {
423 - // Firefox support
424 - caretPos = e.selectionStart;
425 - }
426 - return caretPos;
427 - }
428 - return getCaret( this.get( 0 ) );
429 -},
430 -/**
431 - * Ported from Wikia's LinkSuggest extension
432 - * https://svn.wikia-code.com/wikia/trunk/extensions/wikia/LinkSuggest
433 - *
434 - * Scroll a textarea to a certain offset
435 - * @param pos Byte offset
436 - */
437 -scrollToCaretPosition: function( pos ) {
438 - function getLineLength( e ) {
439 - return Math.floor( e.scrollWidth / ( $.os.name == 'linux' ? 7 : 8 ) );
440 - }
441 - function getCaretScrollPosition( e ) {
442 - var text = e.value.replace( /\r/g, "" );
443 - var caret = $( e ).getCaretPosition();
444 - var lineLength = getLineLength( e );
445 - var row = 0;
446 - var charInLine = 0;
447 - var lastSpaceInLine = 0;
448 - for ( i = 0; i < caret; i++ ) {
449 - charInLine++;
450 - if ( text.charAt( i ) == " " ) {
451 - lastSpaceInLine = charInLine;
452 - } else if ( text.charAt( i ) == "\n" ) {
453 - lastSpaceInLine = 0;
454 - charInLine = 0;
455 - row++;
456 - }
457 - if ( charInLine > lineLength ) {
458 - if ( lastSpaceInLine > 0 ) {
459 - charInLine = charInLine - lastSpaceInLine;
460 - lastSpaceInLine = 0;
461 - row++;
462 - }
463 - }
464 - }
465 - var nextSpace = 0;
466 - for ( j = caret; j < caret + lineLength; j++ ) {
467 - if (
468 - text.charAt( j ) == " " ||
469 - text.charAt( j ) == "\n" ||
470 - caret == text.length
471 - ) {
472 - nextSpace = j;
473 - break;
474 - }
475 - }
476 - if( nextSpace > lineLength && caret <= lineLength ) {
477 - charInLine = caret - lastSpaceInLine;
478 - row++;
479 - }
480 - return (
481 - $.os.name == 'mac' ? 13 : ( $.os.name == 'linux' ? 15 : 16 )
482 - ) * row;
483 - }
484 - return this.each(function() {
485 - $(this).focus();
486 - if ( this.selectionStart || this.selectionStart == '0' ) {
487 - // Mozilla
488 - this.selectionStart = pos;
489 - this.selectionEnd = pos;
490 - $(this).scrollTop( getCaretScrollPosition( this ) );
491 - } else if ( document.selection && document.selection.createRange ) {
492 - // IE / Opera
493 - /*
494 - * IE automatically scrolls the section to the bottom of the page,
495 - * except if it's already in view and the cursor position hasn't
496 - * changed, in which case it does nothing. In that case we'll force
497 - * it to act by moving one character back and forth.
498 - */
499 - var range = document.selection.createRange();
500 - var oldPos = $(this).getCaretPosition();
501 - var goBack = false;
502 - if ( oldPos == pos ) {
503 - pos++;
504 - goBack = true;
505 - }
506 - range.moveToElementText( this );
507 - range.collapse();
508 - range.move( 'character', pos );
509 - range.select();
510 - this.scrollTop += range.offsetTop;
511 - if ( goBack ) {
512 - range.move( 'character', -1 );
513 - range.select();
514 - }
515 - }
516 - $(this).trigger( 'scrollToPosition' );
517 - });
518 -}
519 -
520 -} ); } )( jQuery );/**
521 - * This plugin provides a way to build a user interface around a textarea. You
522 - * can build the UI from a confguration..
523 - * $j( 'div#edittoolbar' ).wikiEditor(
524 - * { 'modules': { 'toolbar': { ... config ... } } }
525 - * );
526 - * ...and add modules after it's already been initialized...
527 - * $j( 'textarea#wpTextbox1' ).wikiEditor(
528 - * 'addModule', 'toc', { ... config ... }
529 - * );
530 - * ...using the API, which is still be finished.
531 - */
532 -(function($) {
533 -$.wikiEditor = { 'modules': {}, 'instances': [] };
534 -$.fn.wikiEditor = function() {
535 -
536 -/* Initialization */
537 -
538 -// The wikiEditor context is stored in the element, so when this function
539 -// gets called again we can pick up where we left off
540 -var context = $(this).data( 'context' );
541 -
542 -/* API */
543 -
544 -// The first time this is called, we expect context to be undefined, meaning
545 -// the editing ui has not yet been, and still needs to be built, however each
546 -// additional call after that is expected to be an API call, which contains a
547 -// string as the first argument which corrosponds to a supported api call
548 -if ( typeof context !== 'undefined' ) {
549 - // Since javascript gives arugments as an object, we need to convert them
550 - // so they can be used more easily
551 - arguments = $.makeArray( arguments );
552 - if ( arguments.length > 0 ) {
553 - // Handle API calls
554 - var call = arguments.shift();
555 - if ( call in context.api ) {
556 - context.api[call](
557 - context, arguments[0] == undefined ? {} : arguments[0]
558 - );
559 - }
560 - // Store the context for next time and return
561 - return $(this).data( 'context', context );
562 - }
563 - // Nothing to do, just return
564 - return $(this);
565 -}
566 -
567 -/* Construction */
568 -
569 -var instance = $.wikiEditor.instances.length;
570 -context = {
571 - '$textarea': $(this), 'modules': {}, 'data': {}, 'instance': instance
572 -};
573 -$.wikiEditor.instances[instance] = $(this);
574 -
575 -// Encapsulate the textarea with some containers for layout
576 -$(this)
577 - .wrap( $( '<div></div>' ).addClass( 'wikiEditor-ui' ) )
578 - .wrap( $( '<div></div>' ).addClass( 'wikiEditor-ui-bottom' ) )
579 - .wrap( $( '<div></div>' ).addClass( 'wikiEditor-ui-text' ) );
580 -// Get a refrence to the outter container
581 -context.$ui = $(this).parent().parent().parent();
582 -context.$ui.after( $( '<div style="clear:both;"></div>' ) );
583 -// Attach a container in the top
584 -context.$ui.prepend( $( '<div></div>' ).addClass( 'wikiEditor-ui-top' ) );
585 -// Create a set of standard methods for internal and external use
586 -context.api = {
587 - /**
588 - * Accepts either a string of the name of a module to add without any
589 - * additional configuration parameters, or an object with members keyed with
590 - * module names and valued with configuration objects
591 - */
592 - addModule: function( context, data ) {
593 - // A safe way of calling an API function on a module
594 - function callModuleApi( module, call, data ) {
595 - if (
596 - module in $.wikiEditor.modules &&
597 - 'fn' in $.wikiEditor.modules[module] &&
598 - call in $.wikiEditor.modules[module].fn
599 - ) {
600 - $.wikiEditor.modules[module].fn[call]( context, data );
601 - }
602 - }
603 - if ( typeof data == 'string' ) {
604 - callModuleApi( data, 'create', {} );
605 - } else if ( typeof data == 'object' ) {
606 - for ( module in data ) {
607 - if ( typeof module == 'string' ) {
608 - callModuleApi( module, 'create', data[module] );
609 - }
610 - }
611 - }
612 - }
613 -};
614 -// Allow modules to extend the API
615 -for ( module in $.wikiEditor.modules ) {
616 - if ( 'api' in $.wikiEditor.modules[module] ) {
617 - for ( call in $.wikiEditor.modules[module].api ) {
618 - // Modules may not overwrite existing API functions - first come,
619 - // first serve
620 - if ( !( call in context.api ) ) {
621 - context.api[call] = $.wikiEditor.modules[module].api[call];
622 - }
623 - }
624 - }
625 -}
626 -// Each browser seems to do this differently, so let's keep our editor
627 -// consistent by allways starting at the begining
628 -context.$textarea.scrollToCaretPosition( 0 );
629 -// If there was a configuration passed, it's assumed to be for the addModule
630 -// API call, so we can just send it on it's way right now
631 -if ( arguments.length > 0 && typeof arguments[0] == 'object' ) {
632 - context.api.addModule( context, arguments[0] );
633 -}
634 -// Store the context for next time, and support chaining
635 -return $(this).data( 'context', context );;
636 -
 2+/*
 3+ * jQuery Asynchronous Plugin 1.0
 4+ *
 5+ * Copyright (c) 2008 Vincent Robert (genezys.net)
 6+ * Dual licensed under the MIT (MIT-LICENSE.txt)
 7+ * and GPL (GPL-LICENSE.txt) licenses.
 8+ *
 9+ */
 10+(function($){
 11+
 12+// opts.delay : (default 10) delay between async call in ms
 13+// opts.bulk : (default 500) delay during which the loop can continue synchronously without yielding the CPU
 14+// opts.test : (default true) function to test in the while test part
 15+// opts.loop : (default empty) function to call in the while loop part
 16+// opts.end : (default empty) function to call at the end of the while loop
 17+$.whileAsync = function(opts)
 18+{
 19+ var delay = Math.abs(opts.delay) || 10,
 20+ bulk = isNaN(opts.bulk) ? 500 : Math.abs(opts.bulk),
 21+ test = opts.test || function(){ return true; },
 22+ loop = opts.loop || function(){},
 23+ end = opts.end || function(){};
 24+
 25+ (function(){
 26+
 27+ var t = false,
 28+ begin = new Date();
 29+
 30+ while( t = test() )
 31+ {
 32+ loop();
 33+ if( bulk === 0 || (new Date() - begin) > bulk )
 34+ {
 35+ break;
 36+ }
 37+ }
 38+ if( t )
 39+ {
 40+ setTimeout(arguments.callee, delay);
 41+ }
 42+ else
 43+ {
 44+ end();
 45+ }
 46+
 47+ })();
 48+}
 49+
 50+// opts.delay : (default 10) delay between async call in ms
 51+// opts.bulk : (default 500) delay during which the loop can continue synchronously without yielding the CPU
 52+// opts.loop : (default empty) function to call in the each loop part, signature: function(index, value) this = value
 53+// opts.end : (default empty) function to call at the end of the each loop
 54+$.eachAsync = function(array, opts)
 55+{
 56+ var i = 0,
 57+ l = array.length,
 58+ loop = opts.loop || function(){};
 59+
 60+ $.whileAsync(
 61+ $.extend(opts, {
 62+ test: function(){ return i < l; },
 63+ loop: function()
 64+ {
 65+ var val = array[i];
 66+ return loop.call(val, i++, val);
 67+ }
 68+ })
 69+ );
 70+}
 71+
 72+$.fn.eachAsync = function(opts)
 73+{
 74+ $.eachAsync(this, opts);
 75+ return this;
 76+}
 77+
 78+})(jQuery);
 79+
 80+/*
 81+
 82+jQuery Browser Plugin
 83+ * Version 2.3
 84+ * 2008-09-17 19:27:05
 85+ * URL: http://jquery.thewikies.com/browser
 86+ * Description: jQuery Browser Plugin extends browser detection capabilities and can assign browser selectors to CSS classes.
 87+ * Author: Nate Cavanaugh, Minhchau Dang, & Jonathan Neal
 88+ * Copyright: Copyright (c) 2008 Jonathan Neal under dual MIT/GPL license.
 89+ * JSLint: This javascript file passes JSLint verification.
 90+*//*jslint
 91+ bitwise: true,
 92+ browser: true,
 93+ eqeqeq: true,
 94+ forin: true,
 95+ nomen: true,
 96+ plusplus: true,
 97+ undef: true,
 98+ white: true
 99+*//*global
 100+ jQuery
 101+*/
 102+
 103+(function ($) {
 104+ $.browserTest = function (a, z) {
 105+ var u = 'unknown', x = 'X', m = function (r, h) {
 106+ for (var i = 0; i < h.length; i = i + 1) {
 107+ r = r.replace(h[i][0], h[i][1]);
 108+ }
 109+
 110+ return r;
 111+ }, c = function (i, a, b, c) {
 112+ var r = {
 113+ name: m((a.exec(i) || [u, u])[1], b)
 114+ };
 115+
 116+ r[r.name] = true;
 117+
 118+ r.version = (c.exec(i) || [x, x, x, x])[3];
 119+
 120+ if (r.name.match(/safari/) && r.version > 400) {
 121+ r.version = '2.0';
 122+ }
 123+
 124+ if (r.name === 'presto') {
 125+ r.version = ($.browser.version > 9.27) ? 'futhark' : 'linear_b';
 126+ }
 127+ r.versionNumber = parseFloat(r.version, 10) || 0;
 128+ r.versionX = (r.version !== x) ? (r.version + '').substr(0, 1) : x;
 129+ r.className = r.name + r.versionX;
 130+
 131+ return r;
 132+ };
 133+
 134+ a = (a.match(/Opera|Navigator|Minefield|KHTML|Chrome/) ? m(a, [
 135+ [/(Firefox|MSIE|KHTML,\slike\sGecko|Konqueror)/, ''],
 136+ ['Chrome Safari', 'Chrome'],
 137+ ['KHTML', 'Konqueror'],
 138+ ['Minefield', 'Firefox'],
 139+ ['Navigator', 'Netscape']
 140+ ]) : a).toLowerCase();
 141+
 142+ $.browser = $.extend((!z) ? $.browser : {}, c(a, /(camino|chrome|firefox|netscape|konqueror|lynx|msie|opera|safari)/, [], /(camino|chrome|firefox|netscape|netscape6|opera|version|konqueror|lynx|msie|safari)(\/|\s)([a-z0-9\.\+]*?)(\;|dev|rel|\s|$)/));
 143+
 144+ $.layout = c(a, /(gecko|konqueror|msie|opera|webkit)/, [
 145+ ['konqueror', 'khtml'],
 146+ ['msie', 'trident'],
 147+ ['opera', 'presto']
 148+ ], /(applewebkit|rv|konqueror|msie)(\:|\/|\s)([a-z0-9\.]*?)(\;|\)|\s)/);
 149+
 150+ $.os = {
 151+ name: (/(win|mac|linux|sunos|solaris|iphone)/.exec(navigator.platform.toLowerCase()) || [u])[0].replace('sunos', 'solaris')
 152+ };
 153+
 154+ if (!z) {
 155+ $('html').addClass([$.os.name, $.browser.name, $.browser.className, $.layout.name, $.layout.className].join(' '));
 156+ }
 157+ };
 158+
 159+ $.browserTest(navigator.userAgent);
 160+})(jQuery);
 161+
 162+/**
 163+ * Cookie plugin
 164+ *
 165+ * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
 166+ * Dual licensed under the MIT and GPL licenses:
 167+ * http://www.opensource.org/licenses/mit-license.php
 168+ * http://www.gnu.org/licenses/gpl.html
 169+ *
 170+ */
 171+
 172+/**
 173+ * Create a cookie with the given name and value and other optional parameters.
 174+ *
 175+ * @example $.cookie('the_cookie', 'the_value');
 176+ * @desc Set the value of a cookie.
 177+ * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
 178+ * @desc Create a cookie with all available options.
 179+ * @example $.cookie('the_cookie', 'the_value');
 180+ * @desc Create a session cookie.
 181+ * @example $.cookie('the_cookie', null);
 182+ * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
 183+ * used when the cookie was set.
 184+ *
 185+ * @param String name The name of the cookie.
 186+ * @param String value The value of the cookie.
 187+ * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
 188+ * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
 189+ * If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
 190+ * If set to null or omitted, the cookie will be a session cookie and will not be retained
 191+ * when the the browser exits.
 192+ * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
 193+ * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
 194+ * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
 195+ * require a secure protocol (like HTTPS).
 196+ * @type undefined
 197+ *
 198+ * @name $.cookie
 199+ * @cat Plugins/Cookie
 200+ * @author Klaus Hartl/klaus.hartl@stilbuero.de
 201+ */
 202+
 203+/**
 204+ * Get the value of a cookie with the given name.
 205+ *
 206+ * @example $.cookie('the_cookie');
 207+ * @desc Get the value of a cookie.
 208+ *
 209+ * @param String name The name of the cookie.
 210+ * @return The value of the cookie.
 211+ * @type String
 212+ *
 213+ * @name $.cookie
 214+ * @cat Plugins/Cookie
 215+ * @author Klaus Hartl/klaus.hartl@stilbuero.de
 216+ */
 217+jQuery.cookie = function(name, value, options) {
 218+ if (typeof value != 'undefined') { // name and value given, set cookie
 219+ options = options || {};
 220+ if (value === null) {
 221+ value = '';
 222+ options.expires = -1;
 223+ }
 224+ var expires = '';
 225+ if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
 226+ var date;
 227+ if (typeof options.expires == 'number') {
 228+ date = new Date();
 229+ date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
 230+ } else {
 231+ date = options.expires;
 232+ }
 233+ expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
 234+ }
 235+ // CAUTION: Needed to parenthesize options.path and options.domain
 236+ // in the following expressions, otherwise they evaluate to undefined
 237+ // in the packed version for some reason...
 238+ var path = options.path ? '; path=' + (options.path) : '';
 239+ var domain = options.domain ? '; domain=' + (options.domain) : '';
 240+ var secure = options.secure ? '; secure' : '';
 241+ document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
 242+ } else { // only name given, get cookie
 243+ var cookieValue = null;
 244+ if (document.cookie && document.cookie != '') {
 245+ var cookies = document.cookie.split(';');
 246+ for (var i = 0; i < cookies.length; i++) {
 247+ var cookie = jQuery.trim(cookies[i]);
 248+ // Does this cookie string begin with the name we want?
 249+ if (cookie.substring(0, name.length + 1) == (name + '=')) {
 250+ cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
 251+ break;
 252+ }
 253+ }
 254+ }
 255+ return cookieValue;
 256+ }
 257+};
 258+
 259+/**
 260+ * These plugins provide extra functionality for interaction with textareas.
 261+ */
 262+( function( $ ) { $.fn.extend( {
 263+/**
 264+ * Ported from skins/common/edit.js by Trevor Parscal
 265+ * (c) 2009 Wikimedia Foundation (GPLv2) - http://www.wikimedia.org
 266+ *
 267+ * Inserts text at the begining and end of a text selection, optionally
 268+ * inserting text at the caret when selection is empty.
 269+ *
 270+ * @param pre Text to insert before selection
 271+ * @param peri Text to insert at caret if selection is empty
 272+ * @param post Text to insert after selection
 273+ */
 274+encapsulateSelection: function( pre, peri, post ) {
 275+ /**
 276+ * Check if the selected text is the same as the insert text
 277+ */
 278+ function checkSelectedText() {
 279+ if ( !selText ) {
 280+ selText = peri;
 281+ isSample = true;
 282+ } else if ( selText.charAt( selText.length - 1 ) == ' ' ) {
 283+ // Exclude ending space char
 284+ selText = selText.substring(0, selText.length - 1);
 285+ post += ' '
 286+ }
 287+ }
 288+ var e = this.jquery ? this[0] : this;
 289+ var selText;
 290+ var isSample = false;
 291+ if ( document.selection && document.selection.createRange ) {
 292+ // IE/Opera
 293+ if ( document.documentElement && document.documentElement.scrollTop ) {
 294+ var winScroll = document.documentElement.scrollTop;
 295+ } else if ( document.body ) {
 296+ var winScroll = document.body.scrollTop;
 297+ }
 298+ $(this).focus();
 299+ var range = document.selection.createRange();
 300+ selText = range.text;
 301+ checkSelectedText();
 302+ range.text = pre + selText + post;
 303+ if ( isSample && range.moveStart ) {
 304+ if ( window.opera ) {
 305+ post = post.replace( /\n/g, '' );
 306+ }
 307+ range.moveStart( 'character', - post.length - selText.length );
 308+ range.moveEnd( 'character', - post.length );
 309+ }
 310+ range.select();
 311+ if ( document.documentElement && document.documentElement.scrollTop ) {
 312+ document.documentElement.scrollTop = winScroll
 313+ } else if ( document.body ) {
 314+ document.body.scrollTop = winScroll;
 315+ }
 316+ } else if ( e.selectionStart || e.selectionStart == '0' ) {
 317+ // Mozilla
 318+ var textScroll = e.scrollTop;
 319+ $(this).focus();
 320+ var startPos = e.selectionStart;
 321+ var endPos = e.selectionEnd;
 322+ selText = e.value.substring( startPos, endPos );
 323+ checkSelectedText();
 324+ e.value = e.value.substring( 0, startPos ) + pre + selText + post +
 325+ e.value.substring( endPos, e.value.length );
 326+ if ( isSample ) {
 327+ e.selectionStart = startPos + pre.length;
 328+ e.selectionEnd = startPos + pre.length + selText.length;
 329+ } else {
 330+ e.selectionStart =
 331+ startPos + pre.length + selText.length + post.length;
 332+ e.selectionEnd = e.selectionStart;
 333+ }
 334+ e.scrollTop = textScroll;
 335+ }
 336+ $(this).trigger( 'encapsulateSelection' );
 337+},
 338+/**
 339+ * Ported from Wikia's LinkSuggest extension
 340+ * https://svn.wikia-code.com/wikia/trunk/extensions/wikia/LinkSuggest
 341+ * Some code copied from
 342+ * http://www.dedestruct.com/2008/03/22/howto-cross-browser-cursor-position-in-textareas/
 343+ *
 344+ * Get the position (in resolution of bytes not nessecarily characters)
 345+ * in a textarea
 346+ */
 347+ getCaretPosition: function() {
 348+ function getCaret( e ) {
 349+ var caretPos = 0;
 350+ if($.browser.msie) {
 351+ // IE Support
 352+ var postFinished = false;
 353+ var periFinished = false;
 354+ var postFinished = false;
 355+ var preText, rawPreText, periText;
 356+ var rawPeriText, postText, rawPostText;
 357+ // Create range containing text in the selection
 358+ var periRange = document.selection.createRange().duplicate();
 359+ // Create range containing text before the selection
 360+ var preRange = document.body.createTextRange();
 361+ // Select all the text
 362+ preRange.moveToElementText(e);
 363+ // Move the end where we need it
 364+ preRange.setEndPoint("EndToStart", periRange);
 365+ // Create range containing text after the selection
 366+ var postRange = document.body.createTextRange();
 367+ // Select all the text
 368+ postRange.moveToElementText(e);
 369+ // Move the start where we need it
 370+ postRange.setEndPoint("StartToEnd", periRange);
 371+ // Load the text values we need to compare
 372+ preText = rawPreText = preRange.text;
 373+ periText = rawPeriText = periRange.text;
 374+ postText = rawPostText = postRange.text;
 375+ /*
 376+ * Check each range for trimmed newlines by shrinking the range by 1
 377+ * character and seeing if the text property has changed. If it has
 378+ * not changed then we know that IE has trimmed a \r\n from the end.
 379+ */
 380+ do {
 381+ if ( !postFinished ) {
 382+ if ( preRange.
 383+ compareEndPoints( "StartToEnd", preRange ) == 0 ) {
 384+ postFinished = true;
 385+ } else {
 386+ preRange.moveEnd( "character", -1 )
 387+ if ( preRange.text == preText ) {
 388+ rawPreText += "\r\n";
 389+ } else {
 390+ postFinished = true;
 391+ }
 392+ }
 393+ }
 394+ if ( !periFinished ) {
 395+ if ( periRange.
 396+ compareEndPoints( "StartToEnd", periRange ) == 0 ) {
 397+ periFinished = true;
 398+ } else {
 399+ periRange.moveEnd( "character", -1 )
 400+ if ( periRange.text == periText ) {
 401+ rawPeriText += "\r\n";
 402+ } else {
 403+ periFinished = true;
 404+ }
 405+ }
 406+ }
 407+ if ( !postFinished ) {
 408+ if ( postRange.
 409+ compareEndPoints("StartToEnd", postRange) == 0 ) {
 410+ postFinished = true;
 411+ } else {
 412+ postRange.moveEnd( "character", -1 )
 413+ if ( postRange.text == postText ) {
 414+ rawPostText += "\r\n";
 415+ } else {
 416+ postFinished = true;
 417+ }
 418+ }
 419+ }
 420+ } while ( ( !postFinished || !periFinished || !postFinished ) );
 421+ caretPos = rawPreText.replace( /\r\n/g, "\n" ).length;
 422+ } else if ( e.selectionStart || e.selectionStart == '0' ) {
 423+ // Firefox support
 424+ caretPos = e.selectionStart;
 425+ }
 426+ return caretPos;
 427+ }
 428+ return getCaret( this.get( 0 ) );
 429+},
 430+/**
 431+ * Ported from Wikia's LinkSuggest extension
 432+ * https://svn.wikia-code.com/wikia/trunk/extensions/wikia/LinkSuggest
 433+ *
 434+ * Scroll a textarea to a certain offset
 435+ * @param pos Byte offset
 436+ */
 437+scrollToCaretPosition: function( pos ) {
 438+ function getLineLength( e ) {
 439+ return Math.floor( e.scrollWidth / ( $.os.name == 'linux' ? 7 : 8 ) );
 440+ }
 441+ function getCaretScrollPosition( e ) {
 442+ var text = e.value.replace( /\r/g, "" );
 443+ var caret = $( e ).getCaretPosition();
 444+ var lineLength = getLineLength( e );
 445+ var row = 0;
 446+ var charInLine = 0;
 447+ var lastSpaceInLine = 0;
 448+ for ( i = 0; i < caret; i++ ) {
 449+ charInLine++;
 450+ if ( text.charAt( i ) == " " ) {
 451+ lastSpaceInLine = charInLine;
 452+ } else if ( text.charAt( i ) == "\n" ) {
 453+ lastSpaceInLine = 0;
 454+ charInLine = 0;
 455+ row++;
 456+ }
 457+ if ( charInLine > lineLength ) {
 458+ if ( lastSpaceInLine > 0 ) {
 459+ charInLine = charInLine - lastSpaceInLine;
 460+ lastSpaceInLine = 0;
 461+ row++;
 462+ }
 463+ }
 464+ }
 465+ var nextSpace = 0;
 466+ for ( j = caret; j < caret + lineLength; j++ ) {
 467+ if (
 468+ text.charAt( j ) == " " ||
 469+ text.charAt( j ) == "\n" ||
 470+ caret == text.length
 471+ ) {
 472+ nextSpace = j;
 473+ break;
 474+ }
 475+ }
 476+ if( nextSpace > lineLength && caret <= lineLength ) {
 477+ charInLine = caret - lastSpaceInLine;
 478+ row++;
 479+ }
 480+ return (
 481+ $.os.name == 'mac' ? 13 : ( $.os.name == 'linux' ? 15 : 16 )
 482+ ) * row;
 483+ }
 484+ return this.each(function() {
 485+ $(this).focus();
 486+ if ( this.selectionStart || this.selectionStart == '0' ) {
 487+ // Mozilla
 488+ this.selectionStart = pos;
 489+ this.selectionEnd = pos;
 490+ $(this).scrollTop( getCaretScrollPosition( this ) );
 491+ } else if ( document.selection && document.selection.createRange ) {
 492+ // IE / Opera
 493+ /*
 494+ * IE automatically scrolls the section to the bottom of the page,
 495+ * except if it's already in view and the cursor position hasn't
 496+ * changed, in which case it does nothing. In that case we'll force
 497+ * it to act by moving one character back and forth.
 498+ */
 499+ var range = document.selection.createRange();
 500+ var oldPos = $(this).getCaretPosition();
 501+ var goBack = false;
 502+ if ( oldPos == pos ) {
 503+ pos++;
 504+ goBack = true;
 505+ }
 506+ range.moveToElementText( this );
 507+ range.collapse();
 508+ range.move( 'character', pos );
 509+ range.select();
 510+ this.scrollTop += range.offsetTop;
 511+ if ( goBack ) {
 512+ range.move( 'character', -1 );
 513+ range.select();
 514+ }
 515+ }
 516+ $(this).trigger( 'scrollToPosition' );
 517+ });
 518+}
 519+
 520+} ); } )( jQuery );/**
 521+ * This plugin provides a way to build a user interface around a textarea. You
 522+ * can build the UI from a confguration..
 523+ * $j( 'div#edittoolbar' ).wikiEditor(
 524+ * { 'modules': { 'toolbar': { ... config ... } } }
 525+ * );
 526+ * ...and add modules after it's already been initialized...
 527+ * $j( 'textarea#wpTextbox1' ).wikiEditor(
 528+ * 'addModule', 'toc', { ... config ... }
 529+ * );
 530+ * ...using the API, which is still be finished.
 531+ */
 532+(function($) {
 533+$.wikiEditor = { 'modules': {}, 'instances': [] };
 534+$.fn.wikiEditor = function() {
 535+
 536+/* Initialization */
 537+
 538+// The wikiEditor context is stored in the element, so when this function
 539+// gets called again we can pick up where we left off
 540+var context = $(this).data( 'context' );
 541+
 542+/* API */
 543+
 544+// The first time this is called, we expect context to be undefined, meaning
 545+// the editing ui has not yet been, and still needs to be built, however each
 546+// additional call after that is expected to be an API call, which contains a
 547+// string as the first argument which corrosponds to a supported api call
 548+if ( typeof context !== 'undefined' ) {
 549+ // Since javascript gives arugments as an object, we need to convert them
 550+ // so they can be used more easily
 551+ arguments = $.makeArray( arguments );
 552+ if ( arguments.length > 0 ) {
 553+ // Handle API calls
 554+ var call = arguments.shift();
 555+ if ( call in context.api ) {
 556+ context.api[call](
 557+ context, arguments[0] == undefined ? {} : arguments[0]
 558+ );
 559+ }
 560+ // Store the context for next time and return
 561+ return $(this).data( 'context', context );
 562+ }
 563+ // Nothing to do, just return
 564+ return $(this);
 565+}
 566+
 567+/* Construction */
 568+
 569+var instance = $.wikiEditor.instances.length;
 570+context = {
 571+ '$textarea': $(this), 'modules': {}, 'data': {}, 'instance': instance
 572+};
 573+$.wikiEditor.instances[instance] = $(this);
 574+
 575+// Encapsulate the textarea with some containers for layout
 576+$(this)
 577+ .wrap( $( '<div></div>' ).addClass( 'wikiEditor-ui' ) )
 578+ .wrap( $( '<div></div>' ).addClass( 'wikiEditor-ui-bottom' ) )
 579+ .wrap( $( '<div></div>' ).addClass( 'wikiEditor-ui-text' ) );
 580+// Get a refrence to the outter container
 581+context.$ui = $(this).parent().parent().parent();
 582+context.$ui.after( $( '<div style="clear:both;"></div>' ) );
 583+// Attach a container in the top
 584+context.$ui.prepend( $( '<div></div>' ).addClass( 'wikiEditor-ui-top' ) );
 585+// Create a set of standard methods for internal and external use
 586+context.api = {
 587+ /**
 588+ * Accepts either a string of the name of a module to add without any
 589+ * additional configuration parameters, or an object with members keyed with
 590+ * module names and valued with configuration objects
 591+ */
 592+ addModule: function( context, data ) {
 593+ // A safe way of calling an API function on a module
 594+ function callModuleApi( module, call, data ) {
 595+ if (
 596+ module in $.wikiEditor.modules &&
 597+ 'fn' in $.wikiEditor.modules[module] &&
 598+ call in $.wikiEditor.modules[module].fn
 599+ ) {
 600+ $.wikiEditor.modules[module].fn[call]( context, data );
 601+ }
 602+ }
 603+ if ( typeof data == 'string' ) {
 604+ callModuleApi( data, 'create', {} );
 605+ } else if ( typeof data == 'object' ) {
 606+ for ( module in data ) {
 607+ if ( typeof module == 'string' ) {
 608+ callModuleApi( module, 'create', data[module] );
 609+ }
 610+ }
 611+ }
 612+ }
 613+};
 614+// Allow modules to extend the API
 615+for ( module in $.wikiEditor.modules ) {
 616+ if ( 'api' in $.wikiEditor.modules[module] ) {
 617+ for ( call in $.wikiEditor.modules[module].api ) {
 618+ // Modules may not overwrite existing API functions - first come,
 619+ // first serve
 620+ if ( !( call in context.api ) ) {
 621+ context.api[call] = $.wikiEditor.modules[module].api[call];
 622+ }
 623+ }
 624+ }
 625+}
 626+// Each browser seems to do this differently, so let's keep our editor
 627+// consistent by allways starting at the begining
 628+context.$textarea.scrollToCaretPosition( 0 );
 629+// If there was a configuration passed, it's assumed to be for the addModule
 630+// API call, so we can just send it on it's way right now
 631+if ( arguments.length > 0 && typeof arguments[0] == 'object' ) {
 632+ context.api.addModule( context, arguments[0] );
 633+}
 634+// Store the context for next time, and support chaining
 635+return $(this).data( 'context', context );;
 636+
637637 };})(jQuery);/**
638638 * TOC Module for wikiEditor
639639 */
@@ -1249,7 +1249,7 @@
12501250 )
12511251 );
12521252 } else {
1253 - sectionQueue[sectionQueue.length] = {
 1253+ s = {
12541254 'context': context,
12551255 '$sections': $sections,
12561256 '$tabs': $tabs,
@@ -1257,23 +1257,7 @@
12581258 'config': config[section],
12591259 'selected': ( selected == section )
12601260 };
1261 - }
1262 - }
1263 - $.eachAsync( sectionQueue, {
1264 - 'bulk': 0,
1265 - 'end': function() {
1266 - // HACK: Opera doesn't seem to want to redraw after these bits
1267 - // are added to the DOM, so we can just FORCE it!
1268 - $( 'body' ).css( 'position', 'static' );
1269 - $( 'body' ).css( 'position', 'relative' );
1270 - },
1271 - 'loop': function( i, s ) {
1272 - s.$sections.append(
1273 - $.wikiEditor.modules.toolbar.fn.buildSection(
1274 - s.context, s.section, s.config
1275 - )
1276 - .css( 'display', s.selected ? 'block' : 'none' )
1277 - );
 1261+ sectionQueue[sectionQueue.length] = s;
12781262 s.$tabs.append(
12791263 $( '<span></span>' )
12801264 .attr( {
@@ -1319,6 +1303,24 @@
13201304 )
13211305 );
13221306 }
 1307+ }
 1308+ $.eachAsync( sectionQueue, {
 1309+ 'bulk': 0,
 1310+ 'end': function() {
 1311+ // HACK: Opera doesn't seem to want to redraw after these bits
 1312+ // are added to the DOM, so we can just FORCE it!
 1313+ $( 'body' ).css( 'position', 'static' );
 1314+ $( 'body' ).css( 'position', 'relative' );
 1315+ },
 1316+ 'loop': function( i, s ) {
 1317+ s.$sections.append(
 1318+ $.wikiEditor.modules.toolbar.fn.buildSection(
 1319+ s.context, s.section, s.config
 1320+ )
 1321+ .css( 'display', s.selected ? 'block' : 'none' )
 1322+ );
 1323+
 1324+ }
13231325 } );
13241326 }
13251327 }
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.min.js
@@ -1,94 +1,94 @@
2 -
3 -(function($){$.whileAsync=function(opts)
4 -{var delay=Math.abs(opts.delay)||10,bulk=isNaN(opts.bulk)?500:Math.abs(opts.bulk),test=opts.test||function(){return true;},loop=opts.loop||function(){},end=opts.end||function(){};(function(){var t=false,begin=new Date();while(t=test())
5 -{loop();if(bulk===0||(new Date()-begin)>bulk)
6 -{break;}}
7 -if(t)
8 -{setTimeout(arguments.callee,delay);}
9 -else
10 -{end();}})();}
11 -$.eachAsync=function(array,opts)
12 -{var i=0,l=array.length,loop=opts.loop||function(){};$.whileAsync($.extend(opts,{test:function(){return i<l;},loop:function()
13 -{var val=array[i];return loop.call(val,i++,val);}}));}
14 -$.fn.eachAsync=function(opts)
15 -{$.eachAsync(this,opts);return this;}})(jQuery);(function($){$.browserTest=function(a,z){var u='unknown',x='X',m=function(r,h){for(var i=0;i<h.length;i=i+1){r=r.replace(h[i][0],h[i][1]);}
16 -return r;},c=function(i,a,b,c){var r={name:m((a.exec(i)||[u,u])[1],b)};r[r.name]=true;r.version=(c.exec(i)||[x,x,x,x])[3];if(r.name.match(/safari/)&&r.version>400){r.version='2.0';}
17 -if(r.name==='presto'){r.version=($.browser.version>9.27)?'futhark':'linear_b';}
18 -r.versionNumber=parseFloat(r.version,10)||0;r.versionX=(r.version!==x)?(r.version+'').substr(0,1):x;r.className=r.name+r.versionX;return r;};a=(a.match(/Opera|Navigator|Minefield|KHTML|Chrome/)?m(a,[[/(Firefox|MSIE|KHTML,\slike\sGecko|Konqueror)/,''],['Chrome Safari','Chrome'],['KHTML','Konqueror'],['Minefield','Firefox'],['Navigator','Netscape']]):a).toLowerCase();$.browser=$.extend((!z)?$.browser:{},c(a,/(camino|chrome|firefox|netscape|konqueror|lynx|msie|opera|safari)/,[],/(camino|chrome|firefox|netscape|netscape6|opera|version|konqueror|lynx|msie|safari)(\/|\s)([a-z0-9\.\+]*?)(\;|dev|rel|\s|$)/));$.layout=c(a,/(gecko|konqueror|msie|opera|webkit)/,[['konqueror','khtml'],['msie','trident'],['opera','presto']],/(applewebkit|rv|konqueror|msie)(\:|\/|\s)([a-z0-9\.]*?)(\;|\)|\s)/);$.os={name:(/(win|mac|linux|sunos|solaris|iphone)/.exec(navigator.platform.toLowerCase())||[u])[0].replace('sunos','solaris')};if(!z){$('html').addClass([$.os.name,$.browser.name,$.browser.className,$.layout.name,$.layout.className].join(' '));}};$.browserTest(navigator.userAgent);})(jQuery);jQuery.cookie=function(name,value,options){if(typeof value!='undefined'){options=options||{};if(value===null){value='';options.expires=-1;}
19 -var expires='';if(options.expires&&(typeof options.expires=='number'||options.expires.toUTCString)){var date;if(typeof options.expires=='number'){date=new Date();date.setTime(date.getTime()+(options.expires*24*60*60*1000));}else{date=options.expires;}
20 -expires='; expires='+date.toUTCString();}
21 -var path=options.path?'; path='+(options.path):'';var domain=options.domain?'; domain='+(options.domain):'';var secure=options.secure?'; secure':'';document.cookie=[name,'=',encodeURIComponent(value),expires,path,domain,secure].join('');}else{var cookieValue=null;if(document.cookie&&document.cookie!=''){var cookies=document.cookie.split(';');for(var i=0;i<cookies.length;i++){var cookie=jQuery.trim(cookies[i]);if(cookie.substring(0,name.length+1)==(name+'=')){cookieValue=decodeURIComponent(cookie.substring(name.length+1));break;}}}
22 -return cookieValue;}};(function($){$.fn.extend({encapsulateSelection:function(pre,peri,post){function checkSelectedText(){if(!selText){selText=peri;isSample=true;}else if(selText.charAt(selText.length-1)==' '){selText=selText.substring(0,selText.length-1);post+=' '}}
23 -var e=this.jquery?this[0]:this;var selText;var isSample=false;if(document.selection&&document.selection.createRange){if(document.documentElement&&document.documentElement.scrollTop){var winScroll=document.documentElement.scrollTop;}else if(document.body){var winScroll=document.body.scrollTop;}
24 -$(this).focus();var range=document.selection.createRange();selText=range.text;checkSelectedText();range.text=pre+selText+post;if(isSample&&range.moveStart){if(window.opera){post=post.replace(/\n/g,'');}
25 -range.moveStart('character',-post.length-selText.length);range.moveEnd('character',-post.length);}
26 -range.select();if(document.documentElement&&document.documentElement.scrollTop){document.documentElement.scrollTop=winScroll}else if(document.body){document.body.scrollTop=winScroll;}}else if(e.selectionStart||e.selectionStart=='0'){var textScroll=e.scrollTop;$(this).focus();var startPos=e.selectionStart;var endPos=e.selectionEnd;selText=e.value.substring(startPos,endPos);checkSelectedText();e.value=e.value.substring(0,startPos)+pre+selText+post+
27 -e.value.substring(endPos,e.value.length);if(isSample){e.selectionStart=startPos+pre.length;e.selectionEnd=startPos+pre.length+selText.length;}else{e.selectionStart=startPos+pre.length+selText.length+post.length;e.selectionEnd=e.selectionStart;}
28 -e.scrollTop=textScroll;}
29 -$(this).trigger('encapsulateSelection');},getCaretPosition:function(){function getCaret(e){var caretPos=0;if($.browser.msie){var postFinished=false;var periFinished=false;var postFinished=false;var preText,rawPreText,periText;var rawPeriText,postText,rawPostText;var periRange=document.selection.createRange().duplicate();var preRange=document.body.createTextRange();preRange.moveToElementText(e);preRange.setEndPoint("EndToStart",periRange);var postRange=document.body.createTextRange();postRange.moveToElementText(e);postRange.setEndPoint("StartToEnd",periRange);preText=rawPreText=preRange.text;periText=rawPeriText=periRange.text;postText=rawPostText=postRange.text;do{if(!postFinished){if(preRange.compareEndPoints("StartToEnd",preRange)==0){postFinished=true;}else{preRange.moveEnd("character",-1)
30 -if(preRange.text==preText){rawPreText+="\r\n";}else{postFinished=true;}}}
31 -if(!periFinished){if(periRange.compareEndPoints("StartToEnd",periRange)==0){periFinished=true;}else{periRange.moveEnd("character",-1)
32 -if(periRange.text==periText){rawPeriText+="\r\n";}else{periFinished=true;}}}
33 -if(!postFinished){if(postRange.compareEndPoints("StartToEnd",postRange)==0){postFinished=true;}else{postRange.moveEnd("character",-1)
34 -if(postRange.text==postText){rawPostText+="\r\n";}else{postFinished=true;}}}}while((!postFinished||!periFinished||!postFinished));caretPos=rawPreText.replace(/\r\n/g,"\n").length;}else if(e.selectionStart||e.selectionStart=='0'){caretPos=e.selectionStart;}
35 -return caretPos;}
36 -return getCaret(this.get(0));},scrollToCaretPosition:function(pos){function getLineLength(e){return Math.floor(e.scrollWidth/($.os.name=='linux'?7:8));}
37 -function getCaretScrollPosition(e){var text=e.value.replace(/\r/g,"");var caret=$(e).getCaretPosition();var lineLength=getLineLength(e);var row=0;var charInLine=0;var lastSpaceInLine=0;for(i=0;i<caret;i++){charInLine++;if(text.charAt(i)==" "){lastSpaceInLine=charInLine;}else if(text.charAt(i)=="\n"){lastSpaceInLine=0;charInLine=0;row++;}
38 -if(charInLine>lineLength){if(lastSpaceInLine>0){charInLine=charInLine-lastSpaceInLine;lastSpaceInLine=0;row++;}}}
39 -var nextSpace=0;for(j=caret;j<caret+lineLength;j++){if(text.charAt(j)==" "||text.charAt(j)=="\n"||caret==text.length){nextSpace=j;break;}}
40 -if(nextSpace>lineLength&&caret<=lineLength){charInLine=caret-lastSpaceInLine;row++;}
41 -return($.os.name=='mac'?13:($.os.name=='linux'?15:16))*row;}
42 -return this.each(function(){$(this).focus();if(this.selectionStart||this.selectionStart=='0'){this.selectionStart=pos;this.selectionEnd=pos;$(this).scrollTop(getCaretScrollPosition(this));}else if(document.selection&&document.selection.createRange){var range=document.selection.createRange();var oldPos=$(this).getCaretPosition();var goBack=false;if(oldPos==pos){pos++;goBack=true;}
43 -range.moveToElementText(this);range.collapse();range.move('character',pos);range.select();this.scrollTop+=range.offsetTop;if(goBack){range.move('character',-1);range.select();}}
44 -$(this).trigger('scrollToPosition');});}});})(jQuery);(function($){$.wikiEditor={'modules':{},'instances':[]};$.fn.wikiEditor=function(){var context=$(this).data('context');if(typeof context!=='undefined'){arguments=$.makeArray(arguments);if(arguments.length>0){var call=arguments.shift();if(call in context.api){context.api[call](context,arguments[0]==undefined?{}:arguments[0]);}
45 -return $(this).data('context',context);}
46 -return $(this);}
47 -var instance=$.wikiEditor.instances.length;context={'$textarea':$(this),'modules':{},'data':{},'instance':instance};$.wikiEditor.instances[instance]=$(this);$(this).wrap($('<div></div>').addClass('wikiEditor-ui')).wrap($('<div></div>').addClass('wikiEditor-ui-bottom')).wrap($('<div></div>').addClass('wikiEditor-ui-text'));context.$ui=$(this).parent().parent().parent();context.$ui.after($('<div style="clear:both;"></div>'));context.$ui.prepend($('<div></div>').addClass('wikiEditor-ui-top'));context.api={addModule:function(context,data){function callModuleApi(module,call,data){if(module in $.wikiEditor.modules&&'fn'in $.wikiEditor.modules[module]&&call in $.wikiEditor.modules[module].fn){$.wikiEditor.modules[module].fn[call](context,data);}}
48 -if(typeof data=='string'){callModuleApi(data,'create',{});}else if(typeof data=='object'){for(module in data){if(typeof module=='string'){callModuleApi(module,'create',data[module]);}}}}};for(module in $.wikiEditor.modules){if('api'in $.wikiEditor.modules[module]){for(call in $.wikiEditor.modules[module].api){if(!(call in context.api)){context.api[call]=$.wikiEditor.modules[module].api[call];}}}}
49 -context.$textarea.scrollToCaretPosition(0);if(arguments.length>0&&typeof arguments[0]=='object'){context.api.addModule(context,arguments[0]);}
50 -return $(this).data('context',context);;};})(jQuery);(function($){$.wikiEditor.modules.toc={api:{},fn:{create:function(context,config){if('$toc'in context.modules){return;}
51 -context.modules.$toc=$('<div></div>').addClass('wikiEditor-ui-toc');$.wikiEditor.modules.toc.fn.build(context,config);context.$ui.find('.wikiEditor-ui-bottom').append(context.modules.$toc);context.modules.$toc.height(context.$ui.find('.wikiEditor-ui-bottom').height());context.modules.$toc.css('width','12em');context.$ui.find('.wikiEditor-ui-text').css(($('body.rtl').size()?'marginLeft':'marginRight'),'12em');$.wikiEditor.modules.toc.fn.build(context);$.wikiEditor.modules.toc.fn.update(context);context.$textarea.bind('keyup encapsulateSelection',function(event){var context=$(this).data('context');$(this).eachAsync({bulk:0,loop:function(){$.wikiEditor.modules.toc.fn.build(context);$.wikiEditor.modules.toc.fn.update(context);}});}).bind('mouseup scrollToPosition',function(event){var context=$(this).data('context');$(this).eachAsync({bulk:0,loop:function(){$.wikiEditor.modules.toc.fn.update(context);}});});},update:function(context){context.modules.$toc.find('a').removeClass('currentSelection');var position=context.$textarea.getCaretPosition();var section=0;if(context.data.outline.length>0){if(!(position<context.data.outline[0].position-1)){while(section<context.data.outline.length&&context.data.outline[section].position-1<position){section++;}
52 -section=Math.max(0,section);}
53 -context.modules.$toc.find('a.section-'+section).addClass('currentSelection');}},build:function(context){function buildStructure(outline,offset,level){if(offset==undefined)offset=0;if(level==undefined)level=1;var sections=[];for(var i=offset;i<outline.length;i++){if(outline[i].nLevel==level){var sub=buildStructure(outline,i+1,level+1);if(sub.length){outline[i].sections=sub;}
54 -sections[sections.length]=outline[i];}else if(outline[i].nLevel<level){break;}}
55 -return sections;}
56 -function buildList(structure){var list=$('<ul></ul>');for(i in structure){var item=$('<li></li>').append($('<a></a>').attr('href','#').addClass('section-'+structure[i].index).data('textbox',context.$textarea).data('position',structure[i].position).click(function(event){$(this).data('textbox').scrollToCaretPosition($(this).data('position'));event.preventDefault();}).text(structure[i].text));if(structure[i].sections!==undefined){item.append(buildList(structure[i].sections));}
57 -list.append(item);}
58 -return list;}
59 -var outline=[];var wikitext='\n'+context.$textarea.val()+'\n';var headings=wikitext.match(/\n={1,5}.*={1,5}(?=\n)/g);var offset=0;headings=$.makeArray(headings);for(var h=0;h<headings.length;h++){text=headings[h];var position=wikitext.indexOf(text,offset);if(position>offset){offset=position;}else if(position==-1){continue;}
60 -text=$.trim(text);var startLevel=0;for(var c=0;c<text.length;c++){if(text.charAt(c)=='='){startLevel++;}else{break;}}
61 -var endLevel=0;for(var c=text.length-1;c>=0;c--){if(text.charAt(c)=='='){endLevel++;}else{break;}}
62 -var level=Math.min(startLevel,endLevel);text=$.trim(text.substr(level,text.length-(level*2)));outline[h]={'text':text,'position':position,'level':level,'index':h+1};}
63 -var lastLevel=0;var nLevel=0;for(var i=0;i<outline.length;i++){if(outline[i].level>lastLevel){nLevel++;}
64 -else if(outline[i].level<lastLevel){nLevel-=Math.max(1,lastLevel-outline[i].level);}
65 -outline[i].nLevel=nLevel;lastLevel=nLevel;}
66 -var structure=buildStructure(outline);structure.unshift({'text':wgTitle,'level':1,'index':0,'position':0});context.modules.$toc.html(buildList(structure));context.data.outline=outline;}}};})(jQuery);(function($){$.wikiEditor.modules.toolbar={imgPath:wgScriptPath+'/extensions/UsabilityInitiative/images/wikiEditor/toolbar/',api:{addToToolbar:function(context,data){},modifyToolbar:function(context,data){},removeFromToolbar:function(context,data){if(typeof data.section=='string'){var selector='div[rel='+data.section+'].section';if(typeof data.group=='string'){selector+=' div[rel='+data.group+'].group';if(typeof data.tool=='string'){selector+=' div[rel='+data.tool+'].tool';}}
67 -context.modules.$toolbar.find(selector).remove();}}},fn:{autoMsg:function(object,property){if(property in object){return object[property];}else if(property+'Msg'in object){return gM(object[property+'Msg']);}else{return'';}},create:function(context,config){if('$toolbar'in context.modules){return;}
68 -context.modules.$toolbar=$('<div></div>').addClass('wikiEditor-ui-toolbar');$.wikiEditor.modules.toolbar.fn.build(context,config);context.$ui.find('.wikiEditor-ui-top').append(context.modules.$toolbar);},doAction:function(context,action){switch(action.type){case'encapsulate':var parts={'pre':'','peri':'','post':''};for(part in parts){if(part+'Msg'in action.options){parts[part]=gM(action.options[part+'Msg'],(action.options[part]||null));}else{parts[part]=(action.options[part]||'')}}
69 -context.$textarea.encapsulateSelection(parts.pre,parts.peri,parts.post);break;default:break;}},buildSection:function(context,id,section){switch(section.type){case'toolbar':return $.wikiEditor.modules.toolbar.fn.buildToolbar(context,id,section);case'booklet':return $.wikiEditor.modules.toolbar.fn.buildBooklet(context,id,section);default:return null;}},buildToolbar:function(context,id,toolbar){var $toolbar=$('<div></div>').attr({'class':'toolbar section section-'+id,'rel':id});if('groups'in toolbar){for(group in toolbar.groups){$toolbar.append($.wikiEditor.modules.toolbar.fn.buildGroup(context,group,toolbar.groups[group]));}}
70 -return $toolbar;},buildGroup:function(context,id,group){var $group=$('<div></div>').attr({'class':'group group-'+id,'rel':id});var label=$.wikiEditor.modules.toolbar.fn.autoMsg(group,'label');if(label){$group.append($('<div></div>').text(label).addClass('label'))}
71 -if('tools'in group){for(tool in group.tools){$group.append($.wikiEditor.modules.toolbar.fn.buildTool(context,tool,group.tools[tool]));}}
72 -return $group;},buildTool:function(context,id,tool){if('filters'in tool){for(filter in tool.filters){if($(tool.filters[filter]).size()==0){return null;}}}
73 -var label=$.wikiEditor.modules.toolbar.fn.autoMsg(tool,'label');switch(tool.type){case'button':$button=$('<img />').attr({'src':$.wikiEditor.modules.toolbar.imgPath+tool.icon,'alt':label,'title':label,'rel':id,'class':'tool tool-'+id});if('action'in tool){$button.data('action',tool.action).data('context',context).click(function(){$.wikiEditor.modules.toolbar.fn.doAction($(this).data('context'),$(this).data('action'));return false;});}
74 -return $button;case'select':var $select=$('<select></select>').attr({'rel':id,'class':'tool tool-'+id});$select.append($('<option></option>').text(label))
75 -if('list'in tool){$select.data('list',tool.list).data('context',context).click(function(){var list=$(this).data('list');var val=$(this).val();if(val in list&&'action'in list[val]){$.wikiEditor.modules.toolbar.fn.doAction($(this).data('context'),list[val].action);}
76 -$(this).find(":selected").attr('selected',false).find(":first").attr('selected',true);return false;});for(option in tool.list){var optionLabel=$.wikiEditor.modules.toolbar.fn.autoMsg(tool.list[option],'label');$select.append($('<option></option>').text(optionLabel).attr('value',option));}}
77 -return $select;default:return null;}},buildBooklet:function(context,id,booklet){var selected=$.cookie('wikiEditor-'+context.instance+'-booklet-'+id+'-page');var $booklet=$('<div></div>').attr({'class':'booklet section section-'+id,'rel':id});var $pages=$('<div></div>').attr('class','pages');var $index=$('<div></div>').attr('class','index');if('pages'in booklet){if(!(selected in booklet.pages)){selected=null;}
78 -for(page in booklet.pages){if(selected===null){selected=page;}
79 -var $page=$.wikiEditor.modules.toolbar.fn.buildPage(context,page,booklet.pages[page]);var $bookmark=$.wikiEditor.modules.toolbar.fn.buildBookmark(context,page,booklet.pages[page]);if(selected==page){$page.show();$bookmark.addClass('current');}else{$page.hide();}
80 -$pages.append($page);$index.append($bookmark);}}
81 -return $booklet.append($index).append($pages);},buildBookmark:function(context,id,page){var label=$.wikiEditor.modules.toolbar.fn.autoMsg(page,'label');return $('<div></div>').text(label).attr('rel',id).data('context',context).click(function(){$(this).parent().parent().find('.page').hide();$(this).parent().parent().find('.page-'+$(this).attr('rel')).show();$(this).siblings().removeClass('current');$(this).addClass('current');var section=$(this).parent().parent().attr('rel');$.cookie('wikiEditor-'+$(this).data('context').instance+'-booklet-'+section+'-page',$(this).attr('rel'));});},buildPage:function(context,id,page){var $page=$('<div></div>').attr({'class':'page page-'+id,'rel':id});switch(page.layout){case'table':$page.addClass('page-table');var $table=$('<table></table>').attr({'cellpadding':'0','cellspacing':'0','border':'0','width':'100%','class':'table table-'+id});if('headings'in page){var $headings=$('<tr></tr>');for(heading in page.headings){var content=$.wikiEditor.modules.toolbar.fn.autoMsg(page.headings[heading],'content');$headings.append($('<th></th>').text(content));}
82 -$table.append($headings);}
83 -if('rows'in page){for(row in page.rows){var $row=$('<tr></tr>');for(cell in page.rows[row]){var $cell=$('<td></td>').attr({'class':'cell cell-'+cell,'valign':'top'});var content=$.wikiEditor.modules.toolbar.fn.autoMsg(page.rows[row][cell],'content');$cell.append($('<span></span>').html(content));$row.append($cell);}
84 -$table.append($row);}}
85 -$page.append($table);break;case'characters':$page.addClass('page-characters');$characters=$('<div></div>');if('language'in page){$characters.attr('lang',page.language);}
86 -if('direction'in page){$characters.attr('dir',page.direction);}
87 -if('characters'in page){for(character in page.characters){var tool=page.characters[character];if(typeof tool=='string'){tool={'label':tool,'action':{'type':'encapsulate','options':{'pre':tool}}};}
88 -if('action'in tool&&'label'in tool){var $character=$('<a></a>').attr('href','#').text(tool.label).data('context',context).data('action',tool.action).click(function(){$.wikiEditor.modules.toolbar.fn.doAction($(this).data('context'),$(this).data('action'));return false;});$characters.append($character);}}
89 -$page.append($characters);}
90 -break;}
91 -return $page;},build:function(context,config){var $tabs=$('<div></div>').addClass('tabs').appendTo(context.modules.$toolbar);var $sections=$('<div></div>').addClass('sections').appendTo(context.modules.$toolbar);context.modules.$toolbar.append($('<div></div>').addClass('break'));var selected=$.cookie('wikiEditor-'+context.instance+'-toolbar-section');var sectionQueue=[];for(section in config){if(section=='main'){context.modules.$toolbar.prepend($.wikiEditor.modules.toolbar.fn.buildSection(context,section,config[section]));}else{sectionQueue[sectionQueue.length]={'context':context,'$sections':$sections,'$tabs':$tabs,'section':section,'config':config[section],'selected':(selected==section)};}}
92 -$.eachAsync(sectionQueue,{'bulk':0,'end':function(){$('body').css('position','static');$('body').css('position','relative');},'loop':function(i,s){s.$sections.append($.wikiEditor.modules.toolbar.fn.buildSection(s.context,s.section,s.config).css('display',s.selected?'block':'none'));s.$tabs.append($('<span></span>').attr({'class':'tab tab-'+s.section,'rel':s.section}).append($('<a></a>').addClass(s.selected?'current':null).attr('href','#').text($.wikiEditor.modules.toolbar.fn.autoMsg(s.config,'label')).data('context',s.context).click(function(){var $section=$(this).data('context').$ui.find('.section-'+
93 -$(this).parent().attr('rel'));$(this).blur();var show=$section.css('display')=='none';$section.parent().children().hide();$(this).parent().parent().find('a').removeClass('current');if(show){$section.show();$(this).addClass('current');}
94 -$.cookie('wikiEditor-'+
95 -$(this).data('context').instance+'-toolbar-section',show?$section.attr('rel'):null);return false;})));}});}}};})(jQuery);
\ No newline at end of file
 2+
 3+(function($){$.whileAsync=function(opts)
 4+{var delay=Math.abs(opts.delay)||10,bulk=isNaN(opts.bulk)?500:Math.abs(opts.bulk),test=opts.test||function(){return true;},loop=opts.loop||function(){},end=opts.end||function(){};(function(){var t=false,begin=new Date();while(t=test())
 5+{loop();if(bulk===0||(new Date()-begin)>bulk)
 6+{break;}}
 7+if(t)
 8+{setTimeout(arguments.callee,delay);}
 9+else
 10+{end();}})();}
 11+$.eachAsync=function(array,opts)
 12+{var i=0,l=array.length,loop=opts.loop||function(){};$.whileAsync($.extend(opts,{test:function(){return i<l;},loop:function()
 13+{var val=array[i];return loop.call(val,i++,val);}}));}
 14+$.fn.eachAsync=function(opts)
 15+{$.eachAsync(this,opts);return this;}})(jQuery);(function($){$.browserTest=function(a,z){var u='unknown',x='X',m=function(r,h){for(var i=0;i<h.length;i=i+1){r=r.replace(h[i][0],h[i][1]);}
 16+return r;},c=function(i,a,b,c){var r={name:m((a.exec(i)||[u,u])[1],b)};r[r.name]=true;r.version=(c.exec(i)||[x,x,x,x])[3];if(r.name.match(/safari/)&&r.version>400){r.version='2.0';}
 17+if(r.name==='presto'){r.version=($.browser.version>9.27)?'futhark':'linear_b';}
 18+r.versionNumber=parseFloat(r.version,10)||0;r.versionX=(r.version!==x)?(r.version+'').substr(0,1):x;r.className=r.name+r.versionX;return r;};a=(a.match(/Opera|Navigator|Minefield|KHTML|Chrome/)?m(a,[[/(Firefox|MSIE|KHTML,\slike\sGecko|Konqueror)/,''],['Chrome Safari','Chrome'],['KHTML','Konqueror'],['Minefield','Firefox'],['Navigator','Netscape']]):a).toLowerCase();$.browser=$.extend((!z)?$.browser:{},c(a,/(camino|chrome|firefox|netscape|konqueror|lynx|msie|opera|safari)/,[],/(camino|chrome|firefox|netscape|netscape6|opera|version|konqueror|lynx|msie|safari)(\/|\s)([a-z0-9\.\+]*?)(\;|dev|rel|\s|$)/));$.layout=c(a,/(gecko|konqueror|msie|opera|webkit)/,[['konqueror','khtml'],['msie','trident'],['opera','presto']],/(applewebkit|rv|konqueror|msie)(\:|\/|\s)([a-z0-9\.]*?)(\;|\)|\s)/);$.os={name:(/(win|mac|linux|sunos|solaris|iphone)/.exec(navigator.platform.toLowerCase())||[u])[0].replace('sunos','solaris')};if(!z){$('html').addClass([$.os.name,$.browser.name,$.browser.className,$.layout.name,$.layout.className].join(' '));}};$.browserTest(navigator.userAgent);})(jQuery);jQuery.cookie=function(name,value,options){if(typeof value!='undefined'){options=options||{};if(value===null){value='';options.expires=-1;}
 19+var expires='';if(options.expires&&(typeof options.expires=='number'||options.expires.toUTCString)){var date;if(typeof options.expires=='number'){date=new Date();date.setTime(date.getTime()+(options.expires*24*60*60*1000));}else{date=options.expires;}
 20+expires='; expires='+date.toUTCString();}
 21+var path=options.path?'; path='+(options.path):'';var domain=options.domain?'; domain='+(options.domain):'';var secure=options.secure?'; secure':'';document.cookie=[name,'=',encodeURIComponent(value),expires,path,domain,secure].join('');}else{var cookieValue=null;if(document.cookie&&document.cookie!=''){var cookies=document.cookie.split(';');for(var i=0;i<cookies.length;i++){var cookie=jQuery.trim(cookies[i]);if(cookie.substring(0,name.length+1)==(name+'=')){cookieValue=decodeURIComponent(cookie.substring(name.length+1));break;}}}
 22+return cookieValue;}};(function($){$.fn.extend({encapsulateSelection:function(pre,peri,post){function checkSelectedText(){if(!selText){selText=peri;isSample=true;}else if(selText.charAt(selText.length-1)==' '){selText=selText.substring(0,selText.length-1);post+=' '}}
 23+var e=this.jquery?this[0]:this;var selText;var isSample=false;if(document.selection&&document.selection.createRange){if(document.documentElement&&document.documentElement.scrollTop){var winScroll=document.documentElement.scrollTop;}else if(document.body){var winScroll=document.body.scrollTop;}
 24+$(this).focus();var range=document.selection.createRange();selText=range.text;checkSelectedText();range.text=pre+selText+post;if(isSample&&range.moveStart){if(window.opera){post=post.replace(/\n/g,'');}
 25+range.moveStart('character',-post.length-selText.length);range.moveEnd('character',-post.length);}
 26+range.select();if(document.documentElement&&document.documentElement.scrollTop){document.documentElement.scrollTop=winScroll}else if(document.body){document.body.scrollTop=winScroll;}}else if(e.selectionStart||e.selectionStart=='0'){var textScroll=e.scrollTop;$(this).focus();var startPos=e.selectionStart;var endPos=e.selectionEnd;selText=e.value.substring(startPos,endPos);checkSelectedText();e.value=e.value.substring(0,startPos)+pre+selText+post+
 27+e.value.substring(endPos,e.value.length);if(isSample){e.selectionStart=startPos+pre.length;e.selectionEnd=startPos+pre.length+selText.length;}else{e.selectionStart=startPos+pre.length+selText.length+post.length;e.selectionEnd=e.selectionStart;}
 28+e.scrollTop=textScroll;}
 29+$(this).trigger('encapsulateSelection');},getCaretPosition:function(){function getCaret(e){var caretPos=0;if($.browser.msie){var postFinished=false;var periFinished=false;var postFinished=false;var preText,rawPreText,periText;var rawPeriText,postText,rawPostText;var periRange=document.selection.createRange().duplicate();var preRange=document.body.createTextRange();preRange.moveToElementText(e);preRange.setEndPoint("EndToStart",periRange);var postRange=document.body.createTextRange();postRange.moveToElementText(e);postRange.setEndPoint("StartToEnd",periRange);preText=rawPreText=preRange.text;periText=rawPeriText=periRange.text;postText=rawPostText=postRange.text;do{if(!postFinished){if(preRange.compareEndPoints("StartToEnd",preRange)==0){postFinished=true;}else{preRange.moveEnd("character",-1)
 30+if(preRange.text==preText){rawPreText+="\r\n";}else{postFinished=true;}}}
 31+if(!periFinished){if(periRange.compareEndPoints("StartToEnd",periRange)==0){periFinished=true;}else{periRange.moveEnd("character",-1)
 32+if(periRange.text==periText){rawPeriText+="\r\n";}else{periFinished=true;}}}
 33+if(!postFinished){if(postRange.compareEndPoints("StartToEnd",postRange)==0){postFinished=true;}else{postRange.moveEnd("character",-1)
 34+if(postRange.text==postText){rawPostText+="\r\n";}else{postFinished=true;}}}}while((!postFinished||!periFinished||!postFinished));caretPos=rawPreText.replace(/\r\n/g,"\n").length;}else if(e.selectionStart||e.selectionStart=='0'){caretPos=e.selectionStart;}
 35+return caretPos;}
 36+return getCaret(this.get(0));},scrollToCaretPosition:function(pos){function getLineLength(e){return Math.floor(e.scrollWidth/($.os.name=='linux'?7:8));}
 37+function getCaretScrollPosition(e){var text=e.value.replace(/\r/g,"");var caret=$(e).getCaretPosition();var lineLength=getLineLength(e);var row=0;var charInLine=0;var lastSpaceInLine=0;for(i=0;i<caret;i++){charInLine++;if(text.charAt(i)==" "){lastSpaceInLine=charInLine;}else if(text.charAt(i)=="\n"){lastSpaceInLine=0;charInLine=0;row++;}
 38+if(charInLine>lineLength){if(lastSpaceInLine>0){charInLine=charInLine-lastSpaceInLine;lastSpaceInLine=0;row++;}}}
 39+var nextSpace=0;for(j=caret;j<caret+lineLength;j++){if(text.charAt(j)==" "||text.charAt(j)=="\n"||caret==text.length){nextSpace=j;break;}}
 40+if(nextSpace>lineLength&&caret<=lineLength){charInLine=caret-lastSpaceInLine;row++;}
 41+return($.os.name=='mac'?13:($.os.name=='linux'?15:16))*row;}
 42+return this.each(function(){$(this).focus();if(this.selectionStart||this.selectionStart=='0'){this.selectionStart=pos;this.selectionEnd=pos;$(this).scrollTop(getCaretScrollPosition(this));}else if(document.selection&&document.selection.createRange){var range=document.selection.createRange();var oldPos=$(this).getCaretPosition();var goBack=false;if(oldPos==pos){pos++;goBack=true;}
 43+range.moveToElementText(this);range.collapse();range.move('character',pos);range.select();this.scrollTop+=range.offsetTop;if(goBack){range.move('character',-1);range.select();}}
 44+$(this).trigger('scrollToPosition');});}});})(jQuery);(function($){$.wikiEditor={'modules':{},'instances':[]};$.fn.wikiEditor=function(){var context=$(this).data('context');if(typeof context!=='undefined'){arguments=$.makeArray(arguments);if(arguments.length>0){var call=arguments.shift();if(call in context.api){context.api[call](context,arguments[0]==undefined?{}:arguments[0]);}
 45+return $(this).data('context',context);}
 46+return $(this);}
 47+var instance=$.wikiEditor.instances.length;context={'$textarea':$(this),'modules':{},'data':{},'instance':instance};$.wikiEditor.instances[instance]=$(this);$(this).wrap($('<div></div>').addClass('wikiEditor-ui')).wrap($('<div></div>').addClass('wikiEditor-ui-bottom')).wrap($('<div></div>').addClass('wikiEditor-ui-text'));context.$ui=$(this).parent().parent().parent();context.$ui.after($('<div style="clear:both;"></div>'));context.$ui.prepend($('<div></div>').addClass('wikiEditor-ui-top'));context.api={addModule:function(context,data){function callModuleApi(module,call,data){if(module in $.wikiEditor.modules&&'fn'in $.wikiEditor.modules[module]&&call in $.wikiEditor.modules[module].fn){$.wikiEditor.modules[module].fn[call](context,data);}}
 48+if(typeof data=='string'){callModuleApi(data,'create',{});}else if(typeof data=='object'){for(module in data){if(typeof module=='string'){callModuleApi(module,'create',data[module]);}}}}};for(module in $.wikiEditor.modules){if('api'in $.wikiEditor.modules[module]){for(call in $.wikiEditor.modules[module].api){if(!(call in context.api)){context.api[call]=$.wikiEditor.modules[module].api[call];}}}}
 49+context.$textarea.scrollToCaretPosition(0);if(arguments.length>0&&typeof arguments[0]=='object'){context.api.addModule(context,arguments[0]);}
 50+return $(this).data('context',context);;};})(jQuery);(function($){$.wikiEditor.modules.toc={api:{},fn:{create:function(context,config){if('$toc'in context.modules){return;}
 51+context.modules.$toc=$('<div></div>').addClass('wikiEditor-ui-toc');$.wikiEditor.modules.toc.fn.build(context,config);context.$ui.find('.wikiEditor-ui-bottom').append(context.modules.$toc);context.modules.$toc.height(context.$ui.find('.wikiEditor-ui-bottom').height());context.modules.$toc.css('width','12em');context.$ui.find('.wikiEditor-ui-text').css(($('body.rtl').size()?'marginLeft':'marginRight'),'12em');$.wikiEditor.modules.toc.fn.build(context);$.wikiEditor.modules.toc.fn.update(context);context.$textarea.bind('keyup encapsulateSelection',function(event){var context=$(this).data('context');$(this).eachAsync({bulk:0,loop:function(){$.wikiEditor.modules.toc.fn.build(context);$.wikiEditor.modules.toc.fn.update(context);}});}).bind('mouseup scrollToPosition',function(event){var context=$(this).data('context');$(this).eachAsync({bulk:0,loop:function(){$.wikiEditor.modules.toc.fn.update(context);}});});},update:function(context){context.modules.$toc.find('a').removeClass('currentSelection');var position=context.$textarea.getCaretPosition();var section=0;if(context.data.outline.length>0){if(!(position<context.data.outline[0].position-1)){while(section<context.data.outline.length&&context.data.outline[section].position-1<position){section++;}
 52+section=Math.max(0,section);}
 53+context.modules.$toc.find('a.section-'+section).addClass('currentSelection');}},build:function(context){function buildStructure(outline,offset,level){if(offset==undefined)offset=0;if(level==undefined)level=1;var sections=[];for(var i=offset;i<outline.length;i++){if(outline[i].nLevel==level){var sub=buildStructure(outline,i+1,level+1);if(sub.length){outline[i].sections=sub;}
 54+sections[sections.length]=outline[i];}else if(outline[i].nLevel<level){break;}}
 55+return sections;}
 56+function buildList(structure){var list=$('<ul></ul>');for(i in structure){var item=$('<li></li>').append($('<a></a>').attr('href','#').addClass('section-'+structure[i].index).data('textbox',context.$textarea).data('position',structure[i].position).click(function(event){$(this).data('textbox').scrollToCaretPosition($(this).data('position'));event.preventDefault();}).text(structure[i].text));if(structure[i].sections!==undefined){item.append(buildList(structure[i].sections));}
 57+list.append(item);}
 58+return list;}
 59+var outline=[];var wikitext='\n'+context.$textarea.val()+'\n';var headings=wikitext.match(/\n={1,5}.*={1,5}(?=\n)/g);var offset=0;headings=$.makeArray(headings);for(var h=0;h<headings.length;h++){text=headings[h];var position=wikitext.indexOf(text,offset);if(position>offset){offset=position;}else if(position==-1){continue;}
 60+text=$.trim(text);var startLevel=0;for(var c=0;c<text.length;c++){if(text.charAt(c)=='='){startLevel++;}else{break;}}
 61+var endLevel=0;for(var c=text.length-1;c>=0;c--){if(text.charAt(c)=='='){endLevel++;}else{break;}}
 62+var level=Math.min(startLevel,endLevel);text=$.trim(text.substr(level,text.length-(level*2)));outline[h]={'text':text,'position':position,'level':level,'index':h+1};}
 63+var lastLevel=0;var nLevel=0;for(var i=0;i<outline.length;i++){if(outline[i].level>lastLevel){nLevel++;}
 64+else if(outline[i].level<lastLevel){nLevel-=Math.max(1,lastLevel-outline[i].level);}
 65+outline[i].nLevel=nLevel;lastLevel=nLevel;}
 66+var structure=buildStructure(outline);structure.unshift({'text':wgTitle,'level':1,'index':0,'position':0});context.modules.$toc.html(buildList(structure));context.data.outline=outline;}}};})(jQuery);(function($){$.wikiEditor.modules.toolbar={imgPath:wgScriptPath+'/extensions/UsabilityInitiative/images/wikiEditor/toolbar/',api:{addToToolbar:function(context,data){},modifyToolbar:function(context,data){},removeFromToolbar:function(context,data){if(typeof data.section=='string'){var selector='div[rel='+data.section+'].section';if(typeof data.group=='string'){selector+=' div[rel='+data.group+'].group';if(typeof data.tool=='string'){selector+=' div[rel='+data.tool+'].tool';}}
 67+context.modules.$toolbar.find(selector).remove();}}},fn:{autoMsg:function(object,property){if(property in object){return object[property];}else if(property+'Msg'in object){return gM(object[property+'Msg']);}else{return'';}},create:function(context,config){if('$toolbar'in context.modules){return;}
 68+context.modules.$toolbar=$('<div></div>').addClass('wikiEditor-ui-toolbar');$.wikiEditor.modules.toolbar.fn.build(context,config);context.$ui.find('.wikiEditor-ui-top').append(context.modules.$toolbar);},doAction:function(context,action){switch(action.type){case'encapsulate':var parts={'pre':'','peri':'','post':''};for(part in parts){if(part+'Msg'in action.options){parts[part]=gM(action.options[part+'Msg'],(action.options[part]||null));}else{parts[part]=(action.options[part]||'')}}
 69+context.$textarea.encapsulateSelection(parts.pre,parts.peri,parts.post);break;default:break;}},buildSection:function(context,id,section){switch(section.type){case'toolbar':return $.wikiEditor.modules.toolbar.fn.buildToolbar(context,id,section);case'booklet':return $.wikiEditor.modules.toolbar.fn.buildBooklet(context,id,section);default:return null;}},buildToolbar:function(context,id,toolbar){var $toolbar=$('<div></div>').attr({'class':'toolbar section section-'+id,'rel':id});if('groups'in toolbar){for(group in toolbar.groups){$toolbar.append($.wikiEditor.modules.toolbar.fn.buildGroup(context,group,toolbar.groups[group]));}}
 70+return $toolbar;},buildGroup:function(context,id,group){var $group=$('<div></div>').attr({'class':'group group-'+id,'rel':id});var label=$.wikiEditor.modules.toolbar.fn.autoMsg(group,'label');if(label){$group.append($('<div></div>').text(label).addClass('label'))}
 71+if('tools'in group){for(tool in group.tools){$group.append($.wikiEditor.modules.toolbar.fn.buildTool(context,tool,group.tools[tool]));}}
 72+return $group;},buildTool:function(context,id,tool){if('filters'in tool){for(filter in tool.filters){if($(tool.filters[filter]).size()==0){return null;}}}
 73+var label=$.wikiEditor.modules.toolbar.fn.autoMsg(tool,'label');switch(tool.type){case'button':$button=$('<img />').attr({'src':$.wikiEditor.modules.toolbar.imgPath+tool.icon,'alt':label,'title':label,'rel':id,'class':'tool tool-'+id});if('action'in tool){$button.data('action',tool.action).data('context',context).click(function(){$.wikiEditor.modules.toolbar.fn.doAction($(this).data('context'),$(this).data('action'));return false;});}
 74+return $button;case'select':var $select=$('<select></select>').attr({'rel':id,'class':'tool tool-'+id});$select.append($('<option></option>').text(label))
 75+if('list'in tool){$select.data('list',tool.list).data('context',context).click(function(){var list=$(this).data('list');var val=$(this).val();if(val in list&&'action'in list[val]){$.wikiEditor.modules.toolbar.fn.doAction($(this).data('context'),list[val].action);}
 76+$(this).find(":selected").attr('selected',false).find(":first").attr('selected',true);return false;});for(option in tool.list){var optionLabel=$.wikiEditor.modules.toolbar.fn.autoMsg(tool.list[option],'label');$select.append($('<option></option>').text(optionLabel).attr('value',option));}}
 77+return $select;default:return null;}},buildBooklet:function(context,id,booklet){var selected=$.cookie('wikiEditor-'+context.instance+'-booklet-'+id+'-page');var $booklet=$('<div></div>').attr({'class':'booklet section section-'+id,'rel':id});var $pages=$('<div></div>').attr('class','pages');var $index=$('<div></div>').attr('class','index');if('pages'in booklet){if(!(selected in booklet.pages)){selected=null;}
 78+for(page in booklet.pages){if(selected===null){selected=page;}
 79+var $page=$.wikiEditor.modules.toolbar.fn.buildPage(context,page,booklet.pages[page]);var $bookmark=$.wikiEditor.modules.toolbar.fn.buildBookmark(context,page,booklet.pages[page]);if(selected==page){$page.show();$bookmark.addClass('current');}else{$page.hide();}
 80+$pages.append($page);$index.append($bookmark);}}
 81+return $booklet.append($index).append($pages);},buildBookmark:function(context,id,page){var label=$.wikiEditor.modules.toolbar.fn.autoMsg(page,'label');return $('<div></div>').text(label).attr('rel',id).data('context',context).click(function(){$(this).parent().parent().find('.page').hide();$(this).parent().parent().find('.page-'+$(this).attr('rel')).show();$(this).siblings().removeClass('current');$(this).addClass('current');var section=$(this).parent().parent().attr('rel');$.cookie('wikiEditor-'+$(this).data('context').instance+'-booklet-'+section+'-page',$(this).attr('rel'));});},buildPage:function(context,id,page){var $page=$('<div></div>').attr({'class':'page page-'+id,'rel':id});switch(page.layout){case'table':$page.addClass('page-table');var $table=$('<table></table>').attr({'cellpadding':'0','cellspacing':'0','border':'0','width':'100%','class':'table table-'+id});if('headings'in page){var $headings=$('<tr></tr>');for(heading in page.headings){var content=$.wikiEditor.modules.toolbar.fn.autoMsg(page.headings[heading],'content');$headings.append($('<th></th>').text(content));}
 82+$table.append($headings);}
 83+if('rows'in page){for(row in page.rows){var $row=$('<tr></tr>');for(cell in page.rows[row]){var $cell=$('<td></td>').attr({'class':'cell cell-'+cell,'valign':'top'});var content=$.wikiEditor.modules.toolbar.fn.autoMsg(page.rows[row][cell],'content');$cell.append($('<span></span>').html(content));$row.append($cell);}
 84+$table.append($row);}}
 85+$page.append($table);break;case'characters':$page.addClass('page-characters');$characters=$('<div></div>');if('language'in page){$characters.attr('lang',page.language);}
 86+if('direction'in page){$characters.attr('dir',page.direction);}
 87+if('characters'in page){for(character in page.characters){var tool=page.characters[character];if(typeof tool=='string'){tool={'label':tool,'action':{'type':'encapsulate','options':{'pre':tool}}};}
 88+if('action'in tool&&'label'in tool){var $character=$('<a></a>').attr('href','#').text(tool.label).data('context',context).data('action',tool.action).click(function(){$.wikiEditor.modules.toolbar.fn.doAction($(this).data('context'),$(this).data('action'));return false;});$characters.append($character);}}
 89+$page.append($characters);}
 90+break;}
 91+return $page;},build:function(context,config){var $tabs=$('<div></div>').addClass('tabs').appendTo(context.modules.$toolbar);var $sections=$('<div></div>').addClass('sections').appendTo(context.modules.$toolbar);context.modules.$toolbar.append($('<div></div>').addClass('break'));var selected=$.cookie('wikiEditor-'+context.instance+'-toolbar-section');var sectionQueue=[];for(section in config){if(section=='main'){context.modules.$toolbar.prepend($.wikiEditor.modules.toolbar.fn.buildSection(context,section,config[section]));}else{s={'context':context,'$sections':$sections,'$tabs':$tabs,'section':section,'config':config[section],'selected':(selected==section)};sectionQueue[sectionQueue.length]=s;s.$tabs.append($('<span></span>').attr({'class':'tab tab-'+s.section,'rel':s.section}).append($('<a></a>').addClass(s.selected?'current':null).attr('href','#').text($.wikiEditor.modules.toolbar.fn.autoMsg(s.config,'label')).data('context',s.context).click(function(){var $section=$(this).data('context').$ui.find('.section-'+
 92+$(this).parent().attr('rel'));$(this).blur();var show=$section.css('display')=='none';$section.parent().children().hide();$(this).parent().parent().find('a').removeClass('current');if(show){$section.show();$(this).addClass('current');}
 93+$.cookie('wikiEditor-'+
 94+$(this).data('context').instance+'-toolbar-section',show?$section.attr('rel'):null);return false;})));}}
 95+$.eachAsync(sectionQueue,{'bulk':0,'end':function(){$('body').css('position','static');$('body').css('position','relative');},'loop':function(i,s){s.$sections.append($.wikiEditor.modules.toolbar.fn.buildSection(s.context,s.section,s.config).css('display',s.selected?'block':'none'));}});}}};})(jQuery);
\ No newline at end of file

Follow-up revisions

RevisionCommit summaryAuthorDate
r54646EditToolbar: Allow user/site JS, which is loaded before editToolbarConfigurat...catrope09:52, 9 August 2009
r54752Merge a bunch of UsabilityInitiative fixes. This commit may mess up svn:merge...catrope22:12, 10 August 2009

Status & tagging log