Aller au contenu

Utilisateur:Gede/vector.js

Une page de Wikipédia, l'encyclopédie libre.
Note : après avoir enregistré la page, vous devrez forcer le rechargement complet du cache de votre navigateur pour voir les changements.

Mozilla / Firefox / Konqueror / Safari : maintenez la touche Majuscule (Shift) en cliquant sur le bouton Actualiser (Reload) ou pressez Maj-Ctrl-R (Cmd-R sur Apple Mac) ;

Firefox (sur GNU/Linux) / Chrome / Internet Explorer / Opera : maintenez la touche Ctrl en cliquant sur le bouton Actualiser ou pressez Ctrl-F5.
// <nowiki>
importScript('User:Alphos/historyselect.js');



//wgVectorEnabledModules.simplesearch = false;

jQuery(document).ready(function($){			
   $('table.sortable_new').each(function(){
         var thead = $(this).find('tr:first').detach();
         $(this).find('tbody:first').before('<thead />');
         $(this).find('thead').prepend(thead);
         if($(this).hasClass('pager_new')) {
              $(this).ariaSorTable({rowsToShow: 10, pager: true,});
         } else {
              $(this).ariaSorTable();
         }
   });
});	

jQuery(document).ready(function($){			
   $('#toc a').click(function(){
         var cible = $(this).attr('href');
         $(cible).parents('.acc_navbox collapsed').removeClass('acc_navbox collapsed');
   });
});

jQuery(document).ready(function($){
   $('[tabindex]').attr('tabindex',0);
});
 
jQuery(document).ready(function($){
   $('#searchform').append($('<input />').attr({'type':'hidden','name':'advanced','value':1}));
   $('#searchform').append($('<input />').attr({'type':'hidden','name':'ns4','value':1}));
   $('#searchform').append($('<input />').attr({'type':'hidden','name':'ns5','value':1}));
   $('#searchform').append($('<input />').attr({'type':'hidden','name':'ns8','value':1}));
   $('#searchform').append($('<input />').attr({'type':'hidden','name':'ns9','value':1}));
   $('#searchform').append($('<input />').attr({'type':'hidden','name':'ns10','value':1}));
   $('#searchform').append($('<input />').attr({'type':'hidden','name':'ns12','value':1}));
});

jQuery(document).ready(function($){
   $('#bodyContent > p:first b').wrapInner('<dfn />');
   $('#bodyContent > p:first b dfn').unwrap();
});

jQuery(document).ready(function($){
   $('#content div.acc_navbox:has(div.acc_navbox)').removeClass('acc_navbox').toggleClass('error').text('Désolé : pas de boîtes déroulantes dans des boîtes déroulantes');
   var $navbox=$('#content div.acc_navbox p.acc_navbox_header');
 
   $navbox.each(function(){
      var $label = 'Ouvrir/fermer ' + $(this).find('span.acc_navbox_label').text();
      $(this).append('<span class="acc_navbox_toggle acc_navbox_space"><a href="#" title="'+$label+'">Enrouler</a></span>');
 
      var $parent = $(this).parent();
      var $toggle = $(this).find('span.acc_navbox_toggle a');
      if($parent.hasClass('collapsed')) {
         $parent.find('ul.acc_navbox_content, div.acc_navbox_content').hide();
         var $label = $toggle.text();
         if($label == 'Enrouler') {
            $toggle.text('Dérouler');
         }
      }
      $parent.attr({'role':'navigation'})
   });
 
   $('div.acc_navbox > p.acc_navbox_header > span.acc_navbox_toggle a').click(function(){
      var $parent = $(this).parents('div.acc_navbox');
      $parent.toggleClass('collapsed');
      $parent.find('ul.acc_navbox_content, div.acc_navbox_content').slideToggle('fast');
      if($(this).text() == 'Enrouler' || $(this).text() == 'Dérouler') {
         $(this).text(($(this).text() == 'Enrouler') ? 'Dérouler' : 'Enrouler');
      }
      return false;
   });
});

importScript('Utilisateur:Lgd/typo.js');

/* test tableau amélioré */

jQuery(document).ready(function($){
 
  $('#p-accessibility ul').append('<li><a title="Vérifier ..." id="acc_new_test" href="#">Complément tableaux</a></li>');

  var state=$.cookie('acc_new_test');
  if(state=='true'  && (mw.config.get('wgAction')=='view')){
  	acc_new_test();
  }
 
  if(state!=null){
  	$.cookie('acc_new_test',state,{'expires':30,'path':'/'});
  }
 
  $('#acc_new_test').click(function(){
  	acc_new_test();
  	return false;
  });
 
  function acc_new_test(){
  	$('#acc_new_test').toggleClass('acc_on');
  	$.cookie('acc_new_test',$('#acc_new_test').is('.acc_on'),{'expires':30,'path':'/'});
  	if($('#acc_new_test').attr('class') == 'acc_on') {
/*
  		$('#content table:not(:has(table))').each(function() {
  			$(this).find('tr:first-child th:only-child').prepend('<span class="error acc_th_error">Vérifiez s\'il faut scinder le tableau en plusieurs tableaux simples<br>ou si cette cellule ne devrait pas être un titre de tableau</span>');
  			$(this).find('tr:last-child th:only-child').prepend('<span class="error acc_th_error">Vérifiez si cette cellule n\'est pas une note à placer après le tableau</span>');
  			$(this).find('tr:not(:last-child):not(:first-child) th:only-child').prepend('<span class="error acc_th_error">Vérifiez s\'il faut scinder le tableau en plusieurs tableaux simples</span>');
  		});
*/
  		$('#content table tr:first-child th:only-child:not(:has(span.acc_th_error))').prepend('<span class="error acc_th_error">Vérifiez s\'il faut scinder le tableau en plusieurs tableaux simples<br>ou si cette cellule ne devrait pas être un titre de tableau</span>');
  		$('#content table tr:last-child th:only-child:not(:has(span.acc_th_error))').prepend('<span class="error acc_th_error">Vérifiez si cette cellule n\'est pas une note à placer après le tableau</span>');
  		$('#content table tr:not(:last-child):not(:first-child) th:only-child:not(:has(span.acc_th_error))').prepend('<span class="error acc_th_error">Vérifiez s\'il faut scinder le tableau en plusieurs tableaux simples</span>');
  		$('#content table th:not([scope]):not(:has(span.acc_th_error))').prepend('<span class="error acc_th_error">Vérifiez s\'il faut ajouter un SCOPE ou transformer en TD (code wiki: |)</span>');
  	} else {
  	  	$('#content table span.acc_th_error').remove();    
  	}
  };
});

