[win32 service] activate logging to the configured file as soon as possible
since we don't always have access to the system events of the computer running CW
it is important to get as much information as possible in the log file, especially
startup failure messages.
/*
* jQuery UI Tabs @VERSION
*
* Copyright (c) 2007, 2008 Klaus Hartl (stilbuero.de)
* 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() {
this.options.event += '.tabs'; // namespace event
// create tabs
this._tabify(true);
},
_setData: function(key, value) {
if ((/^selected/).test(key))
this.select(value);
else {
this.options[key] = value;
this._tabify();
}
},
length: function() {
return this.$tabs.length;
},
_tabId: function(a) {
return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '')
|| this.options.idPrefix + $.data(a);
},
ui: function(tab, panel) {
return {
options: this.options,
tab: tab,
panel: panel,
index: this.$tabs.index(tab)
};
},
_tabify: function(init) {
this.$lis = $('li:has(a[href])', this.element);
this.$tabs = this.$lis.map(function() { return $('a', this)[0]; });
this.$panels = $([]);
var self = this, o = this.options;
this.$tabs.each(function(i, a) {
// inline tab
if (a.hash && a.hash.replace('#', '')) // Safari 2 reports '#' for an empty hash
self.$panels = self.$panels.add(a.hash);
// remote tab
else if ($(a).attr('href') != '#') { // prevent loading the page itself if href is just "#"
$.data(a, 'href.tabs', a.href); // required for restore on destroy
$.data(a, 'load.tabs', a.href); // mutable
var id = self._tabId(a);
a.href = '#' + id;
var $panel = $('#' + id);
if (!$panel.length) {
$panel = $(o.panelTemplate).attr('id', id).addClass(o.panelClass)
.insertAfter( self.$panels[i - 1] || self.element );
$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 not present
this.element.addClass(o.navClass);
this.$panels.each(function() {
var $this = $(this);
$this.addClass(o.panelClass);
});
// Selected tab
// use "selected" option or try to retrieve:
// 1. from fragment identifier in url
// 2. from cookie
// 3. from selected class attribute on <li>
if (o.selected === undefined) {
if (location.hash) {
this.$tabs.each(function(i, a) {
if (a.hash == location.hash) {
o.selected = i;
// prevent page scroll to fragment
if ($.browser.msie || $.browser.opera) { // && !o.remote
var $toShow = $(location.hash), toShowId = $toShow.attr('id');
$toShow.attr('id', '');
setTimeout(function() {
$toShow.attr('id', toShowId); // restore id
}, 500);
}
scrollTo(0, 0);
return false; // break
}
});
}
else if (o.cookie) {
var index = parseInt($.cookie('ui-tabs-' + $.data(self.element[0])), 10);
if (index && self.$tabs[index])
o.selected = index;
}
else if (self.$lis.filter('.' + o.selectedClass).length)
o.selected = self.$lis.index( self.$lis.filter('.' + o.selectedClass)[0] );
}
o.selected = o.selected === null || o.selected !== undefined ? o.selected : 0; // first tab selected by default
// 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('.' + o.disabledClass),
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(o.hideClass);
this.$lis.removeClass(o.selectedClass);
if (o.selected !== null) {
this.$panels.eq(o.selected).show().removeClass(o.hideClass); // use show and remove class to show in any case no matter how it has been hidden before
this.$lis.eq(o.selected).addClass(o.selectedClass);
// 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();
}
// clean up to avoid memory leaks in certain versions of IE 6
$(window).bind('unload', function() {
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('.' + o.selectedClass)[0] );
// set or update cookie after init and add/remove respectively
if (o.cookie)
$.cookie('ui-tabs-' + $.data(self.element[0]), o.selected, o.cookie);
// disable tabs
for (var i = 0, li; li = this.$lis[i]; i++)
$(li)[$.inArray(i, o.disabled) != -1 && !$(li).hasClass(o.selectedClass) ? 'addClass' : 'removeClass'](o.disabledClass);
// reset cache if switching from cached to not cached
if (o.cache === false)
this.$tabs.removeData('cache.tabs');
// set up animations
var hideFx, showFx, baseFx = { 'min-width': 0, duration: 1 }, baseDuration = 'normal';
if (o.fx && o.fx.constructor == Array)
hideFx = o.fx[0] || baseFx, showFx = o.fx[1] || baseFx;
else
hideFx = showFx = o.fx || baseFx;
// reset some styles to maintain print style sheets etc.
var resetCSS = { display: '', overflow: '', height: '' };
if (!$.browser.msie) // not in IE to prevent ClearType font issue
resetCSS.opacity = '';
// Hide a tab, animation prevents browser scrolling to fragment,
// $show is optional.
function hideTab(clicked, $hide, $show) {
$hide.animate(hideFx, hideFx.duration || baseDuration, function() { //
$hide.addClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
if ($.browser.msie && hideFx.opacity)
$hide[0].style.filter = '';
if ($show)
showTab(clicked, $show, $hide);
});
}
// Show a tab, animation prevents browser scrolling to fragment,
// $hide is optional.
function showTab(clicked, $show, $hide) {
if (showFx === baseFx)
$show.css('display', 'block'); // prevent occasionally occuring flicker in Firefox cause by gap between showing and hiding the tab panels
$show.animate(showFx, showFx.duration || baseDuration, function() {
$show.removeClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
if ($.browser.msie && showFx.opacity)
$show[0].style.filter = '';
// callback
self._trigger('show', null, self.ui(clicked, $show[0]));
});
}
// switch a tab
function switchTab(clicked, $li, $hide, $show) {
/*if (o.bookmarkable && trueClick) { // add to history only if true click occured, not a triggered click
$.ajaxHistory.update(clicked.hash);
}*/
$li.addClass(o.selectedClass)
.siblings().removeClass(o.selectedClass);
hideTab(clicked, $hide, $show);
}
// attach tab event handler, unbind to avoid duplicates from former tabifying...
this.$tabs.unbind('.tabs').bind(o.event, function() {
//var trueClick = e.clientX; // add to history only if true click occured, not a triggered click
var $li = $(this).parents('li:eq(0)'),
$hide = self.$panels.filter(':visible'),
$show = $(this.hash);
// If tab is already selected and not unselectable 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(o.selectedClass) && !o.unselect)
|| $li.hasClass(o.disabledClass)
|| $(this).hasClass(o.loadingClass)
|| self._trigger('select', null, self.ui(this, $show[0])) === false
) {
this.blur();
return false;
}
self.options.selected = self.$tabs.index(this);
// if tab may be closed
if (o.unselect) {
if ($li.hasClass(o.selectedClass)) {
self.options.selected = null;
$li.removeClass(o.selectedClass);
self.$panels.stop();
hideTab(this, $hide);
this.blur();
return false;
} else if (!$hide.length) {
self.$panels.stop();
var a = this;
self.load(self.$tabs.index(this), function() {
$li.addClass(o.selectedClass).addClass(o.unselectClass);
showTab(a, $show);
});
this.blur();
return false;
}
}
if (o.cookie)
$.cookie('ui-tabs-' + $.data(self.element[0]), self.options.selected, o.cookie);
// stop possibly running animations
self.$panels.stop();
// show new tab
if ($show.length) {
// prevent scrollbar scrolling to 0 and than back in IE7, happens only if bookmarking/history is enabled
/*if ($.browser.msie && o.bookmarkable) {
var showId = this.hash.replace('#', '');
$show.attr('id', '');
setTimeout(function() {
$show.attr('id', showId); // restore id
}, 0);
}*/
var a = this;
self.load(self.$tabs.index(this), $hide.length ?
function() {
switchTab(a, $li, $hide, $show);
} :
function() {
$li.addClass(o.selectedClass);
showTab(a, $show);
}
);
// Set scrollbar to saved position - need to use timeout with 0 to prevent browser scroll to target of hash
/*var scrollX = window.pageXOffset || document.documentElement && document.documentElement.scrollLeft || document.body.scrollLeft || 0;
var scrollY = window.pageYOffset || document.documentElement && document.documentElement.scrollTop || document.body.scrollTop || 0;
setTimeout(function() {
scrollTo(scrollX, scrollY);
}, 0);*/
} 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 in modern
// browsers via CSS, also blur removes focus from address bar in Firefox
// which can become a usability and annoying problem with tabsRotate.
if ($.browser.msie)
this.blur();
//return o.bookmarkable && !!trueClick; // convert trueClick == undefined to Boolean required in IE
return false;
});
// disable click if event is configured to something else
if (!(/^click/).test(o.event))
this.$tabs.bind('click.tabs', function() { return false; });
},
add: function(url, label, index) {
if (index == undefined)
index = this.$tabs.length; // append by default
var o = this.options;
var $li = $(o.tabTemplate.replace(/#\{href\}/g, url).replace(/#\{label\}/g, label));
$li.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)
.addClass(o.hideClass)
.data('destroy.tabs', true);
}
$panel.addClass(o.panelClass);
if (index >= this.$lis.length) {
$li.appendTo(this.element);
$panel.appendTo(this.element[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) {
$li.addClass(o.selectedClass);
$panel.removeClass(o.hideClass);
var href = $.data(this.$tabs[0], 'load.tabs');
if (href)
this.load(index, href);
}
// 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(o.selectedClass) && 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;
var $li = this.$lis.eq(index).removeClass(o.disabledClass);
if ($.browser.safari) { // fix disappearing tab (that used opacity indicating disabling) after enabling in Safari 2...
$li.css('display', 'inline-block');
setTimeout(function() {
$li.css('display', 'block');
}, 0);
}
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(o.disabledClass);
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 + ']')[0] );
this.$tabs.eq(index).trigger(this.options.event);
},
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');
callback = callback || function() {};
// no remote or from cache - just finish with callback
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('.' + o.loadingClass).removeClass(o.loadingClass)
.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('<em></em>')
.find('em').data('label.tabs', label).html(o.spinner);
}
var ajaxOptions = $.extend({}, o.ajaxOptions, {
url: url,
success: function(r, s) {
$(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]));
o.ajaxOptions.success && o.ajaxOptions.success(r, s);
// 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(o.loadingClass);
setTimeout(function() { // timeout is again required in IE, "wait" for id being restored
self.xhr = $.ajax(ajaxOptions);
}, 0);
},
url: function(index, url) {
this.$tabs.eq(index).removeData('cache.tabs').data('load.tabs', url);
},
destroy: function() {
var o = this.options;
this.element.unbind('.tabs')
.removeClass(o.navClass).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.add(this.$panels).each(function() {
if ($.data(this, 'destroy.tabs'))
$(this).remove();
else
$(this).removeClass([o.selectedClass, o.unselectClass,
o.disabledClass, o.panelClass, o.hideClass].join(' '));
});
}
});
$.ui.tabs.defaults = {
// basic setup
unselect: false,
event: 'click',
disabled: [],
cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
// TODO history: false,
// Ajax
spinner: 'Loading…',
cache: false,
idPrefix: 'ui-tabs-',
ajaxOptions: {},
// animations
fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
// templates
tabTemplate: '<li><a href="#{href}"><span>#{label}</span></a></li>',
panelTemplate: '<div></div>',
// CSS classes
navClass: 'ui-tabs-nav',
selectedClass: 'ui-tabs-selected',
unselectClass: 'ui-tabs-unselect',
disabledClass: 'ui-tabs-disabled',
panelClass: 'ui-tabs-panel',
hideClass: 'ui-tabs-hide',
loadingClass: 'ui-tabs-loading'
};
$.ui.tabs.getter = "length";
/*
* Tabs Extensions
*/
/*
* Rotate
*/
$.extend($.ui.tabs.prototype, {
rotation: null,
rotate: function(ms, continuing) {
continuing = continuing || false;
var self = this, t = this.options.selected;
function start() {
self.rotation = setInterval(function() {
t = ++t < self.$tabs.length ? t : 0;
self.select(t);
}, ms);
}
function stop(e) {
if (!e || e.clientX) { // only in case of a true click
clearInterval(self.rotation);
}
}
// start interval
if (ms) {
start();
if (!continuing)
this.$tabs.bind(this.options.event, stop);
else
this.$tabs.bind(this.options.event, function() {
stop();
t = self.options.selected;
start();
});
}
// stop interval
else {
stop();
this.$tabs.unbind(this.options.event, stop);
}
}
});
})(jQuery);