Index: src/webapp/standalone-demos/keyboard-a11y/html/CheckboxExample.html =================================================================== --- src/webapp/standalone-demos/keyboard-a11y/html/CheckboxExample.html (revision 9725) +++ src/webapp/standalone-demos/keyboard-a11y/html/CheckboxExample.html (working copy) @@ -4,7 +4,7 @@ - + Index: src/webapp/standalone-demos/keyboard-a11y/html/jquery-ui-accessible-tabs.html =================================================================== --- src/webapp/standalone-demos/keyboard-a11y/html/jquery-ui-accessible-tabs.html (revision 9725) +++ src/webapp/standalone-demos/keyboard-a11y/html/jquery-ui-accessible-tabs.html (working copy) @@ -2,12 +2,13 @@ Accessible jQuery UI Tabs - - + + - - + + + @@ -21,30 +22,30 @@ Select on Focus: Disabled

- - - - - -
-
- Cats meow. -
-
- Dogs bark. -
-
- Hamsters wheel. -
-
- Alligators bite. -
-
- +
+ + + + +
+
+ Cats meow. +
+
+ Dogs bark. +
+
+ Hamsters wheel. +
+
+ Alligators bite. +
+
+
Index: src/webapp/standalone-demos/keyboard-a11y/js/jquery-ui-accessible-tabs.js =================================================================== --- src/webapp/standalone-demos/keyboard-a11y/js/jquery-ui-accessible-tabs.js (revision 9725) +++ src/webapp/standalone-demos/keyboard-a11y/js/jquery-ui-accessible-tabs.js (working copy) @@ -75,14 +75,14 @@ }; // Public API. - fluid.accessibletabs = function (tabsId, panelsId) { + fluid.accessibletabs = function (container, tabsId, panelsId) { var tablist = $("#" + tabsId); // Remove the anchors in the list from the tab order. fluid.tabindex(tablist.find("a"), -1); // Turn the list into a jQuery UI tabs widget. - tablist.tabs(); + $(container).tabs(); // Make them accessible. makeTabsSelectable(tablist); @@ -94,7 +94,7 @@ selectOnFocus = false; // Instantiate the tabs widget. - fluid.accessibletabs("tabs", "panels"); + fluid.accessibletabs("#tabs-container", "tabs", "panels"); // Bind the select on focus link. $("#selectOnFocusLink").click(function (evt) { Index: src/webapp/standalone-demos/lib/jquery/js/jquery.ui.tabs.js =================================================================== --- src/webapp/standalone-demos/lib/jquery/js/jquery.ui.tabs.js (revision 0) +++ src/webapp/standalone-demos/lib/jquery/js/jquery.ui.tabs.js (revision 0) @@ -0,0 +1,721 @@ +/* + * jQuery UI Tabs 1.8 + * + * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Tabs + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + */ +(function($) { + +var tabId = 0, + listId = 0; + +$.widget("ui.tabs", { + options: { + add: null, + ajaxOptions: null, + cache: false, + cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } + collapsible: false, + disable: null, + disabled: [], + enable: null, + event: 'click', + fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 } + idPrefix: 'ui-tabs-', + load: null, + panelTemplate: '
', + remove: null, + select: null, + show: null, + spinner: 'Loading…', + tabTemplate: '
  • #{label}
  • ' + }, + _create: function() { + this._tabify(true); + }, + + _setOption: function(key, value) { + if (key == 'selected') { + if (this.options.collapsible && value == this.options.selected) { + return; + } + this.select(value); + } + else { + this.options[key] = value; + this._tabify(); + } + }, + + _tabId: function(a) { + return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '') || + this.options.idPrefix + (++tabId); + }, + + _sanitizeSelector: function(hash) { + return hash.replace(/:/g, '\\:'); // we need this because an id may contain a ":" + }, + + _cookie: function() { + var cookie = this.cookie || (this.cookie = this.options.cookie.name || 'ui-tabs-' + (++listId)); + return $.cookie.apply(null, [cookie].concat($.makeArray(arguments))); + }, + + _ui: function(tab, panel) { + return { + tab: tab, + panel: panel, + index: this.anchors.index(tab) + }; + }, + + _cleanup: function() { + // restore all former loading tabs labels + this.lis.filter('.ui-state-processing').removeClass('ui-state-processing') + .find('span:data(label.tabs)') + .each(function() { + var el = $(this); + el.html(el.data('label.tabs')).removeData('label.tabs'); + }); + }, + + _tabify: function(init) { + + this.list = this.element.find('ol,ul').eq(0); + this.lis = $('li:has(a[href])', this.list); + this.anchors = this.lis.map(function() { return $('a', this)[0]; }); + this.panels = $([]); + + var self = this, o = this.options; + + var fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash + this.anchors.each(function(i, a) { + var href = $(a).attr('href'); + + // For dynamically created HTML that contains a hash as href IE < 8 expands + // such href to the full page url with hash and then misinterprets tab as ajax. + // Same consideration applies for an added tab with a fragment identifier + // since a[href=#fragment-identifier] does unexpectedly not match. + // Thus normalize href attribute... + var hrefBase = href.split('#')[0], baseEl; + if (hrefBase && (hrefBase === location.toString().split('#')[0] || + (baseEl = $('base')[0]) && hrefBase === baseEl.href)) { + href = a.hash; + a.href = href; + } + + // inline tab + if (fragmentId.test(href)) { + self.panels = self.panels.add(self._sanitizeSelector(href)); + } + + // remote tab + else if (href != '#') { // prevent loading the page itself if href is just "#" + $.data(a, 'href.tabs', href); // required for restore on destroy + + // TODO until #3808 is fixed strip fragment identifier from url + // (IE fails to load from such url) + $.data(a, 'load.tabs', href.replace(/#.*$/, '')); // mutable data + + var id = self._tabId(a); + a.href = '#' + id; + var $panel = $('#' + id); + if (!$panel.length) { + $panel = $(o.panelTemplate).attr('id', id).addClass('ui-tabs-panel ui-widget-content ui-corner-bottom') + .insertAfter(self.panels[i - 1] || self.list); + $panel.data('destroy.tabs', true); + } + self.panels = self.panels.add($panel); + } + + // invalid tab href + else { + o.disabled.push(i); + } + }); + + // initialization from scratch + if (init) { + + // attach necessary classes for styling + this.element.addClass('ui-tabs ui-widget ui-widget-content ui-corner-all'); + this.list.addClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all'); + this.lis.addClass('ui-state-default ui-corner-top'); + this.panels.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom'); + + // Selected tab + // use "selected" option or try to retrieve: + // 1. from fragment identifier in url + // 2. from cookie + // 3. from selected class attribute on
  • + if (o.selected === undefined) { + if (location.hash) { + this.anchors.each(function(i, a) { + if (a.hash == location.hash) { + o.selected = i; + return false; // break + } + }); + } + if (typeof o.selected != 'number' && o.cookie) { + o.selected = parseInt(self._cookie(), 10); + } + if (typeof o.selected != 'number' && this.lis.filter('.ui-tabs-selected').length) { + o.selected = this.lis.index(this.lis.filter('.ui-tabs-selected')); + } + o.selected = o.selected || (this.lis.length ? 0 : -1); + } + else if (o.selected === null) { // usage of null is deprecated, TODO remove in next release + o.selected = -1; + } + + // sanity check - default to first tab... + o.selected = ((o.selected >= 0 && this.anchors[o.selected]) || o.selected < 0) ? o.selected : 0; + + // Take disabling tabs via class attribute from HTML + // into account and update option properly. + // A selected tab cannot become disabled. + o.disabled = $.unique(o.disabled.concat( + $.map(this.lis.filter('.ui-state-disabled'), + function(n, i) { return self.lis.index(n); } ) + )).sort(); + + if ($.inArray(o.selected, o.disabled) != -1) { + o.disabled.splice($.inArray(o.selected, o.disabled), 1); + } + + // highlight selected tab + this.panels.addClass('ui-tabs-hide'); + this.lis.removeClass('ui-tabs-selected ui-state-active'); + if (o.selected >= 0 && this.anchors.length) { // check for length avoids error when initializing empty list + this.panels.eq(o.selected).removeClass('ui-tabs-hide'); + this.lis.eq(o.selected).addClass('ui-tabs-selected ui-state-active'); + + // seems to be expected behavior that the show callback is fired + self.element.queue("tabs", function() { + self._trigger('show', null, self._ui(self.anchors[o.selected], self.panels[o.selected])); + }); + + this.load(o.selected); + } + + // clean up to avoid memory leaks in certain versions of IE 6 + $(window).bind('unload', function() { + self.lis.add(self.anchors).unbind('.tabs'); + self.lis = self.anchors = self.panels = null; + }); + + } + // update selected after add/remove + else { + o.selected = this.lis.index(this.lis.filter('.ui-tabs-selected')); + } + + // update collapsible + this.element[o.collapsible ? 'addClass' : 'removeClass']('ui-tabs-collapsible'); + + // set or update cookie after init and add/remove respectively + if (o.cookie) { + this._cookie(o.selected, o.cookie); + } + + // disable tabs + for (var i = 0, li; (li = this.lis[i]); i++) { + $(li)[$.inArray(i, o.disabled) != -1 && + !$(li).hasClass('ui-tabs-selected') ? 'addClass' : 'removeClass']('ui-state-disabled'); + } + + // reset cache if switching from cached to not cached + if (o.cache === false) { + this.anchors.removeData('cache.tabs'); + } + + // remove all handlers before, tabify may run on existing tabs after add or option change + this.lis.add(this.anchors).unbind('.tabs'); + + if (o.event != 'mouseover') { + var addState = function(state, el) { + if (el.is(':not(.ui-state-disabled)')) { + el.addClass('ui-state-' + state); + } + }; + var removeState = function(state, el) { + el.removeClass('ui-state-' + state); + }; + this.lis.bind('mouseover.tabs', function() { + addState('hover', $(this)); + }); + this.lis.bind('mouseout.tabs', function() { + removeState('hover', $(this)); + }); + this.anchors.bind('focus.tabs', function() { + addState('focus', $(this).closest('li')); + }); + this.anchors.bind('blur.tabs', function() { + removeState('focus', $(this).closest('li')); + }); + } + + // set up animations + var hideFx, showFx; + if (o.fx) { + if ($.isArray(o.fx)) { + hideFx = o.fx[0]; + showFx = o.fx[1]; + } + else { + hideFx = showFx = o.fx; + } + } + + // Reset certain styles left over from animation + // and prevent IE's ClearType bug... + function resetStyle($el, fx) { + $el.css({ display: '' }); + if (!$.support.opacity && fx.opacity) { + $el[0].style.removeAttribute('filter'); + } + } + + // Show a tab... + var showTab = showFx ? + function(clicked, $show) { + $(clicked).closest('li').addClass('ui-tabs-selected ui-state-active'); + $show.hide().removeClass('ui-tabs-hide') // avoid flicker that way + .animate(showFx, showFx.duration || 'normal', function() { + resetStyle($show, showFx); + self._trigger('show', null, self._ui(clicked, $show[0])); + }); + } : + function(clicked, $show) { + $(clicked).closest('li').addClass('ui-tabs-selected ui-state-active'); + $show.removeClass('ui-tabs-hide'); + self._trigger('show', null, self._ui(clicked, $show[0])); + }; + + // Hide a tab, $show is optional... + var hideTab = hideFx ? + function(clicked, $hide) { + $hide.animate(hideFx, hideFx.duration || 'normal', function() { + self.lis.removeClass('ui-tabs-selected ui-state-active'); + $hide.addClass('ui-tabs-hide'); + resetStyle($hide, hideFx); + self.element.dequeue("tabs"); + }); + } : + function(clicked, $hide, $show) { + self.lis.removeClass('ui-tabs-selected ui-state-active'); + $hide.addClass('ui-tabs-hide'); + self.element.dequeue("tabs"); + }; + + // attach tab event handler, unbind to avoid duplicates from former tabifying... + this.anchors.bind(o.event + '.tabs', function() { + var el = this, $li = $(this).closest('li'), $hide = self.panels.filter(':not(.ui-tabs-hide)'), + $show = $(self._sanitizeSelector(this.hash)); + + // If tab is already selected and not collapsible or tab disabled or + // or is already loading or click callback returns false stop here. + // Check if click handler returns false last so that it is not executed + // for a disabled or loading tab! + if (($li.hasClass('ui-tabs-selected') && !o.collapsible) || + $li.hasClass('ui-state-disabled') || + $li.hasClass('ui-state-processing') || + self._trigger('select', null, self._ui(this, $show[0])) === false) { + this.blur(); + return false; + } + + o.selected = self.anchors.index(this); + + self.abort(); + + // if tab may be closed + if (o.collapsible) { + if ($li.hasClass('ui-tabs-selected')) { + o.selected = -1; + + if (o.cookie) { + self._cookie(o.selected, o.cookie); + } + + self.element.queue("tabs", function() { + hideTab(el, $hide); + }).dequeue("tabs"); + + this.blur(); + return false; + } + else if (!$hide.length) { + if (o.cookie) { + self._cookie(o.selected, o.cookie); + } + + self.element.queue("tabs", function() { + showTab(el, $show); + }); + + self.load(self.anchors.index(this)); // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171 + + this.blur(); + return false; + } + } + + if (o.cookie) { + self._cookie(o.selected, o.cookie); + } + + // show new tab + if ($show.length) { + if ($hide.length) { + self.element.queue("tabs", function() { + hideTab(el, $hide); + }); + } + self.element.queue("tabs", function() { + showTab(el, $show); + }); + + self.load(self.anchors.index(this)); + } + else { + throw 'jQuery UI Tabs: Mismatching fragment identifier.'; + } + + // Prevent IE from keeping other link focussed when using the back button + // and remove dotted border from clicked link. This is controlled via CSS + // in modern browsers; blur() removes focus from address bar in Firefox + // which can become a usability and annoying problem with tabs('rotate'). + if ($.browser.msie) { + this.blur(); + } + + }); + + // disable click in any case + this.anchors.bind('click.tabs', function(){return false;}); + + }, + + destroy: function() { + var o = this.options; + + this.abort(); + + this.element.unbind('.tabs') + .removeClass('ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible') + .removeData('tabs'); + + this.list.removeClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all'); + + this.anchors.each(function() { + var href = $.data(this, 'href.tabs'); + if (href) { + this.href = href; + } + var $this = $(this).unbind('.tabs'); + $.each(['href', 'load', 'cache'], function(i, prefix) { + $this.removeData(prefix + '.tabs'); + }); + }); + + this.lis.unbind('.tabs').add(this.panels).each(function() { + if ($.data(this, 'destroy.tabs')) { + $(this).remove(); + } + else { + $(this).removeClass([ + 'ui-state-default', + 'ui-corner-top', + 'ui-tabs-selected', + 'ui-state-active', + 'ui-state-hover', + 'ui-state-focus', + 'ui-state-disabled', + 'ui-tabs-panel', + 'ui-widget-content', + 'ui-corner-bottom', + 'ui-tabs-hide' + ].join(' ')); + } + }); + + if (o.cookie) { + this._cookie(null, o.cookie); + } + + return this; + }, + + add: function(url, label, index) { + if (index === undefined) { + index = this.anchors.length; // append by default + } + + var self = this, o = this.options, + $li = $(o.tabTemplate.replace(/#\{href\}/g, url).replace(/#\{label\}/g, label)), + id = !url.indexOf('#') ? url.replace('#', '') : this._tabId($('a', $li)[0]); + + $li.addClass('ui-state-default ui-corner-top').data('destroy.tabs', true); + + // try to find an existing element before creating a new one + var $panel = $('#' + id); + if (!$panel.length) { + $panel = $(o.panelTemplate).attr('id', id).data('destroy.tabs', true); + } + $panel.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide'); + + if (index >= this.lis.length) { + $li.appendTo(this.list); + $panel.appendTo(this.list[0].parentNode); + } + else { + $li.insertBefore(this.lis[index]); + $panel.insertBefore(this.panels[index]); + } + + o.disabled = $.map(o.disabled, + function(n, i) { return n >= index ? ++n : n; }); + + this._tabify(); + + if (this.anchors.length == 1) { // after tabify + o.selected = 0; + $li.addClass('ui-tabs-selected ui-state-active'); + $panel.removeClass('ui-tabs-hide'); + this.element.queue("tabs", function() { + self._trigger('show', null, self._ui(self.anchors[0], self.panels[0])); + }); + + this.load(0); + } + + // callback + this._trigger('add', null, this._ui(this.anchors[index], this.panels[index])); + return this; + }, + + remove: function(index) { + var o = this.options, $li = this.lis.eq(index).remove(), + $panel = this.panels.eq(index).remove(); + + // If selected tab was removed focus tab to the right or + // in case the last tab was removed the tab to the left. + if ($li.hasClass('ui-tabs-selected') && this.anchors.length > 1) { + this.select(index + (index + 1 < this.anchors.length ? 1 : -1)); + } + + o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }), + function(n, i) { return n >= index ? --n : n; }); + + this._tabify(); + + // callback + this._trigger('remove', null, this._ui($li.find('a')[0], $panel[0])); + return this; + }, + + enable: function(index) { + var o = this.options; + if ($.inArray(index, o.disabled) == -1) { + return; + } + + this.lis.eq(index).removeClass('ui-state-disabled'); + o.disabled = $.grep(o.disabled, function(n, i) { return n != index; }); + + // callback + this._trigger('enable', null, this._ui(this.anchors[index], this.panels[index])); + return this; + }, + + disable: function(index) { + var self = this, o = this.options; + if (index != o.selected) { // cannot disable already selected tab + this.lis.eq(index).addClass('ui-state-disabled'); + + o.disabled.push(index); + o.disabled.sort(); + + // callback + this._trigger('disable', null, this._ui(this.anchors[index], this.panels[index])); + } + + return this; + }, + + select: function(index) { + if (typeof index == 'string') { + index = this.anchors.index(this.anchors.filter('[href$=' + index + ']')); + } + else if (index === null) { // usage of null is deprecated, TODO remove in next release + index = -1; + } + if (index == -1 && this.options.collapsible) { + index = this.options.selected; + } + + this.anchors.eq(index).trigger(this.options.event + '.tabs'); + return this; + }, + + load: function(index) { + var self = this, o = this.options, a = this.anchors.eq(index)[0], url = $.data(a, 'load.tabs'); + + this.abort(); + + // not remote or from cache + if (!url || this.element.queue("tabs").length !== 0 && $.data(a, 'cache.tabs')) { + this.element.dequeue("tabs"); + return; + } + + // load remote from here on + this.lis.eq(index).addClass('ui-state-processing'); + + if (o.spinner) { + var span = $('span', a); + span.data('label.tabs', span.html()).html(o.spinner); + } + + this.xhr = $.ajax($.extend({}, o.ajaxOptions, { + url: url, + success: function(r, s) { + $(self._sanitizeSelector(a.hash)).html(r); + + // take care of tab labels + self._cleanup(); + + if (o.cache) { + $.data(a, 'cache.tabs', true); // if loaded once do not load them again + } + + // callbacks + self._trigger('load', null, self._ui(self.anchors[index], self.panels[index])); + try { + o.ajaxOptions.success(r, s); + } + catch (e) {} + }, + error: function(xhr, s, e) { + // take care of tab labels + self._cleanup(); + + // callbacks + self._trigger('load', null, self._ui(self.anchors[index], self.panels[index])); + try { + // Passing index avoid a race condition when this method is + // called after the user has selected another tab. + // Pass the anchor that initiated this request allows + // loadError to manipulate the tab content panel via $(a.hash) + o.ajaxOptions.error(xhr, s, index, a); + } + catch (e) {} + } + })); + + // last, so that load event is fired before show... + self.element.dequeue("tabs"); + + return this; + }, + + abort: function() { + // stop possibly running animations + this.element.queue([]); + this.panels.stop(false, true); + + // "tabs" queue must not contain more than two elements, + // which are the callbacks for the latest clicked tab... + this.element.queue("tabs", this.element.queue("tabs").splice(-2, 2)); + + // terminate pending requests from other tabs + if (this.xhr) { + this.xhr.abort(); + delete this.xhr; + } + + // take care of tab labels + this._cleanup(); + return this; + }, + + url: function(index, url) { + this.anchors.eq(index).removeData('cache.tabs').data('load.tabs', url); + return this; + }, + + length: function() { + return this.anchors.length; + } + +}); + +$.extend($.ui.tabs, { + version: '1.8' +}); + +/* + * Tabs Extensions + */ + +/* + * Rotate + */ +$.extend($.ui.tabs.prototype, { + rotation: null, + rotate: function(ms, continuing) { + + var self = this, o = this.options; + + var rotate = self._rotate || (self._rotate = function(e) { + clearTimeout(self.rotation); + self.rotation = setTimeout(function() { + var t = o.selected; + self.select( ++t < self.anchors.length ? t : 0 ); + }, ms); + + if (e) { + e.stopPropagation(); + } + }); + + var stop = self._unrotate || (self._unrotate = !continuing ? + function(e) { + if (e.clientX) { // in case of a true click + self.rotate(null); + } + } : + function(e) { + t = o.selected; + rotate(); + }); + + // start rotation + if (ms) { + this.element.bind('tabsshow', rotate); + this.anchors.bind(o.event + '.tabs', stop); + rotate(); + } + // stop rotation + else { + clearTimeout(self.rotation); + this.element.unbind('tabsshow', rotate); + this.anchors.unbind(o.event + '.tabs', stop); + delete this._rotate; + delete this._unrotate; + } + + return this; + } +}); + +})(jQuery); Index: src/webapp/standalone-demos/lib/jquery/js/ui.tabs.js =================================================================== --- src/webapp/standalone-demos/lib/jquery/js/ui.tabs.js (revision 9725) +++ src/webapp/standalone-demos/lib/jquery/js/ui.tabs.js (working copy) @@ -1,615 +0,0 @@ -/* - * jQuery UI Tabs 1.6rc6 - * - * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Tabs - * - * Depends: - * ui.core.js - */ -(function($) { - -$.widget("ui.tabs", { - - _init: function() { - // create tabs - this._tabify(true); - }, - - _setData: function(key, value) { - if ((/^selected/).test(key)) - this.select(value); - else { - this.options[key] = value; - this._tabify(); - } - }, - - _tabId: function(a) { - return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '') - || this.options.idPrefix + $.data(a); - }, - - _sanitizeSelector: function(hash) { - return hash.replace(/:/g, '\\:'); // we need this because an id may contain a ":" - }, - - _cookie: function() { - var cookie = this.cookie || (this.cookie = this.options.cookie.name || 'ui-tabs-' + $.data(this.list[0])); - return $.cookie.apply(null, [cookie].concat($.makeArray(arguments))); - }, - - _ui: function(tab, panel) { - return { - tab: tab, - panel: panel, - index: this.$tabs.index(tab) - }; - }, - - _tabify: function(init) { - - this.list = this.element.is('div') ? this.element.children('ul:first, ol:first').eq(0) : this.element; - this.$lis = $('li:has(a[href])', this.list); - this.$tabs = this.$lis.map(function() { return $('a', this)[0]; }); - this.$panels = $([]); - - var self = this, o = this.options; - - var fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash - this.$tabs.each(function(i, a) { - var href = $(a).attr('href'); - - // inline tab - if (fragmentId.test(href)) - self.$panels = self.$panels.add(self._sanitizeSelector(href)); - - // remote tab - else if (href != '#') { // prevent loading the page itself if href is just "#" - $.data(a, 'href.tabs', href); // required for restore on destroy - - // TODO until #3808 is fixed strip fragment identifier from url - // (IE fails to load from such url) - $.data(a, 'load.tabs', href.replace(/#.*$/, '')); // mutable data - - var id = self._tabId(a); - a.href = '#' + id; - var $panel = $('#' + id); - if (!$panel.length) { - $panel = $(o.panelTemplate).attr('id', id).addClass('ui-tabs-panel ui-widget-content ui-corner-bottom') - .insertAfter(self.$panels[i - 1] || self.list); - $panel.data('destroy.tabs', true); - } - self.$panels = self.$panels.add($panel); - } - - // invalid tab href - else - o.disabled.push(i + 1); - }); - - // initialization from scratch - if (init) { - - // attach necessary classes for styling - if (this.element.is('div')) { - this.element.addClass('ui-tabs ui-widget ui-widget-content ui-corner-all'); - } - this.list.addClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all'); - this.$lis.addClass('ui-state-default ui-corner-top'); - this.$panels.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom'); - - // Selected tab - // use "selected" option or try to retrieve: - // 1. from fragment identifier in url - // 2. from cookie - // 3. from selected class attribute on
  • - if (o.selected === undefined) { - if (location.hash) { - this.$tabs.each(function(i, a) { - if (a.hash == location.hash) { - o.selected = i; - return false; // break - } - }); - } - else if (o.cookie) - o.selected = parseInt(self._cookie(), 10); - - else if (this.$lis.filter('.ui-tabs-selected').length) - o.selected = this.$lis.index(this.$lis.filter('.ui-tabs-selected')); - - else - o.selected = 0; - - } - else if (o.selected === null) - o.selected = -1; - - // sanity check - o.selected = ((o.selected >= 0 && this.$tabs[o.selected]) || o.selected < 0) ? o.selected : 0; // default to first tab - - // Take disabling tabs via class attribute from HTML - // into account and update option properly. - // A selected tab cannot become disabled. - o.disabled = $.unique(o.disabled.concat( - $.map(this.$lis.filter('.ui-state-disabled'), - function(n, i) { return self.$lis.index(n); } ) - )).sort(); - if ($.inArray(o.selected, o.disabled) != -1) - o.disabled.splice($.inArray(o.selected, o.disabled), 1); - - // highlight selected tab - this.$panels.addClass('ui-tabs-hide'); - this.$lis.removeClass('ui-tabs-selected ui-state-active'); - if (o.selected >= 0 && this.$tabs.length) { // check for length avoids error when initializing empty list - this.$panels.eq(o.selected).removeClass('ui-tabs-hide'); - var classes = ['ui-tabs-selected ui-state-active']; - if (o.deselectable) classes.push('ui-tabs-deselectable'); - this.$lis.eq(o.selected).addClass(classes.join(' ')); - - // seems to be expected behavior that the show callback is fired - var onShow = function() { - self._trigger('show', null, - self._ui(self.$tabs[o.selected], self.$panels[o.selected])); - }; - - // load if remote tab - if ($.data(this.$tabs[o.selected], 'load.tabs')) - this.load(o.selected, onShow); - // just trigger show event - else onShow(); - } - - // states - if (o.event != 'mouseover') { - var handleState = function(state, el) { - if (el.is(':not(.ui-state-disabled)')) el.toggleClass('ui-state-' + state); - }; - this.$lis.bind('mouseover.tabs mouseout.tabs', function() { - handleState('hover', $(this)); - }); - // TODO focus/blur don't seem to work with namespace - this.$tabs.bind('focus.tabs blur.tabs', function() { - handleState('focus', $(this).parents('li:first')); - }); - } - - // clean up to avoid memory leaks in certain versions of IE 6 - $(window).bind('unload', function() { - self.$lis.add(self.$tabs).unbind('.tabs'); - self.$lis = self.$tabs = self.$panels = null; - }); - - } - // update selected after add/remove - else - o.selected = this.$lis.index(this.$lis.filter('.ui-tabs-selected')); - - // set or update cookie after init and add/remove respectively - if (o.cookie) this._cookie(o.selected, o.cookie); - - // disable tabs - for (var i = 0, li; li = this.$lis[i]; i++) - $(li)[$.inArray(i, o.disabled) != -1 && !$(li).hasClass('ui-tabs-selected') ? 'addClass' : 'removeClass']('ui-state-disabled'); - - // reset cache if switching from cached to not cached - if (o.cache === false) this.$tabs.removeData('cache.tabs'); - - // set up animations - var hideFx, showFx; - if (o.fx) { - if ($.isArray(o.fx)) { - hideFx = o.fx[0]; - showFx = o.fx[1]; - } - else hideFx = showFx = o.fx; - } - - // Reset certain styles left over from animation - // and prevent IE's ClearType bug... - function resetStyle($el, fx) { - $el.css({ display: '' }); - if ($.browser.msie && fx.opacity) $el[0].style.removeAttribute('filter'); - } - - // Show a tab... - var showTab = showFx ? - function(clicked, $show) { - $show.hide().removeClass('ui-tabs-hide') // avoid flicker that way - .animate(showFx, 500, function() { - resetStyle($show, showFx); - self._trigger('show', null, self._ui(clicked, $show[0])); - }); - } : - function(clicked, $show) { - $show.removeClass('ui-tabs-hide'); - self._trigger('show', null, self._ui(clicked, $show[0])); - }; - - // Hide a tab, $show is optional... - var hideTab = hideFx ? - function(clicked, $hide, $show) { - $hide.animate(hideFx, hideFx.duration || 'normal', function() { - $hide.addClass('ui-tabs-hide'); - resetStyle($hide, hideFx); - if ($show) showTab(clicked, $show); - }); - } : - function(clicked, $hide, $show) { - $hide.addClass('ui-tabs-hide'); - if ($show) showTab(clicked, $show); - }; - - // Switch a tab... - function switchTab(clicked, $li, $hide, $show) { - var classes = ['ui-tabs-selected ui-state-active']; - if (o.deselectable) classes.push('ui-tabs-deselectable'); - $li.removeClass('ui-state-default').addClass(classes.join(' ')) - .siblings().removeClass(classes.join(' ')).addClass('ui-state-default'); - hideTab(clicked, $hide, $show); - } - - // attach tab event handler, unbind to avoid duplicates from former tabifying... - this.$tabs.unbind('.tabs').bind(o.event + '.tabs', function() { - - var $li = $(this).parents('li:eq(0)'), - $hide = self.$panels.filter(':visible'), - $show = $(self._sanitizeSelector(this.hash)); - - // If tab is already selected and not deselectable or tab disabled or - // or is already loading or click callback returns false stop here. - // Check if click handler returns false last so that it is not executed - // for a disabled or loading tab! - if (($li.hasClass('ui-state-active') && !o.deselectable) - || $li.hasClass('ui-state-disabled') - || $(this).hasClass('ui-tabs-loading') - || self._trigger('select', null, self._ui(this, $show[0])) === false - ) { - this.blur(); - return false; - } - - o.selected = self.$tabs.index(this); - - // if tab may be closed TODO avoid redundant code in this block - if (o.deselectable) { - if ($li.hasClass('ui-state-active')) { - o.selected = -1; - if (o.cookie) self._cookie(o.selected, o.cookie); - $li.removeClass('ui-tabs-selected ui-state-active ui-tabs-deselectable') - .addClass('ui-state-default'); - self.$panels.stop(); - hideTab(this, $hide); - this.blur(); - return false; - } else if (!$hide.length) { - if (o.cookie) self._cookie(o.selected, o.cookie); - self.$panels.stop(); - var a = this; - self.load(self.$tabs.index(this), function() { - $li.addClass('ui-tabs-selected ui-state-active ui-tabs-deselectable') - .removeClass('ui-state-default'); - showTab(a, $show); - }); - this.blur(); - return false; - } - } - - if (o.cookie) self._cookie(o.selected, o.cookie); - - // stop possibly running animations - self.$panels.stop(); - - // show new tab - if ($show.length) { - var a = this; - self.load(self.$tabs.index(this), $hide.length ? - function() { - switchTab(a, $li, $hide, $show); - } : - function() { - $li.addClass('ui-tabs-selected ui-state-active').removeClass('ui-state-default'); - showTab(a, $show); - } - ); - } else - throw 'jQuery UI Tabs: Mismatching fragment identifier.'; - - // Prevent IE from keeping other link focussed when using the back button - // and remove dotted border from clicked link. This is controlled via CSS - // in modern browsers; blur() removes focus from address bar in Firefox - // which can become a usability and annoying problem with tabs('rotate'). - if ($.browser.msie) this.blur(); - - return false; - - }); - - // disable click if event is configured to something else - if (o.event != 'click') this.$tabs.bind('click.tabs', function(){return false;}); - - }, - - destroy: function() { - var o = this.options; - - this.element - .removeClass('ui-tabs ui-widget ui-widget-content ui-corner-all'); - - this.list.unbind('.tabs') - .removeClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all') - .removeData('tabs'); - - this.$tabs.each(function() { - var href = $.data(this, 'href.tabs'); - if (href) - this.href = href; - var $this = $(this).unbind('.tabs'); - $.each(['href', 'load', 'cache'], function(i, prefix) { - $this.removeData(prefix + '.tabs'); - }); - }); - - this.$lis.unbind('.tabs').add(this.$panels).each(function() { - if ($.data(this, 'destroy.tabs')) - $(this).remove(); - else - $(this).removeClass( - 'ui-state-default ' + - 'ui-corner-top ' + - 'ui-tabs-selected ' + - 'ui-state-active ' + - 'ui-tabs-deselectable ' + - 'ui-state-disabled ' + - 'ui-tabs-panel ' + - 'ui-widget-content ' + - 'ui-corner-bottom ' + - 'ui-tabs-hide'); - }); - - if (o.cookie) - this._cookie(null, o.cookie); - }, - - add: function(url, label, index) { - if (index == undefined) - index = this.$tabs.length; // append by default - - var self = this, o = this.options; - var $li = $(o.tabTemplate.replace(/#\{href\}/g, url).replace(/#\{label\}/g, label)); - $li.addClass('ui-state-default ui-corner-top').data('destroy.tabs', true); - - var id = url.indexOf('#') == 0 ? url.replace('#', '') : this._tabId( $('a:first-child', $li)[0] ); - - // try to find an existing element before creating a new one - var $panel = $('#' + id); - if (!$panel.length) { - $panel = $(o.panelTemplate).attr('id', id).data('destroy.tabs', true); - } - $panel.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide'); - if (index >= this.$lis.length) { - $li.appendTo(this.list); - $panel.appendTo(this.list[0].parentNode); - } - else { - $li.insertBefore(this.$lis[index]); - $panel.insertBefore(this.$panels[index]); - } - - o.disabled = $.map(o.disabled, - function(n, i) { return n >= index ? ++n : n }); - - this._tabify(); - - if (this.$tabs.length == 1) { // after tabify - $li.addClass('ui-tabs-selected ui-state-active'); - $panel.removeClass('ui-tabs-hide'); - var href = $.data(this.$tabs[0], 'load.tabs'); - if (href) this.load(0, function() { - self._trigger('show', null, - self._ui(self.$tabs[0], self.$panels[0])); - }); - } - - // callback - this._trigger('add', null, this._ui(this.$tabs[index], this.$panels[index])); - }, - - remove: function(index) { - var o = this.options, $li = this.$lis.eq(index).remove(), - $panel = this.$panels.eq(index).remove(); - - // If selected tab was removed focus tab to the right or - // in case the last tab was removed the tab to the left. - if ($li.hasClass('ui-tabs-selected') && this.$tabs.length > 1) - this.select(index + (index + 1 < this.$tabs.length ? 1 : -1)); - - o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }), - function(n, i) { return n >= index ? --n : n }); - - this._tabify(); - - // callback - this._trigger('remove', null, this._ui($li.find('a')[0], $panel[0])); - }, - - enable: function(index) { - var o = this.options; - if ($.inArray(index, o.disabled) == -1) - return; - - this.$lis.eq(index).removeClass('ui-state-disabled'); - o.disabled = $.grep(o.disabled, function(n, i) { return n != index; }); - - // callback - this._trigger('enable', null, this._ui(this.$tabs[index], this.$panels[index])); - }, - - disable: function(index) { - var self = this, o = this.options; - if (index != o.selected) { // cannot disable already selected tab - this.$lis.eq(index).addClass('ui-state-disabled'); - - o.disabled.push(index); - o.disabled.sort(); - - // callback - this._trigger('disable', null, this._ui(this.$tabs[index], this.$panels[index])); - } - }, - - select: function(index) { - if (typeof index == 'string') - index = this.$tabs.index(this.$tabs.filter('[href$=' + index + ']')); - this.$tabs.eq(index).trigger(this.options.event + '.tabs'); - }, - - load: function(index, callback) { // callback is for internal usage only - - var self = this, o = this.options, $a = this.$tabs.eq(index), a = $a[0], - bypassCache = callback == undefined || callback === false, url = $a.data('load.tabs'); - // TODO bypassCache == false should work - - callback = callback || function() {}; - - // no remote or from cache - just finish with callback - // TODO in any case: insert cancel running load here..! - - if (!url || !bypassCache && $.data(a, 'cache.tabs')) { - callback(); - return; - } - - // load remote from here on - - var inner = function(parent) { - var $parent = $(parent), $inner = $parent.find('*:last'); - return $inner.length && $inner.is(':not(img)') && $inner || $parent; - }; - var cleanup = function() { - self.$tabs.filter('.ui-tabs-loading').removeClass('ui-tabs-loading') - .each(function() { - if (o.spinner) - inner(this).parent().html(inner(this).data('label.tabs')); - }); - self.xhr = null; - }; - - if (o.spinner) { - var label = inner(a).html(); - inner(a).wrapInner('') - .find('em').data('label.tabs', label).html(o.spinner); - } - - var ajaxOptions = $.extend({}, o.ajaxOptions, { - url: url, - success: function(r, s) { - $(self._sanitizeSelector(a.hash)).html(r); - cleanup(); - - if (o.cache) - $.data(a, 'cache.tabs', true); // if loaded once do not load them again - - // callbacks - self._trigger('load', null, self._ui(self.$tabs[index], self.$panels[index])); - try { - o.ajaxOptions.success(r, s); - } - catch (er) {} - - // This callback is required because the switch has to take - // place after loading has completed. Call last in order to - // fire load before show callback... - callback(); - } - }); - if (this.xhr) { - // terminate pending requests from other tabs and restore tab label - this.xhr.abort(); - cleanup(); - } - $a.addClass('ui-tabs-loading'); - self.xhr = $.ajax(ajaxOptions); - }, - - url: function(index, url) { - this.$tabs.eq(index).removeData('cache.tabs').data('load.tabs', url); - }, - - length: function() { - return this.$tabs.length; - } - -}); - -$.extend($.ui.tabs, { - version: '1.6rc6', - getter: 'length', - defaults: { - ajaxOptions: null, - cache: false, - cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } - deselectable: false, - disabled: [], - event: 'click', - fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 } - idPrefix: 'ui-tabs-', - panelTemplate: '
    ', - spinner: 'Loading…', - tabTemplate: '
  • #{label}
  • ' - } -}); - -/* - * Tabs Extensions - */ - -/* - * Rotate - */ -$.extend($.ui.tabs.prototype, { - rotation: null, - rotate: function(ms, continuing) { - - var self = this, t = this.options.selected; - - function rotate() { - clearTimeout(self.rotation); - self.rotation = setTimeout(function() { - t = ++t < self.$tabs.length ? t : 0; - self.select(t); - }, ms); - } - - // start rotation - if (ms) { - this.element.bind('tabsshow', rotate); // will not be attached twice - this.$tabs.bind(this.options.event + '.tabs', !continuing ? - function(e) { - if (e.clientX) { // in case of a true click - clearTimeout(self.rotation); - self.element.unbind('tabsshow', rotate); - } - } : - function(e) { - t = self.options.selected; - rotate(); - } - ); - rotate(); - } - // stop rotation - else { - clearTimeout(self.rotation); - this.element.unbind('tabsshow', rotate); - this.$tabs.unbind(this.options.event + '.tabs', stop); - } - } -}); - -})(jQuery); Index: src/webapp/standalone-demos/reorderer/html/jquery-tabs.html =================================================================== --- src/webapp/standalone-demos/reorderer/html/jquery-tabs.html (revision 9725) +++ src/webapp/standalone-demos/reorderer/html/jquery-tabs.html (working copy) @@ -5,9 +5,9 @@ Reorderable jQuery Tabs Demo - - - + + + - - - + + + + + @@ -36,61 +38,63 @@

    Carving Woods (Reorderable tabs)

    - -
    -

    The tabs at the top of this page can be re-ordered using the keyboard.

    -

    Use the Tab key to move focus to the collection of tabs. - You can tell when focus arrives there because the current tab will change to a white background.

    -

    Once focus is on the tab group, you can select a tab to move and move it using the following keys:

    - - - - - -
    Selection KeysModifiers for movement
    -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    +
    + +
    +

    The tabs at the top of this page can be re-ordered using the keyboard.

    +

    Use the Tab key to move focus to the collection of tabs. + You can tell when focus arrives there because the current tab will change to a white background.

    +

    Once focus is on the tab group, you can select a tab to move and move it using the following keys:

    + + + + + +
    Selection KeysModifiers for movement
    +
    +
    +
      +
    • Soft creamy white wood that is easy to work and glues into larger block very well.
    • +
    • It has no figuring, with a fine straight even grain, the sapwood is almost white.
    • +
    • Carves well and is excellent for detail work.
    • +
    • Very light weight.
    • +
    • Basswood is used in carving, turning, and toy making.
    • +
    +
    +
    +
      +
    • Much lighter in weight than black walnut, this wood has a medium fine straight grain than is a golden brown tone to a reddish brown at the sapwood.
    • +
    • If you use an oil finish to the carving the surface takes on a light oak tone.
    • +
    • Excellent for high relief with some fine detailing.
    • +
    • Used in furniture carving, and veneering.
    • +
    +
    +
    +
      +
    • Extremely durable wood that will accept relief carving.
    • +
    • Most carving work is done with a chisel and mallet.
    • +
    • The grain is medium coarse yet straight.
    • +
    • Walnut burls can have very interesting figuring within them.
    • +
    • The color of walnut can change quickly from deep reddish brown to creamy white.
    • +
    • Used in furniture making, furniture carving, turning, and carving.
    • +
    +
    +
    +
      +
    • A hardwood similar to walnut in it's ability to be carved.
    • +
    • Has a very interesting, distinct grain pattern that is straight.
    • +
    • Mediun to heavy weight wood that is creamy tan with darker brown grain lines.
    • +
    • Smells wonderful while you are carving.
    • +
    • Used in furniture making, furniture carving, and carving.
    • +
    +
    +
    Focus trap @@ -98,8 +102,8 @@ Index: src/webapp/standalone-demos/reorderer/html/table-tr.html =================================================================== --- src/webapp/standalone-demos/reorderer/html/table-tr.html (revision 9725) +++ src/webapp/standalone-demos/reorderer/html/table-tr.html (working copy) @@ -2,243 +2,244 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - -Reorder Table - - - - - - - - - - - - - - - - - - - - -

    Bare Table reordering

    -
    - - - - -

    Reorder Announcements

    - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - SubjectFromForDateBeginning DateEnding Date -
    -

    - zzz

    -
    Sakai AdministratorsiteDec 12, 2008 5:07 pm -
    -

    - aaa

    -
    Sakai AdministratorsiteDec 12, 2008 5:07 pm -
    -

    - bbb

    -
    Sakai AdministratorsiteJan 29, 2009 1:52 pm -
    -

    - ccc

    -
    Sakai AdministratorsiteJan 29, 2009 1:52 pm -
    -

    -

    -
    - - -
    - - + + Reorder Table + + + + + + + + + + + + + + + + + + + + + + +

    Bare Table reordering

    +
    + + + + +

    Reorder Announcements

    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + SubjectFromForDateBeginning DateEnding Date +
    +

    + zzz

    +
    Sakai AdministratorsiteDec 12, 2008 5:07 pm +
    +

    + aaa

    +
    Sakai AdministratorsiteDec 12, 2008 5:07 pm +
    +

    + bbb

    +
    Sakai AdministratorsiteJan 29, 2009 1:52 pm +
    +

    + ccc

    +
    Sakai AdministratorsiteJan 29, 2009 1:52 pm +
    +

    +

    +
    + + +
    + + \ No newline at end of file