/* tests liens from dev corporate */

jQuery(document).ready(function($){
 
  $('#p-accessibility ul').append('<li><a title="Vérifier l\'accessibilité des liens" id="acc_links" href="#">Liens</a></li>');

  var state=$.cookie('acc_links');
  if(state=='true'  && (mw.config.get('wgAction')=='view')){
  	acc_links();
  }
 
  if(state!=null){
  	$.cookie('acc_links',state,{'expires':30,'path':'/'});
  }
 
  $('#acc_links').click(function(){
  	acc_links();
  	return false;
  });
 
  function acc_links(){
  	$('#acc_links').toggleClass('acc_on');
  	$.cookie('acc_links',$('#acc_links').is('.acc_on'),{'expires':30,'path':'/'});
  	if($('#acc_links').attr('class') == 'acc_on') {
		var links  = $('a:empty[href]');
		if(links.length>0) {
			links.addClass('acc_links').before('<span class="error acc_attr_show acc_links">Lien sans libellé (pseudo-contenu CSS)</span>');
		}
		var img = $('a img:only-child[alt=]').filter(function() {
			var texte = $(this).parents('a').text(); 
			return texte.length == 0;
		});
		if(img.length>0) {
			img.before('<span class="error acc_attr_show acc_links">Lien sans libellé (alternative vide)</span>').parents('a').addClass('acc_links');
		}
		
  	} else {
  	  	$('span.acc_links').remove();
  	  	$('a').removeClass('acc_links');
  	}
  };
});


/* test titres amélioré */

jQuery(document).ready(function($){
 
  $('#p-accessibility ul').append('<li><a title="Vérifier l\'accessibilité des titres" id="acc_header2" href="#">Titres amélioré</a></li>');

  var state=$.cookie('acc_header2');
  if(state=='true'  && (mw.config.get('wgAction')=='view')){
  	acc_header2();
  }
 
  if(state!=null){
  	$.cookie('acc_header2',state,{'expires':30,'path':'/'});
  }
 
  $('#acc_header2').click(function(){
  	acc_header2();
  	return false;
  });
 
  function acc_header2(){
  	$('#acc_header2').toggleClass('acc_on');
  	$.cookie('acc_header2',$('#acc_header2').is('.acc_on'),{'expires':30,'path':'/'});
  	if($('#acc_header2').attr('class') == 'acc_on') {
  		var headers= $('#content :header');
  		headers.each(function(index) {
  			if(headers.get(index-1)) {
  				level = parseInt(headers.get(index).nodeName.substring(2,1));
  				levelbefore = parseInt(headers.get(index-1).nodeName.substring(2,1));
  					if(level - levelbefore > 1) {
  						$(this).addClass('acc_headers').before('<span class="error acc_attr_show acc_headers">Titrage de niveau incorrect</span>');
  					}
  			}
  		});
  	} else {
  	  	$('span.acc_headers').remove();
  	  	$('#content :header').removeClass('acc_headers');
  	}
  };
});
/* tests justify from dev corporate */

jQuery(document).ready(function($){
 
  $('#p-accessibility ul').append('<li><a title="Vérifier l\'absence de texte justifié" id="acc_justify" href="#">Justified</a></li>');

  var state=$.cookie('acc_justify');
  if(state=='true'  && (mw.config.get('wgAction')=='view')){
  	acc_justify();
  }
 
  if(state!=null){
  	$.cookie('acc_justify',state,{'expires':30,'path':'/'});
  }
 
  $('#acc_justify').click(function(){
  	acc_justify();
  	return false;
  });
 
  function acc_justify(){
  	$('#acc_justify').toggleClass('acc_on');
  	$.cookie('acc_justify',$('#acc_justify').is('.acc_on'),{'expires':30,'path':'/'});
  	if($('#acc_justify').attr('class') == 'acc_on') {
  	 	var justify = $('#content').find('*').filter(function() {
  	 		return $(this).css('text-align') == 'justify';
  	 	});
  	 	if (justify.length > 0)
  	 		justify.each( function() {
  	 			$(this).before('<span class="error acc_attr_show acc_justify">Texte justifié</span>').addClass('acc_justify');
  	 		});
  	} else {
  	  	$('span.acc_justify').remove();
  	  	$('#content').find('*').removeClass('acc_justify');
  	}
  };
});

/* test img amélioré */

jQuery(document).ready(function($){
  $('#p-accessibility ul').append('<li><a title="..." id="acc_alt_test" href="#">alt amélioré</a></li>');

/* Alternatives */
  var state=$.cookie('wp_acc_alt_test');
  if(state=='true'){
  	acc_alt_test();
  }
 
  if(state!=null){
  	$.cookie('wp_acc_alt_test',state,{'expires':30,'path':'/'});
  }
 
  $('#acc_alt_test').click(function(){
  	acc_alt_test();
  	return false;
  });
 
  function acc_alt_test(){
  	$('#acc_alt_test').toggleClass('acc_on');
  	$.cookie('wp_acc_alt_test',$('#acc_alt_test').is('.acc_on'),{'expires':30,'path':'/'});
  	if($('#acc_alt_test').attr('class') == 'acc_on') {
        	$('#content img').each(function(){
        		var $alt = $(this).attr('alt');
        		var $parent = $(this).parent();
        		var $grandparent = $parent.parent();
        		if(!$grandparent.is('.magnify')) {
        			if($alt == '') {
        				if($parent.is('a')) {
        					$alt = '<span class="error">ALT MANQUANT</span>';
					} else {
						$alt = 'ALT VIDE';
					}
        			} else {
					if($alt.length > 120) {
						$alt = $alt + '<br /><span class="error">Vérifiez si cette alternative de ' + $alt.length + ' caractères pourrait être plus concise (environ 120 caractères au plus) et si l\'alternative actuelle pourrait être transférée dans la section description de la page de l\'image.</span>';
					}
        			} 
        			if (!$(this).parents().is('.thumb')) {
        				if($(this).is('img[alt$=.png], img[alt$=.svg], img[alt$=.jpg], img[alt$=.gif], img[alt$=.PNG], img[alt$=.SVG], img[alt$=.JPG], img[alt$=.GIF]')) {
        					$alt = '<span class="error">ALT MANQUANT</span>';
        				}
        				if(($parent.is('a.image') || $parent.is('.mw-file-description')) && !$grandparent.is('.smiley')) {
        					if($grandparent.is('.flagicon')) {
        						if(!$(this).is('img[alt^=Drapeau], img[alt^=drapeau], img[alt^=Pavillon], img[alt^=pavillon]')) {
        						$alt = $alt + '<br /><span class="error">L\'alternative devrait commencer par « Drapeau... » ou « Pavillon... »</span>';	
        						}
 
        					} else {
        						$alt = $alt + '<br /><span class="error">Vérifiez si le lien sur l\'image peut être désactivé (LINK vide)<br />(ou si l\'image peut être transformée en thumb)</span>';
        					}
        				}
         			}
        			if($parent.is('a')) {
        				$parent.before('<span class="acc_attr_show">'+$alt+'</span>');
        			} else {
        				$(this).before('<span class="acc_attr_show">'+$alt+'</span>');
        			}
			}
        	});
        	$('#content table.gallery').before('<span class="acc_attr_show"><span class="error">Les alternatives des images ne peuvent pas être indiquées dans les galeries. (<a href="https://bugzilla.wikimedia.org/show_bug.cgi?id=18682" target="_blank" title="Demande de correction du bug des alternatives d\'images dans les galeries, sur Bugzilla, en anglais (nouvelle fenêtre)">Vous pouvez voter pour la résolution ce bug</a>).</span></span>');
        	$('#content img[usemap]').before('<span class="acc_attr_show"><span class="error">Les alternatives nécessaires aux images de <span lang="en">timelines</span> ne peuvent pas être indiquées en l\'état actuel de cette extension.</span></span>');
  	} else {
  		$('#content span.acc_attr_show').remove();      	
  	}
  }
 
});

/*!
 * jQuery UI Widget 1.8.7
 *
 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Widget
 */
(function($, undefined) {

    // jQuery 1.4+
    if ($.cleanData) {
        var _cleanData = $.cleanData;
        $.cleanData = function(elems) {
            for (var i = 0, elem; (elem = elems[i]) != null; i++) {
                $(elem).triggerHandler("remove");
            }
            _cleanData(elems);
        };
    } else {
        var _remove = $.fn.remove;
        $.fn.remove = function(selector, keepData) {
            return this.each(function() {
                if (!keepData) {
                    if (!selector || $.filter(selector, [this]).length) {
                        $("*", this).add([this]).each(function() {
                            $(this).triggerHandler("remove");
                        });
                    }
                }
                return _remove.call($(this), selector, keepData);
            });
        };
    }

    $.widget = function(name, base, prototype) {
        var namespace = name.split(".")[0],
        fullName;
        name = name.split(".")[1];
        fullName = namespace + "-" + name;

        if (!prototype) {
            prototype = base;
            base = $.Widget;
        }

        // create selector for plugin
        $.expr[":"][fullName] = function(elem) {
            return !! $.data(elem, name);
        };

        $[namespace] = $[namespace] || {};
        $[namespace][name] = function(options, element) {
            // allow instantiation without initializing for simple inheritance
            if (arguments.length) {
                this._createWidget(options, element);
            }
        };

        var basePrototype = new base();
        // we need to make the options hash a property directly on the new instance
        // otherwise we'll modify the options hash on the prototype that we're
        // inheriting from
        //	$.each( basePrototype, function( key, val ) {
        //		if ( $.isPlainObject(val) ) {
        //			basePrototype[ key ] = $.extend( {}, val );
        //		}
        //	});
        basePrototype.options = $.extend(true, {},
        basePrototype.options);
        $[namespace][name].prototype = $.extend(true, basePrototype, {
            namespace: namespace,
            widgetName: name,
            widgetEventPrefix: $[namespace][name].prototype.widgetEventPrefix || name,
            widgetBaseClass: fullName
        },
        prototype);

        $.widget.bridge(name, $[namespace][name]);
    };

    $.widget.bridge = function(name, object) {
        $.fn[name] = function(options) {
            var isMethodCall = typeof options === "string",
            args = Array.prototype.slice.call(arguments, 1),
            returnValue = this;

            // allow multiple hashes to be passed on init
            options = !isMethodCall && args.length ? $.extend.apply(null, [true, options].concat(args)) : options;

            // prevent calls to internal methods
            if (isMethodCall && options.charAt(0) === "_") {
                return returnValue;
            }

            if (isMethodCall) {
                this.each(function() {
                    var instance = $.data(this, name),
                    methodValue = instance && $.isFunction(instance[options]) ? instance[options].apply(instance, args) : instance;
                    // TODO: add this back in 1.9 and use $.error() (see #5972)
                    //				if ( !instance ) {
                    //					throw "cannot call methods on " + name + " prior to initialization; " +
                    //						"attempted to call method '" + options + "'";
                    //				}
                    //				if ( !$.isFunction( instance[options] ) ) {
                    //					throw "no such method '" + options + "' for " + name + " widget instance";
                    //				}
                    //				var methodValue = instance[ options ].apply( instance, args );
                    if (methodValue !== instance && methodValue !== undefined) {
                        returnValue = methodValue;
                        return false;
                    }
                });
            } else {
                this.each(function() {
                    var instance = $.data(this, name);
                    if (instance) {
                        instance.option(options || {})._init();
                    } else {
                        $.data(this, name, new object(options, this));
                    }
                });
            }

            return returnValue;
        };
    };

    $.Widget = function(options, element) {
        // allow instantiation without initializing for simple inheritance
        if (arguments.length) {
            this._createWidget(options, element);
        }
    };

    $.Widget.prototype = {
        widgetName: "widget",
        widgetEventPrefix: "",
        options: {
            disabled: false
        },
        _createWidget: function(options, element) {
            // $.widget.bridge stores the plugin instance, but we do it anyway
            // so that it's stored even before the _create function runs
            $.data(element, this.widgetName, this);
            this.element = $(element);
            this.options = $.extend(true, {},
            this.options, this._getCreateOptions(), options);

            var self = this;
            this.element.bind("remove." + this.widgetName,
            function() {
                self.destroy();
            });

            this._create();
            this._trigger("create");
            this._init();
        },
        _getCreateOptions: function() {
            return $.metadata && $.metadata.get(this.element[0])[this.widgetName];
        },
        _create: function() {},
        _init: function() {},

        destroy: function() {
            this.element.unbind("." + this.widgetName).removeData(this.widgetName);
            this.widget().unbind("." + this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass + "-disabled " + "ui-state-disabled");
        },

        widget: function() {
            return this.element;
        },

        option: function(key, value) {
            var options = key;

            if (arguments.length === 0) {
                // don't return a reference to the internal hash
                return $.extend({},
                this.options);
            }

            if (typeof key === "string") {
                if (value === undefined) {
                    return this.options[key];
                }
                options = {};
                options[key] = value;
            }

            this._setOptions(options);

            return this;
        },
        _setOptions: function(options) {
            var self = this;
            $.each(options,
            function(key, value) {
                self._setOption(key, value);
            });

            return this;
        },
        _setOption: function(key, value) {
            this.options[key] = value;

            if (key === "disabled") {
                this.widget()[value ? "addClass": "removeClass"](this.widgetBaseClass + "-disabled" + " " + "ui-state-disabled").attr("aria-disabled", value);
            }

            return this;
        },

        enable: function() {
            return this._setOption("disabled", false);
        },
        disable: function() {
            return this._setOption("disabled", true);
        },

        _trigger: function(type, event, data) {
            var callback = this.options[type];

            event = $.Event(event);
            event.type = (type === this.widgetEventPrefix ? type: this.widgetEventPrefix + type).toLowerCase();
            data = data || {};

            // copy original event properties over to the new event
            // this would happen if we could call $.event.fix instead of $.Event
            // but we don't have a way to force an event to be fixed multiple times
            if (event.originalEvent) {
                for (var i = $.event.props.length, prop; i;) {
                    prop = $.event.props[--i];
                    event[prop] = event.originalEvent[prop];
                }
            }

            this.element.trigger(event, data);

            return ! ($.isFunction(callback) && callback.call(this.element[0], event, data) === false || event.isDefaultPrevented());
        }
    };

})(jQuery);

/*!
 * jQuery UI AriaSorTable (24.12.10)
 * http://github.com/fnagel/jQuery-Accessible-RIA
 *
 * Copyright (c) 2009 Felix Nagel for Namics (Deustchland) GmbH
 * Copyright (c) 2010-2011 Felix Nagel
 * Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
 *
 * Depends: jQuery UI
 * Optional: jQuery Address Plugin
 */ 
/*
 USAGE:::::::::::::
* Take a look in the html file or the (german) pdf file delivered with this example
* To set sorting method add css classes, default is text, alphabetically 

* Sorting CSS classes (apply to th elements)
ui-table-text			default: sorts text
ui-table-text-html		sorts text with html tags
ui-table-number 		123 or 123.456
ui-table-number-de 		123,456
ui-table-date 			07/28/2009
ui-table-date-de		28.07.2009
ui-table-date-iso		2009-07-28  
 ui-table-deactivate 	deactivates sorting for this col
 ui-state-active 		class to set a col as pre sorted (server site)

 * Options	
rowToStart			row to start, begins with 1
rowsToShow			How many rows to show? If not set, widget will show all rows
colScopeRow			Which col has scope? Could be the UID or a names, begins with 1
defaultSortBy		first sorting action sould sort ascending or descending?
colsToHide			array; set value true if col should be hidden, example: colsToHide[3] = true;
rowsToHide			array; set value true if row should be hidden, example: rowsToHide[3] = true;
keyboard			activate default keyboard control
pager				add default pager control; (do use with rowsToShow < all rows in the original table)
textPager			String pager
textAsc				String for sorting ascending
textDesc			String for sorting descending
disabled			deactivate the widget
jqAddress			You need to add the add the jQuery Address file, please see demo file!
	enable			enable browser history support
	title
		enable		enable title change
		split		set delimiter string
			
* Callbacks
onInit
onUpdateData
onSetHTML
onRowSort

* public Methods
updateData
setHTML
rowSort
colSwitch
buildPager
setPager
disable
enable
disable
destroy
 
 */
(function($) {
// necassary global var for STRING.sort() function clauses
var sortIndex = 0;
$.widget("ui.ariaSorTable", {

	version: '1.8',
	options: {
		rowToStart: 1,
		rowsToShow: false,
		colScopeRow: 1,
		defaultSortBy: "asc",
		colsToHide: false,
		rowsToHide: false,
		keyboard: true,
		pager: false,
		textPager: "Page:",
		textAsc: "Sort ascending",
		textDesc: "Sort descending",		
		// jQuery Address
		jqAddress: {
			enable: true,
			title: {
				enable: true,
				split: ' | '		
			},
			changeRow: true
		}
	},
	
	_create: function() {
		var options = this.options, self = this;
		// init vars
		options.tableData = [];
		options.originalData = [];
		options.selectedCol = 0;
		options.activeCol = 0;
		
		// ARIA | make UID if no ID is set by default
		var elementID = self.element.attr("id");
		if (elementID != "") {
			options.uid = elementID;
		} else {
			options.uid = Math.random().toString(16).slice(2, 10);
			self.element.attr("id", "ui-table-"+options.uid);
		}		
		self.element.find("caption").attr("id", "ui-table-"+options.uid+"-caption");
		self.element
		.attr("role","grid")
		.attr("aria-readonly","true")
		.attr("aria-labelledby", "ui-table-"+options.uid+"-caption");
			
		// save header elements
		var theadTr = self.element.find("thead tr");
		// bubbling event for th link elements
		options.headers = theadTr.find("th");
		theadTr.bind("click", function(e){
			if (!options.disabled) {
				// get the th element
				th = $(e.target).closest("th", theadTr);
				if (!th.hasClass("ui-table-deactivate")) {	
					// does not work in certain browsers
					// self.rowSort(th.prevAll("th:visible").length); 
					self.rowSort(self._getVisible(th.prevAll("th")).length);	
					return false;
				}
			}
		})
		.attr("role", "row");
		
		options.headers.each( function(index) {
			// get single th element
			var th = $(this);
			
			// ARIA 
			th.attr("id","ui-table-" + options.uid + "-header-" + index)
			.attr("role","columnheader")
			.attr("scope","col");
			
			// select title text ( next sorting action)
			var text = (options.defaultSortBy == "asc") ? options.textAsc : options.textDesc;			
			var thA = th.find("a").length;
			if (!th.hasClass("ui-table-deactivate")) {	
				// no link but JS sort function? Add link
				if (!thA) {
					th.html('<a title="'+text+'" href="#ui-table-dummy">'+th.html()+'</a>');
				}
				// set title attribute | add events
				th.children("a")
				.attr("title", text)
				.bind("mouseenter", function(){ $(this).parent().addClass('ui-state-hover'); })
				.bind("mouseleave", function(){ $(this).parent().removeClass('ui-state-hover'); });
			//not activated th elements with no link are added to the tabindex by setting tabindex attribute
			} else if (!thA) {
				th.attr("tabindex", 0);
			}	
			
			// save pre sorted (server site) ; aka active col | set attributes
			if (th.hasClass("ui-state-active")) {
				if (th.hasClass("ui-table-asc")) {
					th.attr("aria-sort", "ascending").children("a").attr("title", options.textDesc);
				} else if (th.hasClass("ui-table-desc")) {
					th.attr("aria-sort", "descending").children("a").attr("title", options.textAsc);
				}
				options.activeCol = index;				
			}
		});		
		
		// get all table data and save them
		var rows = self.element.find("tbody tr");	
		// go trough every row	
		for (var x = 0; x < rows.length; x++) {
			options.originalData[x] = [];
			var cells = $(rows[x]).children("td");
			for (var y = 0; y < cells.length; y++) {
				options.originalData[x][y] = $(cells[y]).html();
			}
		}
		// set var to table length if no custom value
		if (!options.rowsToShow) options.rowsToShow = rows.length;
		// update data to delete hided rows and cols
		self.updateData();
		// pager?
		if (options.pager) self.buildPager();			
		// activate Keyboard accessibility
		if (options.keyboard) self._setKeyboard();
		
		// add jQuery Address stuff
		if ($.address && options.jqAddress.enable && self._jqAddressHelper) {
			// set inital state
			var startRow = self._jqAddressHelper($.address.pathNames());
			// check is address bar in browser is manually changed but fires setHTML only when necassary
			$.address.externalChange(function(event) {
				var changeRow = self._jqAddressHelper(event.pathNames);
				if (changeRow) self.setHTML(changeRow, false, true);
			});
		}
		startRow = (startRow) ? startRow : options.rowToStart;
		// set new HTML (with ARIA)
		self.setHTML(startRow, true);	 // true = initial	
		// Callback
		self._trigger("onInit", 0);
	},	
	
	
	// make another "cleaned" version of the data array | delete hidden rows and cols
	updateData: function () {
		var options = this.options, self = this;
		options.tableData = [];
		var xIndex = 0;
		for (var x = 0; x < options.originalData.length; x++) {
			if (!options.rowsToHide[x]) {
				options.tableData[xIndex] = [];
				for (var y = 0; y < options.headers.length; y++) {
					if (!options.colsToHide[y]) options.tableData[xIndex].push(options.originalData[x][y]);
				}
				xIndex++;
			} 
		}
		// Callback
		self._trigger("onUpdateData", 0);
	},	
	
	// set new HTML with selected data
	// init and forceFirst only necassary when using jqAddress
	setHTML: function(newRowToStart, init, forceFirst) {
		var options = this.options, self = this;
		// var for diffrent row colors
		var second = true;
		var html = [];		
		// backfall
		if (!newRowToStart) newRowToStart = option.rowToStart;		
		// set pager
		if (options.pager) self.setPager(newRowToStart);
		// make html
		html.push(					"<tbody class=\"ui-table-tbody-active\" aria-live=\"polite\" aria-relevant=\"text\">\n");
		for (var x = newRowToStart - 1; x < newRowToStart - 1 + options.rowsToShow; x++) {
			// check if row data exists
			if (options.tableData[x]) {
				// diffrent row css class
				var rowClass = (second) ? "class=\"odd\"" : "";		
				second = (second) ? false : true;		
				html.push(		"\t\t\t\t<tr role=\"row\""+rowClass+">\n");
				// build table html (with ARIA and HTML table relation attributes)
				for (var y = 0; y < options.tableData[x].length; y++) {
					if (y+1 == options.colScopeRow) {
						html.push("\t\t\t\t\t<td headers=\"ui-table-"+ options.uid +"-header-"+ y +"\" scope=\"row\" role=\"rowheader\">" + options.tableData[x][y] + "</td>\n");
					} else {
						html.push("\t\t\t\t\t<td headers=\"ui-table-"+ options.uid +"-header-"+ y +"\" role=\"gridcell\">" + options.tableData[x][y] + "</td>\n");
					}
				}
				html.push(			"\t\t\t\t</tr>\n");
			}
		}
		html.push(					"\t\t\t</tbody>");
		var str = '';
		str = html.join('');
		// replace tbody or hide original and add new | dont remove but hide because of performance
		var tbody = self.element.find("tbody.ui-table-tbody-active");
		if (tbody.length) {
			tbody.replaceWith(str);
		} else {
			self.element.find("tbody").hide();
			self.element.append(str);
		}
		
		// show or hide header cols
		if (options.colsToHide)
		options.headers.each( function(index) {
			if (!options.colsToHide[index]) {
				$(this).show();
			} else {
				$(this).hide();
			}
		});		
		
		// ARIA
		$(options.headers[0]).parent().parent()
		.attr("aria-live", "polite")
		.attr("aria-relevant","text");
		
		// add jQuery Address stuff
		if ($.address && options.jqAddress.enable) {
			if (!init) {
				if (options.jqAddress.title.enable) $.address.title($.address.title().split(options.jqAddress.title.split)[0] + options.jqAddress.title.split + self.element.find("caption").text() + " (" + newRowToStart + "-" + (newRowToStart - 1 + options.rowsToShow) + ")");
				// save first page in browser history when user (!) starts to interact with the table
				if (options.rowToStart == 1 && newRowToStart != 1 && !forceFirst) {
					// if there is no anchor to keep, prevent double entry
					if ($.address.value() == "") $.address.history(false);
					$.address.value(options.uid + "/" + 1 + "/" + options.rowsToShow);
					$.address.history(true);
				}
				$.address.value(options.uid + "/" + newRowToStart + "/" + (newRowToStart - 1 + options.rowsToShow));
			}
		}		
		// update virtual Buffer
		self._updateVirtualBuffer();
		
		// set new start point
		options.rowToStart = newRowToStart;		
		// Callback
		self._trigger("onSetHTML", 0);
	},
	
	// sort data, build and add the new html to the DOM
	rowSort: function (index) {
		var options = this.options, self = this;
		// get all visible th elements
		// var thArray = options.headers.filter(":visible");
		var thArray = self._getVisible(options.headers);
		// get new (clicked) th element
		th = $(thArray[index]);	
			
		// set global index		
		sortIndex = index;
		// check the css class and sort the array
		if (th.hasClass("ui-table-number")) {
			options.tableData.sort(self._sortNumber);
		} else if (th.hasClass("ui-table-number-de")) {
			options.tableData.sort(self._sortNumberDE);
		} else if (th.hasClass("ui-table-date")) {
			options.tableData.sort(self._sortDate);
		} else if (th.hasClass("ui-table-date-de")) {
			options.tableData.sort(self._sortDateDE);
		} else if (th.hasClass("ui-table-date-iso")) {
			options.tableData.sort(self._sortDateISO);
		} else if (th.hasClass("ui-table-text-html")) {
			options.tableData.sort(self._sortTextHTML);
		} else { 
			// default is text
			options.tableData.sort(self._sortText);
		}
		
		// set new sorted by
		var asc = th.hasClass("ui-table-asc");
		if (asc || th.hasClass("ui-table-desc")) {		
			var newSortBy = (asc) ? "desc" : "asc";
		// no class found? set it by default
		} else {
			var newSortBy = options.defaultSortBy;
		}		
		
		// reverse array if necassary
		if (newSortBy == "desc") options.tableData.reverse();
			
		// get active col
		var thActiveCol = $(thArray[options.activeCol]);
		// set class to remove of the active col
		var sortedBy = (thActiveCol.hasClass("ui-table-asc")) ? "asc" : "desc";
		// delete css class of the last sorted col
		thActiveCol
		.removeClass("ui-table-" + sortedBy)
		.removeClass("ui-state-active")
		// set ARIA-sort to none
		.attr("aria-sort", "none");
		
		// remove focus classs from selected col		
		$(thArray[options.selectedCol]).removeClass("ui-state-focus");	
			
		// set new title text
		var newSortByText = (newSortBy == "asc") ? options.textDesc : options.textAsc;
		var newSortByARIA = (newSortBy == "asc") ? "ascending" : "descending";
		// add new css class, title and css state to the new active col
		th.addClass("ui-state-active")
		.addClass("ui-table-" + newSortBy)
		.attr("aria-sort", newSortByARIA)
		.children("a").attr("title", newSortByText);
		
		// save new sorted and active col
		options.activeCol = options.selectedCol = index;	
		
		// Callback
		self._trigger("onRowSort", 0);				
		// update HTML 
		self.setHTML(options.rowToStart);	
	},
	
	// sorting clauses function
	_sortNumber: function (a, b) {
		// 123.456
		return (a[sortIndex] - b[sortIndex]);
	},
	_sortNumberDE: function (a, b) {
		// 123,456
		return (a[sortIndex].replace(",", ".") - b[sortIndex].replace(",", "."));
	},
	_sortDateDE: function (a, b) {	
		// 28.07.2009
		var x = Date.parse(a[sortIndex].substr(3,2) + "/" + a[sortIndex].substr(0,2) + "/" + a[sortIndex].substr(6,4));
		var y = Date.parse(b[sortIndex].substr(3,2) + "/" + b[sortIndex].substr(0,2) + "/" + b[sortIndex].substr(6,4));	
		return ((x < y) ? 1 : ((x > y) ? -1 : 0));
	},
	_sortDate: function (a, b) {	
		// 07/28/2009
		var x = Date.parse(a[sortIndex]);
		var y = Date.parse(b[sortIndex]);
		return ((x < y) ? 1 : ((x > y) ? -1 : 0));
	},
	_sortDateISO: function (a, b) {
		// 2009-07-28
		var x = Date.parse(a[sortIndex].substr(5,2) + "/" + a[sortIndex].substr(8,2) + "/" + a[sortIndex].substr(0,4));
		var y = Date.parse(b[sortIndex].substr(5,2) + "/" + b[sortIndex].substr(8,2) + "/" + b[sortIndex].substr(0,4));	
		return ((x < y) ? 1 : ((x > y) ? -1 : 0));
	},
	_sortTextHTML: function (a, b) {
		// Text with html
		var x = $(a[sortIndex]).text().toLowerCase();
		var y = $(b[sortIndex]).text().toLowerCase();
		return ((x < y) ? 1 : ((x > y) ? -1 : 0));
	},
	_sortText: function (a, b) {
		// 20:00:13
		// Text without (!) html
		var x = a[sortIndex].toLowerCase();
		var y = b[sortIndex].toLowerCase();
		return ((x < y) ? 1 : ((x > y) ? -1 : 0));
	},
	
	// jQuery :visible filter does not work with tables in certain browser (IE8, ?) so wee built our own function
	// http://www.code-styling.de/deutsch/jquery-132-verursacht-probleme-im-ie-8
	_getVisible: function (elements) {
		var elReturn = [];
		var i = 0;
		elements.each(function(index){
			if ($(this).css('display') != 'none') {
				elReturn[i] = $(this);
				i++;
			}
		});
		return elReturn;
	},
	
	// set keyboard control
	_setKeyboard: function () {	
		var options = this.options, self = this;	
		self.element
		.keydown( function(e){ 
			if (!options.disabled) {
				switch (e.keyCode) {
					// go to next page
					case $.ui.keyCode.DOWN:
					case $.ui.keyCode.PAGE_DOWN:
						// check if new value is in range and if there are any pages to show
						if (options.rowToStart < options.tableData.length-1 && options.rowsToShow != options.tableData.length)  self.setHTML(options.rowToStart + options.rowsToShow);
						break;
					// go to previous page
					case $.ui.keyCode.UP:
					case $.ui.keyCode.PAGE_UP:
						// check if new value is in range and if there are any pages to show
						if (options.rowToStart > 0 + options.rowsToShow && options.rowsToShow != options.tableData.length) self.setHTML(options.rowToStart - options.rowsToShow); 
						break;
					// go to first page
					case $.ui.keyCode.HOME:
						// check if there are any pages to show
						if (options.rowsToShow != options.tableData.length)	self.setHTML(1);
						break;
					// go to last page
					case $.ui.keyCode.END:
						// check if there are any pages to show
						if (options.rowsToShow != options.tableData.length) self.setHTML(((Math.ceil(options.tableData.length / options.rowsToShow)) * options.rowsToShow) - options.rowsToShow + 1);
						break;
					// go to next or previous page
					case $.ui.keyCode.TAB:
						if (e.shiftKey) { 
							if (options.selectedCol > 0) { self.colSwitch(-1); } else { return true; }
						} else { 
							if (options.selectedCol < self._getVisible(options.headers).length-1) { self.colSwitch(1); } else { return true; }
						}			
						break;
					// switch to left col
					case $.ui.keyCode.LEFT:
						if (options.selectedCol > 0) self.colSwitch(-1);	
						break;	
					// switch to right col
					case $.ui.keyCode.RIGHT:
						if (options.selectedCol < self._getVisible(options.headers).length-1) self.colSwitch(1);
						break;	
					// start sorting
					case $.ui.keyCode.SPACE:
						var th = self._getVisible(options.headers);
						$(th[options.selectedCol]).find("a").click();
						break;
					default:
						return true;
						break;
				}
				return false;	
			}
		});
	},
	// switchh selected col
	colSwitch: function (dir) {
		var options = this.options, self = this;
		// get visible headers
		var thArray = self._getVisible(options.headers);
		// remove old selected col css class
		$(thArray[options.selectedCol]).removeClass("ui-state-focus");
		// set new selected col
		options.selectedCol = options.selectedCol + dir;
		// get new selected col
		el = $(thArray[options.selectedCol]);
		// set new focus
		el.addClass("ui-state-focus");
		// set focus 
		if (el.find("a").length) { el.find("a").focus(); } else { el.focus(); }
	},
	// removes instance and attributes
	destroy: function() {
		this.element
		.unbind(".ariaSorTable")
		// remove data
		.removeData('ariaSorTable')
		// remove attributes
		.removeAttr("role")
		.removeAttr("aria-readonly")
		.removeAttr("aria-labelledby")		
			// remove attributes of the caption
			.find("caption").removeAttr("id")			
		// remove ARIA attributes from head element
		.end().find("thead")		
		.removeAttr("aria-live")
		.removeAttr("aria-relevant")		
			// remove event and role of the tr and show them all
			.find("tr")
			.removeAttr("role")
			.unbind("click")
			.end().end()			
		// remove injected HTML
		.find("tbody.ui-table-tbody-active").remove().end()		
		// show hidden original html
		.find("tbody").show();				
		// th's
		$.each(this.options.headers, function() {
			$(this)
			.show()
			.removeAttr("id")
			.removeAttr("role")
			.removeAttr("aria-sort")
			.removeAttr("tabindex")
			.removeAttr("scope");
			// search for added links and delete them | remove event
			var link = $(this).children("a");
			if (link.length) {
				link.unbind("mouseenter mouseleave").removeAttr("title");
				if (link.attr("href") == "#ui-table-dummy")	$(this).html(link.html());
			}
		});		
		// pager
		if (this.options.pager) $("#ui-table-pager").remove();
		// remove virtual buffer form
		$("body>form #virtualBufferForm").parent().remove();
		// call widget destroy function
		$.widget.prototype.destroy.apply(this, arguments);
	},	
	
	// updates virtual buffer | for older screenreader
	_updateVirtualBuffer: function() {
		var form = $("body>form #virtualBufferForm");		
		if(form.length) {
			(form.val() == "1") ? form.val("0") : form.val("1");
		} else {
			var html = '<form><input id="virtualBufferForm" type="hidden" value="1" /></form>';
			$("body").append(html);
		}
	}
});

$.fn.extend($.ui.ariaSorTable.prototype,{
	// this code is only needed if you like to use the pager, otherwise: delete it
	// build a pager
	buildPager: function () {		
		var options = this.options, self = this;
		// build html to inject
		var site = 0;
		var y = 0;
		var html = 	'<div class="ui-table-pager" aria-valuemin="1" aria-controls="ui-table-'+options.uid+'">'+"\n";
			html += 	'<span id="ui-table-'+options.uid+'-pager-title" class="ui-corner-all">'+options.textPager+'</span>'+"\n";						
		while (y < options.tableData.length){
			site++;			
			html += '	<button title="'+options.textPager+' '+ site +'" type="button" class="ui-state-default ui-corner-all" aria-selected="false" aria-labelledby="ui-table-'+options.uid+'-pager-title">'+ site +'</button>'+"\n";
			y = y + options.rowsToShow;
		}
			html += '</div>'+"\n";

		options.pager = self.element.next(".ui-table-pager");	
		if (options.pager.length) options.pager.replaceWith(html);
		else self.element.after(html);
		// ARIA
		options.pager = self.element.next(".ui-table-pager")
		.attr("aria-valuemax", site);
		
		// set events | change css classes and sort table
		options.pagerButtons = options.pager.find("button")
		.each( function(index) {
			$(this)
			.bind("click", function(){ 
				// calculate new start position
				var newRowToStart = (options.rowsToShow * index == 0) ? 1 : (options.rowsToShow * index)+1;				
				// set new html
				self.setHTML(newRowToStart);
			})
			.bind("mouseenter", function(){ $(this).addClass('ui-state-hover'); })
			.bind("mouseleave", function(){ $(this).removeClass('ui-state-hover'); })
			.bind("focus", function(){ $(this).addClass('ui-state-focus'); })
			.bind("blur", function(){ $(this).removeClass('ui-state-focus'); });
		});	
		// set active button after set events
		self.setPager(options.rowToStart);
	},	
	
	// sets active page | call befor setting new options.rowToStart with new row as parameter
	setPager: function (newRow) {		
		var options = this.options, self = this;
		// calculate new start point and add or remove css classes and ARIA attributes
		$(options.pagerButtons[Math.floor(options.rowToStart/options.rowsToShow)]).removeClass('ui-state-active').attr("aria-selected", false);				
		$(options.pagerButtons[Math.floor(newRow/options.rowsToShow)]).addClass('ui-state-active').attr("aria-selected", true);
		options.pager.attr("aria-valuenow", Math.floor(newRow/options.rowsToShow)+1);
	},
	
	// this code is only needed if you like to use the jQuery Address support, otherwise: delete it
	_jqAddressHelper: function (path) {
		var options = this.options, self = this;
		// check if anchor has valid values
		if (path != "" && path[0] == options.uid) {
			var start = parseInt(path[1]);
			var end = parseInt(path[2]);				
			// make this anchor control more fault-tolerant
			if (isNaN(start)) {
				return false;
			} // -> start is a number			
			if (start <=  options.tableData.length) {	
				// is end a number?
				// start shall not be bigger than end
				if (isNaN(end) || start > end) {
					return start;
				} // else -> both are valid numbers				
				
				var range = end - (start - 1);				
				// no need to update if already choosen rows should be displayed
				if (options.rowToStart == start && options.rowsToShow == range) return false;
										
				if (options.jqAddress.changeRow) {
					var temp_rowsToShow = options.rowsToShow;
					options.rowsToShow = range;
					// if we changed rows we need to rebuild pager
					if (options.pager && temp_rowsToShow != options.rowsToShow) self.buildPager();
				}
				return start;			
			} 								
		}
		return false;		
	}
});

})(jQuery);
// </nowiki>