You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3295 lines
149 KiB

10 years ago
// $Id: jquery.js,v 1.12.2.3 2008/06/25 09:38:39 goba Exp $
/*
* jQuery 1.2.6 - New Wave Javascript
*
* Copyright (c) 2008 John Resig (jquery.com)
* Dual licensed under the MIT (MIT-LICENSE.txt)
* and GPL (GPL-LICENSE.txt) licenses.
*
* Date: 2008-05-24 14:22:17 -0400 (Sat, 24 May 2008)
* Rev: 5685
*/
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(H(){J w=1b.4M,3m$=1b.$;J D=1b.4M=1b.$=H(a,b){I 2B D.17.5j(a,b)};J u=/^[^<]*(<(.|\\s)+>)[^>]*$|^#(\\w+)$/,62=/^.[^:#\\[\\.]*$/,12;D.17=D.44={5j:H(d,b){d=d||S;G(d.16){7[0]=d;7.K=1;I 7}G(1j d=="23"){J c=u.2D(d);G(c&&(c[1]||!b)){G(c[1])d=D.4h([c[1]],b);N{J a=S.61(c[3]);G(a){G(a.2v!=c[3])I D().2q(d);I D(a)}d=[]}}N I D(b).2q(d)}N G(D.1D(d))I D(S)[D.17.27?"27":"43"](d);I 7.6Y(D.2d(d))},5w:"1.2.6",8G:H(){I 7.K},K:0,3p:H(a){I a==12?D.2d(7):7[a]},2I:H(b){J a=D(b);a.5n=7;I a},6Y:H(a){7.K=0;2p.44.1p.1w(7,a);I 7},P:H(a,b){I D.P(7,a,b)},5i:H(b){J a=-1;I D.2L(b&&b.5w?b[0]:b,7)},1K:H(c,a,b){J d=c;G(c.1q==56)G(a===12)I 7[0]&&D[b||"1K"](7[0],c);N{d={};d[c]=a}I 7.P(H(i){R(c 1n d)D.1K(b?7.V:7,c,D.1i(7,d[c],b,i,c))})},1g:H(b,a){G((b==\'2h\'||b==\'1Z\')&&3d(a)<0)a=12;I 7.1K(b,a,"2a")},1r:H(b){G(1j b!="49"&&b!=U)I 7.4E().3v((7[0]&&7[0].2z||S).5F(b));J a="";D.P(b||7,H(){D.P(7.3t,H(){G(7.16!=8)a+=7.16!=1?7.76:D.17.1r([7])})});I a},5z:H(b){G(7[0])D(b,7[0].2z).5y().39(7[0]).2l(H(){J a=7;1B(a.1x)a=a.1x;I a}).3v(7);I 7},8Y:H(a){I 7.P(H(){D(7).6Q().5z(a)})},8R:H(a){I 7.P(H(){D(7).5z(a)})},3v:H(){I 7.3W(19,M,Q,H(a){G(7.16==1)7.3U(a)})},6F:H(){I 7.3W(19,M,M,H(a){G(7.16==1)7.39(a,7.1x)})},6E:H(){I 7.3W(19,Q,Q,H(a){7.1d.39(a,7)})},5q:H(){I 7.3W(19,Q,M,H(a){7.1d.39(a,7.2H)})},3l:H(){I 7.5n||D([])},2q:H(b){J c=D.2l(7,H(a){I D.2q(b,a)});I 7.2I(/[^+>] [^+>]/.11(b)||b.1h("..")>-1?D.4r(c):c)},5y:H(e){J f=7.2l(H(){G(D.14.1f&&!D.4n(7)){J a=7.6o(M),5h=S.3h("1v");5h.3U(a);I D.4h([5h.4H])[0]}N I 7.6o(M)});J d=f.2q("*").5c().P(H(){G(7[E]!=12)7[E]=U});G(e===M)7.2q("*").5c().P(H(i){G(7.16==3)I;J c=D.L(7,"3w");R(J a 1n c)R(J b 1n c[a])D.W.1e(d[i],a,c[a][b],c[a][b].L)});I f},1E:H(b){I 7.2I(D.1D(b)&&D.3C(7,H(a,i){I b.1k(a,i)})||D.3g(b,7))},4Y:H(b){G(b.1q==56)G(62.11(b))I 7.2I(D.3g(b,7,M));N b=D.3g(b,7);J a=b.K&&b[b.K-1]!==12&&!b.16;I 7.1E(H(){I a?D.2L(7,b)<0:7!=b})},1e:H(a){I 7.2I(D.4r(D.2R(7.3p(),1j a==\'23\'?D(a):D.2d(a))))},3F:H(a){I!!a&&D.3g(a,7).K>0},7T:H(a){I 7.3F("."+a)},6e:H(b){G(b==12){G(7.K){J c=7[0];G(D.Y(c,"2A")){J e=c.64,63=[],15=c.15,2V=c.O=="2A-2V";G(e<0)I U;R(J i=2V?e:0,2f=2V?e+1:15.K;i<2f;i++){J d=15[i];G(d.2W){b=D.14.1f&&!d.at.2x.an?d.1r:d.2x;G(2V)I b;63.1p(b)}}I 63}N I(7[0].2x||"").1o(/\\r/g,"")}I 12}G(b.1q==4L)b+=\'\';I 7.P(H(){G(7.16!=1)I;G(b.1q==2p&&/5O|5L/.11(7.O))7.4J=(D.2L(7.2x,b)>=0||D.2L(7.34,b)>=0);N G(D.Y(7,"2A")){J a=D.2d(b);D("9R",7).P(H(){7.2W=(D.2L(7.2x,a)>=0||D.2L(7.1r,a)>=0)});G(!a.K)7.64=-1}N 7.2x=b})},2K:H(a){I a==12?(7[0]?7[0].4H:U):7.4E().3v(a)},7b:H(a){I 7.5q(a).21()},79:H(i){I 7.3s(i,i+1)},3s:H(){I 7.2I(2p.44.3s.1w(7,19))},2l:H(b){I 7.2I(D.2l(7,H(a,i){I b.1k(a,i,a)}))},5c:H(){I 7.1e(7.5n)},L:H(d,b){J a=d.1R(".");a[1]=a[1]?"."+a[1]:"";G(b===12){J c=7.5C("9z"+a[1]+"!",[a[0]]);G(c===12&&7.K)c=D.L(7[0],d);I c===12&&a[1]?7.L(a[0]):c}N I 7.1P("9u"+a[1]+"!",[a[0],b]).P(H(){D.L(7,d,b)})},3b:H(a){I 7.P(H(){D.3b(7,a)})},3W:H(g,f,h,d){J e=7.K>1,3x;I 7.P(H(){G(!3x){3x=D.4h(g,7.2z);G(h)3x.9o()}J b=7;G(f&&D.Y(7,"1T")&&D.Y(3x[0],"4F"))b=7.3H("22")[0]||7.3U(7.2z.3h("22"));J c=D([]);D.P(3x,H(){J a=e?D(7).5y(M)[0]:7;G(D.Y(a,"1m"))c=c.1e(a);N{G(a.16==1)c=c.1e(D("1m",a).21());d.1k(b,a)}});c.P(6T)})}};D.17.5j.44=D.17;H 6T(i,a){G(a.4d)D.3Y({1a:a.4d,31:Q,1O:"1m"});N D.5u(a.1r||a.6O||a.4H||"");G(a.1d)a.1d.37(a)}H 1z(){I+2B 8J}D.1l=D.17.1l=H(){J b=19[0]||{},i=1,K=19.K,4x=Q,15;G(b.1q==8I){4x=b;b=19[1]||{};i=2}G(1j b!="49"&&1j b!="H")b={};G(K==i){b=7;--i}R(;i<K;i++)G((15=19[i])!=U)R(J c 1n 15){J a=b[c],2w=15[c];G(b===2w)6M;G(4x&&2w&&1j 2w=="49"&&!2w.16)b[c]=D.1l(4x,a||(2w.K!=U?[]:{}),2w);N G(2w!==12)b[c]=2w}I b};J E="4M"+1z(),6K=0,5r={},6G=/z-?5i|8B-?8A|1y|6B|8v-?1Z/i,3P=S.3P||{};D.1l({8u:H(a){1b.$=3m$;G(a)1b.4M=w;I D},1D:H(a){I!!a&&1j a!="23"&&!a.Y&&a.1q!=2p&&/^[\\s[]?H/.11(a+"")},4n:H(a){I a.1C&&!a.1c||a.2j&&a.2z&&!a.2z.1c},5u:H(a){a
var Drupal = Drupal || { 'settings': {}, 'behaviors': {}, 'themes': {}, 'locale': {} };
/**
* Set the variable that indicates if JavaScript behaviors should be applied
*/
Drupal.jsEnabled = document.getElementsByTagName && document.createElement && document.createTextNode && document.documentElement && document.getElementById;
/**
* Attach all registered behaviors to a page element.
*
* Behaviors are event-triggered actions that attach to page elements, enhancing
* default non-Javascript UIs. Behaviors are registered in the Drupal.behaviors
* object as follows:
* @code
* Drupal.behaviors.behaviorName = function () {
* ...
* };
* @endcode
*
* Drupal.attachBehaviors is added below to the jQuery ready event and so
* runs on initial page load. Developers implementing AHAH/AJAX in their
* solutions should also call this function after new page content has been
* loaded, feeding in an element to be processed, in order to attach all
* behaviors to the new content.
*
* Behaviors should use a class in the form behaviorName-processed to ensure
* the behavior is attached only once to a given element. (Doing so enables
* the reprocessing of given elements, which may be needed on occasion despite
* the ability to limit behavior attachment to a particular element.)
*
* @param context
* An element to attach behaviors to. If none is given, the document element
* is used.
*/
Drupal.attachBehaviors = function(context) {
context = context || document;
if (Drupal.jsEnabled) {
// Execute all of them.
jQuery.each(Drupal.behaviors, function() {
this(context);
});
}
};
/**
* Encode special characters in a plain-text string for display as HTML.
*/
Drupal.checkPlain = function(str) {
str = String(str);
var replace = { '&': '&amp;', '"': '&quot;', '<': '&lt;', '>': '&gt;' };
for (var character in replace) {
var regex = new RegExp(character, 'g');
str = str.replace(regex, replace[character]);
}
return str;
};
/**
* Translate strings to the page language or a given language.
*
* See the documentation of the server-side t() function for further details.
*
* @param str
* A string containing the English string to translate.
* @param args
* An object of replacements pairs to make after translation. Incidences
* of any key in this array are replaced with the corresponding value.
* Based on the first character of the key, the value is escaped and/or themed:
* - !variable: inserted as is
* - @variable: escape plain text to HTML (Drupal.checkPlain)
* - %variable: escape text and theme as a placeholder for user-submitted
* content (checkPlain + Drupal.theme('placeholder'))
* @return
* The translated string.
*/
Drupal.t = function(str, args) {
// Fetch the localized version of the string.
if (Drupal.locale.strings && Drupal.locale.strings[str]) {
str = Drupal.locale.strings[str];
}
if (args) {
// Transform arguments before inserting them
for (var key in args) {
switch (key.charAt(0)) {
// Escaped only
case '@':
args[key] = Drupal.checkPlain(args[key]);
break;
// Pass-through
case '!':
break;
// Escaped and placeholder
case '%':
default:
args[key] = Drupal.theme('placeholder', args[key]);
break;
}
str = str.replace(key, args[key]);
}
}
return str;
};
/**
* Format a string containing a count of items.
*
* This function ensures that the string is pluralized correctly. Since Drupal.t() is
* called by this function, make sure not to pass already-localized strings to it.
*
* See the documentation of the server-side format_plural() function for further details.
*
* @param count
* The item count to display.
* @param singular
* The string for the singular case. Please make sure it is clear this is
* singular, to ease translation (e.g. use "1 new comment" instead of "1 new").
* Do not use @count in the singular string.
* @param plural
* The string for the plural case. Please make sure it is clear this is plural,
* to ease translation. Use @count in place of the item count, as in "@count
* new comments".
* @param args
* An object of replacements pairs to make after translation. Incidences
* of any key in this array are replaced with the corresponding value.
* Based on the first character of the key, the value is escaped and/or themed:
* - !variable: inserted as is
* - @variable: escape plain text to HTML (Drupal.checkPlain)
* - %variable: escape text and theme as a placeholder for user-submitted
* content (checkPlain + Drupal.theme('placeholder'))
* Note that you do not need to include @count in this array.
* This replacement is done automatically for the plural case.
* @return
* A translated string.
*/
Drupal.formatPlural = function(count, singular, plural, args) {
var args = args || {};
args['@count'] = count;
// Determine the index of the plural form.
var index = Drupal.locale.pluralFormula ? Drupal.locale.pluralFormula(args['@count']) : ((args['@count'] == 1) ? 0 : 1);
if (index == 0) {
return Drupal.t(singular, args);
}
else if (index == 1) {
return Drupal.t(plural, args);
}
else {
args['@count['+ index +']'] = args['@count'];
delete args['@count'];
return Drupal.t(plural.replace('@count', '@count['+ index +']'));
}
};
/**
* Generate the themed representation of a Drupal object.
*
* All requests for themed output must go through this function. It examines
* the request and routes it to the appropriate theme function. If the current
* theme does not provide an override function, the generic theme function is
* called.
*
* For example, to retrieve the HTML that is output by theme_placeholder(text),
* call Drupal.theme('placeholder', text).
*
* @param func
* The name of the theme function to call.
* @param ...
* Additional arguments to pass along to the theme function.
* @return
* Any data the theme function returns. This could be a plain HTML string,
* but also a complex object.
*/
Drupal.theme = function(func) {
for (var i = 1, args = []; i < arguments.length; i++) {
args.push(arguments[i]);
}
return (Drupal.theme[func] || Drupal.theme.prototype[func]).apply(this, args);
};
/**
* Parse a JSON response.
*
* The result is either the JSON object, or an object with 'status' 0 and 'data' an error message.
*/
Drupal.parseJson = function (data) {
if ((data.substring(0, 1) != '{') && (data.substring(0, 1) != '[')) {
return { status: 0, data: data.length ? data : Drupal.t('Unspecified error') };
}
return eval('(' + data + ');');
};
/**
* Freeze the current body height (as minimum height). Used to prevent
* unnecessary upwards scrolling when doing DOM manipulations.
*/
Drupal.freezeHeight = function () {
Drupal.unfreezeHeight();
var div = document.createElement('div');
$(div).css({
position: 'absolute',
top: '0px',
left: '0px',
width: '1px',
height: $('body').css('height')
}).attr('id', 'freeze-height');
$('body').append(div);
};
/**
* Unfreeze the body height
*/
Drupal.unfreezeHeight = function () {
$('#freeze-height').remove();
};
/**
* Wrapper to address the mod_rewrite url encoding bug
* (equivalent of drupal_urlencode() in PHP).
*/
Drupal.encodeURIComponent = function (item, uri) {
uri = uri || location.href;
item = encodeURIComponent(item).replace(/%2F/g, '/');
return (uri.indexOf('?q=') != -1) ? item : item.replace(/%26/g, '%2526').replace(/%23/g, '%2523').replace(/\/\//g, '/%252F');
};
/**
* Get the text selection in a textarea.
*/
Drupal.getSelection = function (element) {
if (typeof(element.selectionStart) != 'number' && document.selection) {
// The current selection
var range1 = document.selection.createRange();
var range2 = range1.duplicate();
// Select all text.
range2.moveToElementText(element);
// Now move 'dummy' end point to end point of original range.
range2.setEndPoint('EndToEnd', range1);
// Now we can calculate start and end points.
var start = range2.text.length - range1.text.length;
var end = start + range1.text.length;
return { 'start': start, 'end': end };
}
return { 'start': element.selectionStart, 'end': element.selectionEnd };
};
/**
* Build an error message from ahah response.
*/
Drupal.ahahError = function(xmlhttp, uri) {
if (xmlhttp.status == 200) {
if (jQuery.trim($(xmlhttp.responseText).text())) {
var message = Drupal.t("An error occurred. \n@uri\n@text", {'@uri': uri, '@text': xmlhttp.responseText });
}
else {
var message = Drupal.t("An error occurred. \n@uri\n(no information available).", {'@uri': uri, '@text': xmlhttp.responseText });
}
}
else {
var message = Drupal.t("An HTTP error @status occurred. \n@uri", {'@uri': uri, '@status': xmlhttp.status });
}
return message;
}
// Global Killswitch on the <html> element
if (Drupal.jsEnabled) {
// Global Killswitch on the <html> element
$(document.documentElement).addClass('js');
// 'js enabled' cookie
document.cookie = 'has_js=1; path=/';
// Attach all behaviors.
$(document).ready(function() {
Drupal.attachBehaviors(this);
});
}
/**
* The default themes.
*/
Drupal.theme.prototype = {
/**
* Formats text for emphasized display in a placeholder inside a sentence.
*
* @param str
* The text to format (plain-text).
* @return
* The formatted text (html).
*/
placeholder: function(str) {
return '<em>' + Drupal.checkPlain(str) + '</em>';
}
};
;// $Id: tabledrag.js,v 1.13.2.5 2009/06/18 12:24:24 goba Exp $
/**
* Drag and drop table rows with field manipulation.
*
* Using the drupal_add_tabledrag() function, any table with weights or parent
* relationships may be made into draggable tables. Columns containing a field
* may optionally be hidden, providing a better user experience.
*
* Created tableDrag instances may be modified with custom behaviors by
* overriding the .onDrag, .onDrop, .row.onSwap, and .row.onIndent methods.
* See blocks.js for an example of adding additional functionality to tableDrag.
*/
Drupal.behaviors.tableDrag = function(context) {
for (var base in Drupal.settings.tableDrag) {
if (!$('#' + base + '.tabledrag-processed', context).size()) {
var tableSettings = Drupal.settings.tableDrag[base];
$('#' + base).filter(':not(.tabledrag-processed)').each(function() {
// Create the new tableDrag instance. Save in the Drupal variable
// to allow other scripts access to the object.
Drupal.tableDrag[base] = new Drupal.tableDrag(this, tableSettings);
});
$('#' + base).addClass('tabledrag-processed');
}
}
};
/**
* Constructor for the tableDrag object. Provides table and field manipulation.
*
* @param table
* DOM object for the table to be made draggable.
* @param tableSettings
* Settings for the table added via drupal_add_dragtable().
*/
Drupal.tableDrag = function(table, tableSettings) {
var self = this;
// Required object variables.
this.table = table;
this.tableSettings = tableSettings;
this.dragObject = null; // Used to hold information about a current drag operation.
this.rowObject = null; // Provides operations for row manipulation.
this.oldRowElement = null; // Remember the previous element.
this.oldY = 0; // Used to determine up or down direction from last mouse move.
this.changed = false; // Whether anything in the entire table has changed.
this.maxDepth = 0; // Maximum amount of allowed parenting.
this.rtl = $(this.table).css('direction') == 'rtl' ? -1 : 1; // Direction of the table.
// Configure the scroll settings.
this.scrollSettings = { amount: 4, interval: 50, trigger: 70 };
this.scrollInterval = null;
this.scrollY = 0;
this.windowHeight = 0;
// Check this table's settings to see if there are parent relationships in
// this table. For efficiency, large sections of code can be skipped if we
// don't need to track horizontal movement and indentations.
this.indentEnabled = false;
for (group in tableSettings) {
for (n in tableSettings[group]) {
if (tableSettings[group][n]['relationship'] == 'parent') {
this.indentEnabled = true;
}
if (tableSettings[group][n]['limit'] > 0) {
this.maxDepth = tableSettings[group][n]['limit'];
}
}
}
if (this.indentEnabled) {
this.indentCount = 1; // Total width of indents, set in makeDraggable.
// Find the width of indentations to measure mouse movements against.
// Because the table doesn't need to start with any indentations, we
// manually append 2 indentations in the first draggable row, measure
// the offset, then remove.
var indent = Drupal.theme('tableDragIndentation');
// Match immediate children of the parent element to allow nesting.
var testCell = $('> tbody > tr.draggable:first td:first, > tr.draggable:first td:first', table).prepend(indent).prepend(indent);
this.indentAmount = $('.indentation', testCell).get(1).offsetLeft - $('.indentation', testCell).get(0).offsetLeft;
$('.indentation', testCell).slice(0, 2).remove();
}
// Make each applicable row draggable.
// Match immediate children of the parent element to allow nesting.
$('> tr.draggable, > tbody > tr.draggable', table).each(function() { self.makeDraggable(this); });
// Hide columns containing affected form elements.
this.hideColumns();
// Add mouse bindings to the document. The self variable is passed along
// as event handlers do not have direct access to the tableDrag object.
$(document).bind('mousemove', function(event) { return self.dragRow(event, self); });
$(document).bind('mouseup', function(event) { return self.dropRow(event, self); });
};
/**
* Hide the columns containing form elements according to the settings for
* this tableDrag instance.
*/
Drupal.tableDrag.prototype.hideColumns = function(){
for (var group in this.tableSettings) {
// Find the first field in this group.
for (var d in this.tableSettings[group]) {
var field = $('.' + this.tableSettings[group][d]['target'] + ':first', this.table);
if (field.size() && this.tableSettings[group][d]['hidden']) {
var hidden = this.tableSettings[group][d]['hidden'];
var cell = field.parents('td:first');
break;
}
}
// Hide the column containing this field.
if (hidden && cell[0] && cell.css('display') != 'none') {
// Add 1 to our indexes. The nth-child selector is 1 based, not 0 based.
// Match immediate children of the parent element to allow nesting.
var columnIndex = $('> td', cell.parent()).index(cell.get(0)) + 1;
var headerIndex = $('> td:not(:hidden)', cell.parent()).index(cell.get(0)) + 1;
$('> thead > tr, > tbody > tr, > tr', this.table).each(function(){
var row = $(this);
var parentTag = row.parent().get(0).tagName.toLowerCase();
var index = (parentTag == 'thead') ? headerIndex : columnIndex;
// Adjust the index to take into account colspans.
row.children().each(function(n) {
if (n < index) {
index -= (this.colSpan && this.colSpan > 1) ? this.colSpan - 1 : 0;
}
});
if (index > 0) {
cell = row.children(':nth-child(' + index + ')');
if (cell[0].colSpan > 1) {
// If this cell has a colspan, simply reduce it.
cell[0].colSpan = cell[0].colSpan - 1;
}
else {
// Hide table body cells, but remove table header cells entirely
// (Safari doesn't hide properly).
parentTag == 'thead' ? cell.remove() : cell.css('display', 'none');
}
}
});
}
}
};
/**
* Find the target used within a particular row and group.
*/
Drupal.tableDrag.prototype.rowSettings = function(group, row) {
var field = $('.' + group, row);
for (delta in this.tableSettings[group]) {
var targetClass = this.tableSettings[group][delta]['target'];
if (field.is('.' + targetClass)) {
// Return a copy of the row settings.
var rowSettings = new Object();
for (var n in this.tableSettings[group][delta]) {
rowSettings[n] = this.tableSettings[group][delta][n];
}
return rowSettings;
}
}
};
/**
* Take an item and add event handlers to make it become draggable.
*/
Drupal.tableDrag.prototype.makeDraggable = function(item) {
var self = this;
// Create the handle.
var handle = $('<a href="#" class="tabledrag-handle"><div class="handle">&nbsp;</div></a>').attr('title', Drupal.t('Drag to re-order'));
// Insert the handle after indentations (if any).
if ($('td:first .indentation:last', item).after(handle).size()) {
// Update the total width of indentation in this entire table.
self.indentCount = Math.max($('.indentation', item).size(), self.indentCount);
}
else {
$('td:first', item).prepend(handle);
}
// Add hover action for the handle.
handle.hover(function() {
self.dragObject == null ? $(this).addClass('tabledrag-handle-hover') : null;
}, function() {
self.dragObject == null ? $(this).removeClass('tabledrag-handle-hover') : null;
});
// Add the mousedown action for the handle.
handle.mousedown(function(event) {
// Create a new dragObject recording the event information.
self.dragObject = new Object();
self.dragObject.initMouseOffset = self.getMouseOffset(item, event);
self.dragObject.initMouseCoords = self.mouseCoords(event);
if (self.indentEnabled) {
self.dragObject.indentMousePos = self.dragObject.initMouseCoords;
}
// If there's a lingering row object from the keyboard, remove its focus.
if (self.rowObject) {
$('a.tabledrag-handle', self.rowObject.element).blur();
}
// Create a new rowObject for manipulation of this row.
self.rowObject = new self.row(item, 'mouse', self.indentEnabled, self.maxDepth, true);
// Save the position of the table.
self.table.topY = self.getPosition(self.table).y;
self.table.bottomY = self.table.topY + self.table.offsetHeight;
// Add classes to the handle and row.
$(this).addClass('tabledrag-handle-hover');
$(item).addClass('drag');
// Set the document to use the move cursor during drag.
$('body').addClass('drag');
if (self.oldRowElement) {
$(self.oldRowElement).removeClass('drag-previous');
}
// Hack for IE6 that flickers uncontrollably if select lists are moved.
if (navigator.userAgent.indexOf('MSIE 6.') != -1) {
$('select', this.table).css('display', 'none');
}
// Hack for Konqueror, prevent the blur handler from firing.
// Konqueror always gives links focus, even after returning false on mousedown.
self.safeBlur = false;
// Call optional placeholder function.
self.onDrag();
return false;
});
// Prevent the anchor tag from jumping us to the top of the page.
handle.click(function() {
return false;
});
// Similar to the hover event, add a class when the handle is focused.
handle.focus(function() {
$(this).addClass('tabledrag-handle-hover');
self.safeBlur = true;
});
// Remove the handle class on blur and fire the same function as a mouseup.
handle.blur(function(event) {
$(this).removeClass('tabledrag-handle-hover');
if (self.rowObject && self.safeBlur) {
self.dropRow(event, self);
}
});
// Add arrow-key support to the handle.
handle.keydown(function(event) {
// If a rowObject doesn't yet exist and this isn't the tab key.
if (event.keyCode != 9 && !self.rowObject) {
self.rowObject = new self.row(item, 'keyboard', self.indentEnabled, self.maxDepth, true);
}
var keyChange = false;
switch (event.keyCode) {
case 37: // Left arrow.
case 63234: // Safari left arrow.
keyChange = true;
self.rowObject.indent(-1 * self.rtl);
break;
case 38: // Up arrow.
case 63232: // Safari up arrow.
var previousRow = $(self.rowObject.element).prev('tr').get(0);
while (previousRow && $(previousRow).is(':hidden')) {
previousRow = $(previousRow).prev('tr').get(0);
}
if (previousRow) {
self.safeBlur = false; // Do not allow the onBlur cleanup.
self.rowObject.direction = 'up';
keyChange = true;
if ($(item).is('.tabledrag-root')) {
// Swap with the previous top-level row..
var groupHeight = 0;
while (previousRow && $('.indentation', previousRow).size()) {
previousRow = $(previousRow).prev('tr').get(0);
groupHeight += $(previousRow).is(':hidden') ? 0 : previousRow.offsetHeight;
}
if (previousRow) {
self.rowObject.swap('before', previousRow);
// No need to check for indentation, 0 is the only valid one.
window.scrollBy(0, -groupHeight);
}
}
else if (self.table.tBodies[0].rows[0] != previousRow || $(previousRow).is('.draggable')) {
// Swap with the previous row (unless previous row is the first one
// and undraggable).
self.rowObject.swap('before', previousRow);
self.rowObject.interval = null;
self.rowObject.indent(0);
window.scrollBy(0, -parseInt(item.offsetHeight));
}
handle.get(0).focus(); // Regain focus after the DOM manipulation.
}
break;
case 39: // Right arrow.
case 63235: // Safari right arrow.
keyChange = true;
self.rowObject.indent(1 * self.rtl);
break;
case 40: // Down arrow.
case 63233: // Safari down arrow.
var nextRow = $(self.rowObject.group).filter(':last').next('tr').get(0);
while (nextRow && $(nextRow).is(':hidden')) {
nextRow = $(nextRow).next('tr').get(0);
}
if (nextRow) {
self.safeBlur = false; // Do not allow the onBlur cleanup.
self.rowObject.direction = 'down';
keyChange = true;
if ($(item).is('.tabledrag-root')) {
// Swap with the next group (necessarily a top-level one).
var groupHeight = 0;
nextGroup = new self.row(nextRow, 'keyboard', self.indentEnabled, self.maxDepth, false);
if (nextGroup) {
$(nextGroup.group).each(function () {groupHeight += $(this).is(':hidden') ? 0 : this.offsetHeight});
nextGroupRow = $(nextGroup.group).filter(':last').get(0);
self.rowObject.swap('after', nextGroupRow);
// No need to check for indentation, 0 is the only valid one.
window.scrollBy(0, parseInt(groupHeight));
}
}
else {
// Swap with the next row.
self.rowObject.swap('after', nextRow);
self.rowObject.interval = null;
self.rowObject.indent(0);
window.scrollBy(0, parseInt(item.offsetHeight));
}
handle.get(0).focus(); // Regain focus after the DOM manipulation.
}
break;
}
if (self.rowObject && self.rowObject.changed == true) {
$(item).addClass('drag');
if (self.oldRowElement) {
$(self.oldRowElement).removeClass('drag-previous');
}
self.oldRowElement = item;
self.restripeTable();
self.onDrag();
}
// Returning false if we have an arrow key to prevent scrolling.
if (keyChange) {
return false;
}
});
// Compatibility addition, return false on keypress to prevent unwanted scrolling.
// IE and Safari will supress scrolling on keydown, but all other browsers
// need to return false on keypress. http://www.quirksmode.org/js/keys.html
handle.keypress(function(event) {
switch (event.keyCode) {
case 37: // Left arrow.
case 38: // Up arrow.
case 39: // Right arrow.
case 40: // Down arrow.
return false;
}
});
};
/**
* Mousemove event handler, bound to document.
*/
Drupal.tableDrag.prototype.dragRow = function(event, self) {
if (self.dragObject) {
self.currentMouseCoords = self.mouseCoords(event);
var y = self.currentMouseCoords.y - self.dragObject.initMouseOffset.y;
var x = self.currentMouseCoords.x - self.dragObject.initMouseOffset.x;
// Check for row swapping and vertical scrolling.
if (y != self.oldY) {
self.rowObject.direction = y > self.oldY ? 'down' : 'up';
self.oldY = y; // Update the old value.
// Check if the window should be scrolled (and how fast).
var scrollAmount = self.checkScroll(self.currentMouseCoords.y);
// Stop any current scrolling.
clearInterval(self.scrollInterval);
// Continue scrolling if the mouse has moved in the scroll direction.
if (scrollAmount > 0 && self.rowObject.direction == 'down' || scrollAmount < 0 && self.rowObject.direction == 'up') {
self.setScroll(scrollAmount);
}
// If we have a valid target, perform the swap and restripe the table.
var currentRow = self.findDropTargetRow(x, y);
if (currentRow) {
if (self.rowObject.direction == 'down') {
self.rowObject.swap('after', currentRow, self);
}
else {
self.rowObject.swap('before', currentRow, self);
}
self.restripeTable();
}
}
// Similar to row swapping, handle indentations.
if (self.indentEnabled) {
var xDiff = self.currentMouseCoords.x - self.dragObject.indentMousePos.x;
// Set the number of indentations the mouse has been moved left or right.
var indentDiff = Math.round(xDiff / self.indentAmount * self.rtl);
// Indent the row with our estimated diff, which may be further
// restricted according to the rows around this row.
var indentChange = self.rowObject.indent(indentDiff);
// Update table and mouse indentations.
self.dragObject.indentMousePos.x += self.indentAmount * indentChange * self.rtl;
self.indentCount = Math.max(self.indentCount, self.rowObject.indents);
}
return false;
}
};
/**
* Mouseup event handler, bound to document.
* Blur event handler, bound to drag handle for keyboard support.
*/
Drupal.tableDrag.prototype.dropRow = function(event, self) {
// Drop row functionality shared between mouseup and blur events.
if (self.rowObject != null) {
var droppedRow = self.rowObject.element;
// The row is already in the right place so we just release it.
if (self.rowObject.changed == true) {
// Update the fields in the dropped row.
self.updateFields(droppedRow);
// If a setting exists for affecting the entire group, update all the
// fields in the entire dragged group.
for (var group in self.tableSettings) {
var rowSettings = self.rowSettings(group, droppedRow);
if (rowSettings.relationship == 'group') {
for (n in self.rowObject.children) {
self.updateField(self.rowObject.children[n], group);
}
}
}
self.rowObject.markChanged();
if (self.changed == false) {
$(Drupal.theme('tableDragChangedWarning')).insertAfter(self.table).hide().fadeIn('slow');
self.changed = true;
}
}
if (self.indentEnabled) {
self.rowObject.removeIndentClasses();
}
if (self.oldRowElement) {
$(self.oldRowElement).removeClass('drag-previous');
}
$(droppedRow).removeClass('drag').addClass('drag-previous');
self.oldRowElement = droppedRow;
self.onDrop();
self.rowObject = null;
}
// Functionality specific only to mouseup event.
if (self.dragObject != null) {
$('.tabledrag-handle', droppedRow).removeClass('tabledrag-handle-hover');
self.dragObject = null;
$('body').removeClass('drag');
clearInterval(self.scrollInterval);
// Hack for IE6 that flickers uncontrollably if select lists are moved.
if (navigator.userAgent.indexOf('MSIE 6.') != -1) {
$('select', this.table).css('display', 'block');
}
}
};
/**
* Get the position of an element by adding up parent offsets in the DOM tree.
*/
Drupal.tableDrag.prototype.getPosition = function(element){
var left = 0;
var top = 0;
// Because Safari doesn't report offsetHeight on table rows, but does on table
// cells, grab the firstChild of the row and use that instead.
// http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari
if (element.offsetHeight == 0) {
element = element.firstChild; // a table cell
}
while (element.offsetParent){
left += element.offsetLeft;
top += element.offsetTop;
element = element.offsetParent;
}
left += element.offsetLeft;
top += element.offsetTop;
return {x:left, y:top};
};
/**
* Get the mouse coordinates from the event (allowing for browser differences).
*/
Drupal.tableDrag.prototype.mouseCoords = function(event){
if (event.pageX || event.pageY) {
return {x:event.pageX, y:event.pageY};
}
return {
x:event.clientX + document.body.scrollLeft - document.body.clientLeft,
y:event.clientY + document.body.scrollTop - document.body.clientTop
};
};
/**
* Given a target element and a mouse event, get the mouse offset from that
* element. To do this we need the element's position and the mouse position.
*/
Drupal.tableDrag.prototype.getMouseOffset = function(target, event) {
var docPos = this.getPosition(target);
var mousePos = this.mouseCoords(event);
return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
};
/**
* Find the row the mouse is currently over. This row is then taken and swapped
* with the one being dragged.
*
* @param x
* The x coordinate of the mouse on the page (not the screen).
* @param y
* The y coordinate of the mouse on the page (not the screen).
*/
Drupal.tableDrag.prototype.findDropTargetRow = function(x, y) {
var rows = this.table.tBodies[0].rows;
for (var n=0; n<rows.length; n++) {
var row = rows[n];
var indentDiff = 0;
// Safari fix see Drupal.tableDrag.prototype.getPosition()
if (row.offsetHeight == 0) {
var rowY = this.getPosition(row.firstChild).y;
var rowHeight = parseInt(row.firstChild.offsetHeight)/2;
}
// Other browsers.
else {
var rowY = this.getPosition(row).y;
var rowHeight = parseInt(row.offsetHeight)/2;
}
// Because we always insert before, we need to offset the height a bit.
if ((y > (rowY - rowHeight)) && (y < (rowY + rowHeight))) {
if (this.indentEnabled) {
// Check that this row is not a child of the row being dragged.
for (n in this.rowObject.group) {
if (this.rowObject.group[n] == row) {
return null;
}
}
}
// Check that swapping with this row is allowed.
if (!this.rowObject.isValidSwap(row)) {
return null;
}
// We may have found the row the mouse just passed over, but it doesn't
// take into account hidden rows. Skip backwards until we find a draggable
// row.
while ($(row).is(':hidden') && $(row).prev('tr').is(':hidden')) {
row = $(row).prev('tr').get(0);
}
return row;
}
}
return null;
};
/**
* After the row is dropped, update the table fields according to the settings
* set for this table.
*
* @param changedRow
* DOM object for the row that was just dropped.
*/
Drupal.tableDrag.prototype.updateFields = function(changedRow) {
for (var group in this.tableSettings) {
// Each group may have a different setting for relationship, so we find
// the source rows for each seperately.
this.updateField(changedRow, group);
}
};
/**
* After the row is dropped, update a single table field according to specific
* settings.
*
* @param changedRow
* DOM object for the row that was just dropped.
* @param group
* The settings group on which field updates will occur.
*/
Drupal.tableDrag.prototype.updateField = function(changedRow, group) {
var rowSettings = this.rowSettings(group, changedRow);
// Set the row as it's own target.
if (rowSettings.relationship == 'self' || rowSettings.relationship == 'group') {
var sourceRow = changedRow;
}
// Siblings are easy, check previous and next rows.
else if (rowSettings.relationship == 'sibling') {
var previousRow = $(changedRow).prev('tr').get(0);
var nextRow = $(changedRow).next('tr').get(0);
var sourceRow = changedRow;
if ($(previousRow).is('.draggable') && $('.' + group, previousRow).length) {
if (this.indentEnabled) {
if ($('.indentations', previousRow).size() == $('.indentations', changedRow)) {
sourceRow = previousRow;
}
}
else {
sourceRow = previousRow;
}
}
else if ($(nextRow).is('.draggable') && $('.' + group, nextRow).length) {
if (this.indentEnabled) {
if ($('.indentations', nextRow).size() == $('.indentations', changedRow)) {
sourceRow = nextRow;
}
}
else {
sourceRow = nextRow;
}
}
}
// Parents, look up the tree until we find a field not in this group.
// Go up as many parents as indentations in the changed row.
else if (rowSettings.relationship == 'parent') {
var previousRow = $(changedRow).prev('tr');
while (previousRow.length && $('.indentation', previousRow).length >= this.rowObject.indents) {
previousRow = previousRow.prev('tr');
}
// If we found a row.
if (previousRow.length) {
sourceRow = previousRow[0];
}
// Otherwise we went all the way to the left of the table without finding
// a parent, meaning this item has been placed at the root level.
else {
// Use the first row in the table as source, because it's garanteed to
// be at the root level. Find the first item, then compare this row
// against it as a sibling.
sourceRow = $('tr.draggable:first').get(0);
if (sourceRow == this.rowObject.element) {
sourceRow = $(this.rowObject.group[this.rowObject.group.length - 1]).next('tr.draggable').get(0);
}
var useSibling = true;
}
}
// Because we may have moved the row from one category to another,
// take a look at our sibling and borrow its sources and targets.
this.copyDragClasses(sourceRow, changedRow, group);
rowSettings = this.rowSettings(group, changedRow);
// In the case that we're looking for a parent, but the row is at the top
// of the tree, copy our sibling's values.
if (useSibling) {
rowSettings.relationship = 'sibling';
rowSettings.source = rowSettings.target;
}
var targetClass = '.' + rowSettings.target;
var targetElement = $(targetClass, changedRow).get(0);
// Check if a target element exists in this row.
if (targetElement) {
var sourceClass = '.' + rowSettings.source;
var sourceElement = $(sourceClass, sourceRow).get(0);
switch (rowSettings.action) {
case 'depth':
// Get the depth of the target row.
targetElement.value = $('.indentation', $(sourceElement).parents('tr:first')).size();
break;
case 'match':
// Update the value.
targetElement.value = sourceElement.value;
break;
case 'order':
var siblings = this.rowObject.findSiblings(rowSettings);
if ($(targetElement).is('select')) {
// Get a list of acceptable values.
var values = new Array();
$('option', targetElement).each(function() {
values.push(this.value);
});
var maxVal = values[values.length - 1];
// Populate the values in the siblings.
$(targetClass, siblings).each(function() {
// If there are more items than possible values, assign the maximum value to the row.
if (values.length > 0) {
this.value = values.shift();
}
else {
this.value = maxVal;
}
});
}
else {
// Assume a numeric input field.
var weight = parseInt($(targetClass, siblings[0]).val()) || 0;
$(targetClass, siblings).each(function() {
this.value = weight;
weight++;
});
}
break;
}
}
};
/**
* Copy all special tableDrag classes from one row's form elements to a
* different one, removing any special classes that the destination row
* may have had.
*/
Drupal.tableDrag.prototype.copyDragClasses = function(sourceRow, targetRow, group) {
var sourceElement = $('.' + group, sourceRow);
var targetElement = $('.' + group, targetRow);
if (sourceElement.length && targetElement.length) {
targetElement[0].className = sourceElement[0].className;
}
};
Drupal.tableDrag.prototype.checkScroll = function(cursorY) {
var de = document.documentElement;
var b = document.body;
var windowHeight = this.windowHeight = window.innerHeight || (de.clientHeight && de.clientWidth != 0 ? de.clientHeight : b.offsetHeight);
var scrollY = this.scrollY = (document.all ? (!de.scrollTop ? b.scrollTop : de.scrollTop) : (window.pageYOffset ? window.pageYOffset : window.scrollY));
var trigger = this.scrollSettings.trigger;
var delta = 0;
// Return a scroll speed relative to the edge of the screen.
if (cursorY - scrollY > windowHeight - trigger) {
delta = trigger / (windowHeight + scrollY - cursorY);
delta = (delta > 0 && delta < trigger) ? delta : trigger;
return delta * this.scrollSettings.amount;
}
else if (cursorY - scrollY < trigger) {
delta = trigger / (cursorY - scrollY);
delta = (delta > 0 && delta < trigger) ? delta : trigger;
return -delta * this.scrollSettings.amount;
}
};
Drupal.tableDrag.prototype.setScroll = function(scrollAmount) {
var self = this;
this.scrollInterval = setInterval(function() {
// Update the scroll values stored in the object.
self.checkScroll(self.currentMouseCoords.y);
var aboveTable = self.scrollY > self.table.topY;
var belowTable = self.scrollY + self.windowHeight < self.table.bottomY;
if (scrollAmount > 0 && belowTable || scrollAmount < 0 && aboveTable) {
window.scrollBy(0, scrollAmount);
}
}, this.scrollSettings.interval);
};
Drupal.tableDrag.prototype.restripeTable = function() {
// :even and :odd are reversed because jquery counts from 0 and
// we count from 1, so we're out of sync.
// Match immediate children of the parent element to allow nesting.
$('> tbody > tr.draggable, > tr.draggable', this.table)
.filter(':odd').filter('.odd')
.removeClass('odd').addClass('even')
.end().end()
.filter(':even').filter('.even')
.removeClass('even').addClass('odd');
};
/**
* Stub function. Allows a custom handler when a row begins dragging.
*/
Drupal.tableDrag.prototype.onDrag = function() {
return null;
};
/**
* Stub function. Allows a custom handler when a row is dropped.
*/
Drupal.tableDrag.prototype.onDrop = function() {
return null;
};
/**
* Constructor to make a new object to manipulate a table row.
*
* @param tableRow
* The DOM element for the table row we will be manipulating.
* @param method
* The method in which this row is being moved. Either 'keyboard' or 'mouse'.
* @param indentEnabled
* Whether the containing table uses indentations. Used for optimizations.
* @param maxDepth
* The maximum amount of indentations this row may contain.
* @param addClasses
* Whether we want to add classes to this row to indicate child relationships.
*/
Drupal.tableDrag.prototype.row = function(tableRow, method, indentEnabled, maxDepth, addClasses) {
this.element = tableRow;
this.method = method;
this.group = new Array(tableRow);
this.groupDepth = $('.indentation', tableRow).size();
this.changed = false;
this.table = $(tableRow).parents('table:first').get(0);
this.indentEnabled = indentEnabled;
this.maxDepth = maxDepth;
this.direction = ''; // Direction the row is being moved.
if (this.indentEnabled) {
this.indents = $('.indentation', tableRow).size();
this.children = this.findChildren(addClasses);
this.group = $.merge(this.group, this.children);
// Find the depth of this entire group.
for (var n = 0; n < this.group.length; n++) {
this.groupDepth = Math.max($('.indentation', this.group[n]).size(), this.groupDepth);
}
}
};
/**
* Find all children of rowObject by indentation.
*
* @param addClasses
* Whether we want to add classes to this row to indicate child relationships.
*/
Drupal.tableDrag.prototype.row.prototype.findChildren = function(addClasses) {
var parentIndentation = this.indents;
var currentRow = $(this.element, this.table).next('tr.draggable');
var rows = new Array();
var child = 0;
while (currentRow.length) {
var rowIndentation = $('.indentation', currentRow).length;
// A greater indentation indicates this is a child.
if (rowIndentation > parentIndentation) {
child++;
rows.push(currentRow[0]);
if (addClasses) {
$('.indentation', currentRow).each(function(indentNum) {
if (child == 1 && (indentNum == parentIndentation)) {
$(this).addClass('tree-child-first');
}
if (indentNum == parentIndentation) {
$(this).addClass('tree-child');
}
else if (indentNum > parentIndentation) {
$(this).addClass('tree-child-horizontal');
}
});
}
}
else {
break;
}
currentRow = currentRow.next('tr.draggable');
}
if (addClasses && rows.length) {
$('.indentation:nth-child(' + (parentIndentation + 1) + ')', rows[rows.length - 1]).addClass('tree-child-last');
}
return rows;
};
/**
* Ensure that two rows are allowed to be swapped.
*
* @param row
* DOM object for the row being considered for swapping.
*/
Drupal.tableDrag.prototype.row.prototype.isValidSwap = function(row) {
if (this.indentEnabled) {
var prevRow, nextRow;
if (this.direction == 'down') {
prevRow = row;
nextRow = $(row).next('tr').get(0);
}
else {
prevRow = $(row).prev('tr').get(0);
nextRow = row;
}
this.interval = this.validIndentInterval(prevRow, nextRow);
// We have an invalid swap if the valid indentations interval is empty.
if (this.interval.min > this.interval.max) {
return false;
}
}
// Do not let an un-draggable first row have anything put before it.
if (this.table.tBodies[0].rows[0] == row && $(row).is(':not(.draggable)')) {
return false;
}
return true;
};
/**
* Perform the swap between two rows.
*
* @param position
* Whether the swap will occur 'before' or 'after' the given row.
* @param row
* DOM element what will be swapped with the row group.
*/
Drupal.tableDrag.prototype.row.prototype.swap = function(position, row) {
$(row)[position](this.group);
this.changed = true;
this.onSwap(row);
};
/**
* Determine the valid indentations interval for the row at a given position
* in the table.
*
* @param prevRow
* DOM object for the row before the tested position
* (or null for first position in the table).
* @param nextRow
* DOM object for the row after the tested position
* (or null for last position in the table).
*/
Drupal.tableDrag.prototype.row.prototype.validIndentInterval = function (prevRow, nextRow) {
var minIndent, maxIndent;
// Minimum indentation:
// Do not orphan the next row.
minIndent = nextRow ? $('.indentation', nextRow).size() : 0;
// Maximum indentation:
if (!prevRow || $(this.element).is('.tabledrag-root')) {
// Do not indent the first row in the table or 'root' rows..
maxIndent = 0;
}
else {
// Do not go deeper than as a child of the previous row.
maxIndent = $('.indentation', prevRow).size() + ($(prevRow).is('.tabledrag-leaf') ? 0 : 1);
// Limit by the maximum allowed depth for the table.
if (this.maxDepth) {
maxIndent = Math.min(maxIndent, this.maxDepth - (this.groupDepth - this.indents));
}
}
return {'min':minIndent, 'max':maxIndent};
}
/**
* Indent a row within the legal bounds of the table.
*
* @param indentDiff
* The number of additional indentations proposed for the row (can be
* positive or negative). This number will be adjusted to nearest valid
* indentation level for the row.
*/
Drupal.tableDrag.prototype.row.prototype.indent = function(indentDiff) {
// Determine the valid indentations interval if not available yet.
if (!this.interval) {
prevRow = $(this.element).prev('tr').get(0);
nextRow = $(this.group).filter(':last').next('tr').get(0);
this.interval = this.validIndentInterval(prevRow, nextRow);
}
// Adjust to the nearest valid indentation.
var indent = this.indents + indentDiff;
indent = Math.max(indent, this.interval.min);
indent = Math.min(indent, this.interval.max);
indentDiff = indent - this.indents;
for (var n = 1; n <= Math.abs(indentDiff); n++) {
// Add or remove indentations.
if (indentDiff < 0) {
$('.indentation:first', this.group).remove();
this.indents--;
}
else {
$('td:first', this.group).prepend(Drupal.theme('tableDragIndentation'));
this.indents++;
}
}
if (indentDiff) {
// Update indentation for this row.
this.changed = true;
this.groupDepth += indentDiff;
this.onIndent();
}
return indentDiff;
};
/**
* Find all siblings for a row, either according to its subgroup or indentation.
* Note that the passed in row is included in the list of siblings.
*
* @param settings
* The field settings we're using to identify what constitutes a sibling.
*/
Drupal.tableDrag.prototype.row.prototype.findSiblings = function(rowSettings) {
var siblings = new Array();
var directions = new Array('prev', 'next');
var rowIndentation = this.indents;
for (var d in directions) {
var checkRow = $(this.element)[directions[d]]();
while (checkRow.length) {
// Check that the sibling contains a similar target field.
if ($('.' + rowSettings.target, checkRow)) {
// Either add immediately if this is a flat table, or check to ensure
// that this row has the same level of indentaiton.
if (this.indentEnabled) {
var checkRowIndentation = $('.indentation', checkRow).length
}
if (!(this.indentEnabled) || (checkRowIndentation == rowIndentation)) {
siblings.push(checkRow[0]);
}
else if (checkRowIndentation < rowIndentation) {
// No need to keep looking for siblings when we get to a parent.
break;
}
}
else {
break;
}
checkRow = $(checkRow)[directions[d]]();
}
// Since siblings are added in reverse order for previous, reverse the
// completed list of previous siblings. Add the current row and continue.
if (directions[d] == 'prev') {
siblings.reverse();
siblings.push(this.element);
}
}
return siblings;
};
/**
* Remove indentation helper classes from the current row group.
*/
Drupal.tableDrag.prototype.row.prototype.removeIndentClasses = function() {
for (n in this.children) {
$('.indentation', this.children[n])
.removeClass('tree-child')
.removeClass('tree-child-first')
.removeClass('tree-child-last')
.removeClass('tree-child-horizontal');
}
};
/**
* Add an asterisk or other marker to the changed row.
*/
Drupal.tableDrag.prototype.row.prototype.markChanged = function() {
var marker = Drupal.theme('tableDragChangedMarker');
var cell = $('td:first', this.element);
if ($('span.tabledrag-changed', cell).length == 0) {
cell.append(marker);
}
};
/**
* Stub function. Allows a custom handler when a row is indented.
*/
Drupal.tableDrag.prototype.row.prototype.onIndent = function() {
return null;
};
/**
* Stub function. Allows a custom handler when a row is swapped.
*/
Drupal.tableDrag.prototype.row.prototype.onSwap = function(swappedRow) {
return null;
};
Drupal.theme.prototype.tableDragChangedMarker = function () {
return '<span class="warning tabledrag-changed">*</span>';
};
Drupal.theme.prototype.tableDragIndentation = function () {
return '<div class="indentation">&nbsp;</div>';
};
Drupal.theme.prototype.tableDragChangedWarning = function () {
return '<div class="warning">' + Drupal.theme('tableDragChangedMarker') + ' ' + Drupal.t("Changes made in this table will not be saved until the form is submitted.") + '</div>';
};
;/* $Id: lightbox.js,v 1.5.2.6.2.73 2008/06/29 15:25:12 snpower Exp $ */
/**
* jQuery Lightbox
* @author
* Stella Power, <http://drupal.org/user/66894>
*
* Based on Lightbox v2.03.3 by Lokesh Dhakar
* <http://www.huddletogether.com/projects/lightbox2/>
* Also partially based on the jQuery Lightbox by Warren Krewenki
* <http://warren.mesozen.com>
*
* Permission has been granted to Mark Ashmead & other Drupal Lightbox2 module
* maintainers to distribute this file via Drupal.org
* Under GPL license.
*
* Slideshow, iframe and video functionality added by Stella Power.
*/
var Lightbox = {
overlayOpacity : 0.8, // Controls transparency of shadow overlay.
overlayColor : '000', // Controls colour of shadow overlay.
// Controls the order of the lightbox resizing animation sequence.
resizeSequence: 0, // 0: simultaneous, 1: width then height, 2: height then width.
resizeSpeed: 'normal', // Controls the speed of the lightbox resizing animation.
fadeInSpeed: 'normal', // Controls the speed of the image appearance.
slideDownSpeed: 'slow', // Controls the speed of the image details appearance.
borderSize : 10,
boxColor : 'fff',
fontColor : '000',
topPosition : '',
infoHeight: 20,
alternative_layout : false,
imageArray : [],
imageNum : null,
total : 0,
activeImage : null,
inprogress : false,
disableResize : false,
disableZoom : false,
isZoomedIn : false,
rtl : false,
loopItems : false,
// Slideshow options.
slideInterval : 5000, // In milliseconds.
showPlayPause : true,
autoExit : true,
pauseOnNextClick : false, // True to pause the slideshow when the "Next" button is clicked.
pauseOnPrevClick : true, // True to pause the slideshow when the "Prev" button is clicked.
slideIdArray : [],
slideIdCount : 0,
isSlideshow : false,
isPaused : false,
loopSlides : false,
// Iframe options.
isLightframe : false,
iframe_width : 600,
iframe_height : 400,
iframe_border : 1,
// Video and modal options.
enableVideo : false,
isModal : false,
isVideo : false,
videoId : false,
modalWidth : 400,
modalHeight : 400,
modalHTML : null,
// initialize()
// Constructor runs on completion of the DOM loading. Calls initList
// and then the function inserts html at the bottom of the page which is used
// to display the shadow overlay and the image container.
initialize: function() {
var s = Drupal.settings.lightbox2;
Lightbox.overlayOpacity = s.overlay_opacity;
Lightbox.overlayColor = s.overlay_color;
Lightbox.resizeSequence = s.resize_sequence;
Lightbox.resizeSpeed = s.resize_speed;
Lightbox.fadeInSpeed = s.fade_in_speed;
Lightbox.slideDownSpeed = s.slide_down_speed;
Lightbox.borderSize = s.border_size;
Lightbox.boxColor = s.box_color;
Lightbox.fontColor = s.font_color;
Lightbox.topPosition = s.top_position;
Lightbox.rtl = s.rtl;
Lightbox.loopItems = s.loop_items;
Lightbox.disableResize = s.disable_resize;
Lightbox.disableZoom = s.disable_zoom;
Lightbox.slideInterval = s.slideshow_interval;
Lightbox.showPlayPause = s.show_play_pause;
Lightbox.autoExit = s.slideshow_automatic_exit;
Lightbox.pauseOnNextClick = s.pause_on_next_click;
Lightbox.pauseOnPrevClick = s.pause_on_previous_click;
Lightbox.loopSlides = s.loop_slides;
Lightbox.alternative_layout = s.use_alt_layout;
Lightbox.iframe_width = s.iframe_width;
Lightbox.iframe_height = s.iframe_height;
Lightbox.iframe_border = s.iframe_border;
Lightbox.enableVideo = s.enable_video;
// Attach lightbox to any links with lightbox rels.
Lightbox.initList();
// Make the lightbox divs.
var output = '<div id="overlay" style="display: none;"></div>\
<div id="lightbox" style="display: none;">\
<div id="outerImageContainer"></div>\
<div id="imageDataContainer" class="clearfix">\
<div id="imageData"></div>\
</div>\
</div>';
var loading = '<div id="loading"><a href="#" id="loadingLink"></a></div>';
var modal = '<div id="modalContainer" style="display: none;"></div>';
var frame = '<div id="frameContainer" style="display: none;"><iframe id="lightboxFrame" style="display: none;"></iframe></div>';
var imageContainer = '<div id="imageContainer" style="display: none;"></div>';
var details = '<div id="imageDetails"></div>';
var bottomNav = '<div id="bottomNav"></div>';
var image = '<img id="lightboxImage" />';
var hoverNav = '<div id="hoverNav"><a id="prevLink" href="#"></a><a id="nextLink" href="#"></a></div>';
var frameNav = '<div id="frameHoverNav"><a id="framePrevLink" href="#"></a><a id="frameNextLink" href="#"></a></div>';
var caption = '<span id="caption"></span>';
var numberDisplay = '<span id="numberDisplay"></span>';
var close = '<a id="bottomNavClose" href="#"></a>';
var zoom = '<a id="bottomNavZoom" href="#"></a>';
var zoomOut = '<a id="bottomNavZoomOut" href="#"></a>';
var pause = '<a id="lightshowPause" href="#" style="display: none;"></a>';
var play = '<a id="lightshowPlay" href="#" style="display: none;"></a>';
$("body").append(output);
$('#outerImageContainer').append(modal + frame + imageContainer + loading);
if (!s.use_alt_layout) {
$('#imageContainer').append(image + hoverNav);
$('#imageData').append(frameNav + details + bottomNav);
$('#imageDetails').append(caption + numberDisplay);
$('#bottomNav').append(close + zoom + zoomOut + pause + play);
}
else {
$('#imageContainer').append(image + bottomNav);
$('#bottomNav').append(close + zoom + zoomOut);
$('#imageData').append(hoverNav + details);
$('#imageDetails').append(caption + numberDisplay + pause + play);
}
// Setup onclick handlers.
$('#overlay').click(function() { Lightbox.end(); return false; } ).hide();
$('#loadingLink, #bottomNavClose').click(function() { Lightbox.end('forceClose'); return false; } );
$('#prevLink, #framePrevLink').click(function() { Lightbox.changeData(Lightbox.activeImage - 1); return false; } );
$('#nextLink, #frameNextLink').click(function() { Lightbox.changeData(Lightbox.activeImage + 1); return false; } );
$('#bottomNavZoom').click(function() { Lightbox.changeData(Lightbox.activeImage, true); return false; } );
$('#bottomNavZoomOut').click(function() { Lightbox.changeData(Lightbox.activeImage, false); return false; } );
$('#lightshowPause').click(function() { Lightbox.togglePlayPause("lightshowPause", "lightshowPlay"); return false; } );
$('#lightshowPlay').click(function() { Lightbox.togglePlayPause("lightshowPlay", "lightshowPause"); return false; } );
// Fix positioning.
$('#prevLink, #nextLink, #framePrevLink, #frameNextLink').css({ paddingTop: Lightbox.borderSize + 'px'});
$('#imageContainer, #frameContainer, #modalContainer').css({ padding: Lightbox.borderSize + 'px'});
$('#outerImageContainer, #imageDataContainer, #bottomNavClose').css({backgroundColor: '#' + Lightbox.boxColor, color: '#'+Lightbox.fontColor});
if (!Lightbox.iframe_border) {
$('#lightboxFrame').css({border: 'none'});
$('#lightboxFrame').attr("frameborder", '0');
}
// Force navigation links to always be displayed
if (s.force_show_nav) {
$('#prevLink, #nextLink').addClass("force_show_nav");
}
},
// initList()
// Loops through anchor tags looking for 'lightbox', 'lightshow' and
// 'lightframe', etc, references and applies onclick events to appropriate
// links. You can rerun after dynamically adding images w/ajax.
initList : function() {
// Attach lightbox to any links with rel 'lightbox', 'lightshow' or
// 'lightframe', etc.
$("a[@rel^='lightbox'], area[@rel^='lightbox']").click(function(e) {
$('#lightbox').click(function() { Lightbox.end('forceClose'); } );
Lightbox.start(this, false, false, false, false);
if (e.preventDefault) { e.preventDefault(); }
return false;
});
$("a[@rel^='lightshow'], area[@rel^='lightshow']").click(function(e) {
$('#lightbox').click(function() { Lightbox.end('forceClose'); } );
Lightbox.start(this, true, false, false, false);
if (e.preventDefault) { e.preventDefault(); }
return false;
});
$("a[@rel^='lightframe'], area[@rel^='lightframe']").click(function(e) {
$('#lightbox').click(function() { Lightbox.end('forceClose'); } );
Lightbox.start(this, false, true, false, false);
if (e.preventDefault) { e.preventDefault(); }
return false;
});
$("a[@rel^='lightvideo'], area[@rel^='lightvideo']").click(function(e) {
$('#lightbox').click(function() { Lightbox.end('forceClose'); } );
Lightbox.start(this, false, false, true, false);
if (e.preventDefault) { e.preventDefault(); }
return false;
});
$("a[@rel^='lightmodal'], area[@rel^='lightmodal']").click(function(e) {
$('#lightbox').unbind('click');
Lightbox.start(this, false, false, false, true);
if (e.preventDefault) { e.preventDefault(); }
return false;
});
},
// start()
// Display overlay and lightbox. If image is part of a set, add siblings to
// imageArray.
start: function(imageLink, slideshow, lightframe, lightvideo, lightmodal) {
Lightbox.isPaused = false;
// Replaces hideSelectBoxes() and hideFlash() calls in original lightbox2.
Lightbox.toggleSelectsFlash('hide');
// Stretch overlay to fill page and fade in.
var arrayPageSize = Lightbox.getPageSize();
$("#overlay").hide().css({
width: '100%',
zIndex: '10090',
height: arrayPageSize[1] + 'px',
backgroundColor : '#' + Lightbox.overlayColor,
opacity : Lightbox.overlayOpacity
}).fadeIn(Lightbox.fadeInSpeed);
Lightbox.isSlideshow = slideshow;
Lightbox.isLightframe = lightframe;
Lightbox.isVideo = lightvideo;
Lightbox.isModal = lightmodal;
Lightbox.imageArray = [];
Lightbox.imageNum = 0;
var anchors = $(imageLink.tagName);
var anchor = null;
var rel_parts = Lightbox.parseRel(imageLink);
var rel = rel_parts["rel"];
var rel_group = rel_parts["group"];
var title = (rel_parts["title"] ? rel_parts["title"] : imageLink.title);
var rel_style = null;
var i = 0;
// Handle lightbox images with no grouping.
if ((rel == 'lightbox' || rel == 'lightshow') && !rel_group) {
Lightbox.imageArray.push([imageLink.href, title]);
}
// Handle iframes with no grouping.
else if ((rel == 'lightframe' || rel == 'lightmodal') && !rel_group) {
rel_style = (!rel_parts["style"] ? 'width: '+ Lightbox.iframe_width +'px; height: '+ Lightbox.iframe_height +'px; scrolling: auto;' : rel_parts["style"]);
Lightbox.imageArray.push([imageLink.href, title, rel_style]);
}
// Handle video.
else if (rel == "lightvideo") {
// rel_group contains style information for videos.
rel_style = (!rel_group ? 'width: 400px; height: 400px;' : rel_group);
Lightbox.imageArray.push([imageLink.href, title, rel_style]);
}
// Handle iframes and lightbox & slideshow images.
else if (rel == 'lightbox' || rel == 'lightshow' || rel == 'lightframe' || rel == 'lightmodal') {
// Loop through anchors and add them to imageArray.
for (i = 0; i < anchors.length; i++) {
anchor = anchors[i];
if (anchor.href && $(anchor).attr('rel')) {
var rel_data = Lightbox.parseRel(anchor);
var anchor_title = (rel_data["title"] ? rel_data["title"] : anchor.title);
if (rel_data["rel"] == rel) {
if (rel_data["group"] == rel_group) {
if (Lightbox.isLightframe || Lightbox.isModal) {
rel_style = (!rel_data["style"] ? 'width: '+ Lightbox.iframe_width +'px; height: '+ Lightbox.iframe_height +'px; scrolling: auto;' : rel_data["style"]);
}
Lightbox.imageArray.push([anchor.href, anchor_title, rel_style]);
}
}
}
}
// Remove duplicates.
for (i = 0; i < Lightbox.imageArray.length; i++) {
for (j = Lightbox.imageArray.length-1; j > i; j--) {
if (Lightbox.imageArray[i][0] == Lightbox.imageArray[j][0]) {
Lightbox.imageArray.splice(j,1);
}
}
}
while (Lightbox.imageArray[Lightbox.imageNum][0] != imageLink.href) {
Lightbox.imageNum++;
}
}
if (Lightbox.isSlideshow && Lightbox.showPlayPause && Lightbox.isPaused) {
$('#lightshowPlay').show();
$('#lightshowPause').hide();
}
// Calculate top and left offset for the lightbox.
var arrayPageScroll = Lightbox.getPageScroll();
var lightboxTop = arrayPageScroll[1] + (Lightbox.topPosition == '' ? (arrayPageSize[3] / 10) : Lightbox.topPosition) * 1;
var lightboxLeft = arrayPageScroll[0];
$('#lightbox').css({
zIndex: '10500',
top: lightboxTop + 'px',
left: lightboxLeft + 'px'
}).show();
Lightbox.total = Lightbox.imageArray.length;
Lightbox.changeData(Lightbox.imageNum);
},
// changeData()
// Hide most elements and preload image in preparation for resizing image
// container.
changeData: function(imageNum, zoomIn) {
if (Lightbox.inprogress === false) {
if (Lightbox.total > 1 && ((Lightbox.isSlideshow && Lightbox.loopSlides) || (!Lightbox.isSlideshow && Lightbox.loopItems))) {
if (imageNum >= Lightbox.total) imageNum = 0;
if (imageNum < 0) imageNum = Lightbox.total - 1;
}
if (Lightbox.isSlideshow) {
for (var i = 0; i < Lightbox.slideIdCount; i++) {
window.clearTimeout(Lightbox.slideIdArray[i]);
}
}
Lightbox.inprogress = true;
Lightbox.activeImage = imageNum;
if (Lightbox.disableResize && !Lightbox.isSlideshow) {
zoomIn = true;
}
Lightbox.isZoomedIn = zoomIn;
// Hide elements during transition.
$('#loading').css({zIndex: '10500'}).show();
if (!Lightbox.alternative_layout) {
$('#imageContainer').hide();
}
$('#frameContainer, #modalContainer, #lightboxImage, #lightboxFrame').hide();
$('#hoverNav, #prevLink, #nextLink, #frameHoverNav, #framePrevLink, #frameNextLink').hide();
$('#imageDataContainer, #numberDisplay, #bottomNavZoom, #bottomNavZoomOut').hide();
// Preload image content, but not iframe pages.
if (!Lightbox.isLightframe && !Lightbox.isVideo && !Lightbox.isModal) {
imgPreloader = new Image();
imgPreloader.onerror = function() { Lightbox.imgNodeLoadingError(this); };
imgPreloader.onload = function() {
var photo = document.getElementById('lightboxImage');
photo.src = Lightbox.imageArray[Lightbox.activeImage][0];
photo.alt = Lightbox.imageArray[Lightbox.activeImage][1];
var imageWidth = imgPreloader.width;
var imageHeight = imgPreloader.height;
// Resize code.
var arrayPageSize = Lightbox.getPageSize();
var targ = { w:arrayPageSize[2] - (Lightbox.borderSize * 2), h:arrayPageSize[3] - (Lightbox.borderSize * 6) - (Lightbox.infoHeight * 4) - (arrayPageSize[3] / 10) };
var orig = { w:imgPreloader.width, h:imgPreloader.height };
// Image is very large, so show a smaller version of the larger image
// with zoom button.
if (zoomIn !== true) {
var ratio = 1.0; // Shrink image with the same aspect.
$('#bottomNavZoomOut, #bottomNavZoom').hide();
if ((orig.w >= targ.w || orig.h >= targ.h) && orig.h && orig.w) {
ratio = ((targ.w / orig.w) < (targ.h / orig.h)) ? targ.w / orig.w : targ.h / orig.h;
if (!Lightbox.disableZoom && !Lightbox.isSlideshow) {
$('#bottomNavZoom').css({zIndex: '10500'}).show();
}
}
imageWidth = Math.floor(orig.w * ratio);
imageHeight = Math.floor(orig.h * ratio);
}
else {
$('#bottomNavZoom').hide();
// Only display zoom out button if the image is zoomed in already.
if ((orig.w >= targ.w || orig.h >= targ.h) && orig.h && orig.w) {
// Only display zoom out button if not a slideshow and if the
// buttons aren't disabled.
if (!Lightbox.disableResize && Lightbox.isSlideshow === false && !Lightbox.disableZoom) {
$('#bottomNavZoomOut').css({zIndex: '10500'}).show();
}
}
}
photo.style.width = (imageWidth) + 'px';
photo.style.height = (imageHeight) + 'px';
Lightbox.resizeContainer(imageWidth, imageHeight);
// Clear onLoad, IE behaves irratically with animated gifs otherwise.
imgPreloader.onload = function() {};
};
imgPreloader.src = Lightbox.imageArray[Lightbox.activeImage][0];
imgPreloader.alt = Lightbox.imageArray[Lightbox.activeImage][1];
}
// Set up frame size, etc.
else if (Lightbox.isLightframe) {
var iframe = document.getElementById('lightboxFrame');
var iframeStyles = Lightbox.imageArray[Lightbox.activeImage][2];
iframe = Lightbox.setStyles(iframe, iframeStyles);
Lightbox.resizeContainer(parseInt(iframe.width, 10), parseInt(iframe.height, 10));
}
else if (Lightbox.isVideo || Lightbox.isModal) {
var container = document.getElementById('modalContainer');
var modalStyles = Lightbox.imageArray[Lightbox.activeImage][2];
container = Lightbox.setStyles(container, modalStyles);
if (Lightbox.isVideo) {
Lightbox.modalHeight = parseInt(container.height, 10);
Lightbox.modalWidth = parseInt(container.width, 10);
Lightvideo.startVideo(Lightbox.imageArray[Lightbox.activeImage][0]);
}
Lightbox.resizeContainer(parseInt(container.width, 10), parseInt(container.height, 10));
}
}
},
// imgNodeLoadingError()
imgNodeLoadingError: function(image) {
var s = Drupal.settings.lightbox2;
var original_image = Lightbox.imageArray[Lightbox.activeImage][0];
if (s.display_image_size !== "") {
original_image = original_image.replace(new RegExp("."+s.display_image_size), "");
}
Lightbox.imageArray[Lightbox.activeImage][0] = original_image;
image.onerror = function() { Lightbox.imgLoadingError(image); };
image.src = original_image;
},
// imgLoadingError()
imgLoadingError: function(image) {
var s = Drupal.settings.lightbox2;
Lightbox.imageArray[Lightbox.activeImage][0] = s.default_image;
image.src = s.default_image;
},
// resizeContainer()
resizeContainer: function(imgWidth, imgHeight) {
this.widthCurrent = $('#outerImageContainer').width();
this.heightCurrent = $('#outerImageContainer').height();
var widthNew = (imgWidth + (Lightbox.borderSize * 2));
var heightNew = (imgHeight + (Lightbox.borderSize * 2));
// Scalars based on change from old to new.
this.xScale = ( widthNew / this.widthCurrent) * 100;
this.yScale = ( heightNew / this.heightCurrent) * 100;
// Calculate size difference between new and old image, and resize if
// necessary.
wDiff = this.widthCurrent - widthNew;
hDiff = this.heightCurrent - heightNew;
// Detect animation sequence.
if (Lightbox.resizeSequence) {
var animate1 = {width: widthNew};
var animate2 = {height: heightNew};
if (Lightbox.resizeSequence == 2) {
animate1 = {height: heightNew};
animate2 = {width: widthNew};
}
$('#outerImageContainer').animate(animate1, Lightbox.resizeSpeed).animate(animate2, Lightbox.resizeSpeed, 'linear', function() { Lightbox.showData(); });
}
// Simultaneous.
else {
$('#outerImageContainer').animate({width: widthNew, height: heightNew}, Lightbox.resizeSpeed, 'linear', function() { Lightbox.showData(); });
}
// If new and old image are same size and no scaling transition is necessary
// do a quick pause to prevent image flicker.
if ((hDiff === 0) && (wDiff === 0)) {
if ($.browser.msie) {
Lightbox.pause(250);
}
else {
Lightbox.pause(100);
}
}
var s = Drupal.settings.lightbox2;
if (!s.use_alt_layout) {
$('#prevLink, #nextLink').css({height: imgHeight + 'px'});
}
$('#imageDataContainer').css({width: widthNew + 'px'});
},
// showData()
// Display image and begin preloading neighbors.
showData: function() {
$('#loading').hide();
if (Lightbox.isLightframe || Lightbox.isVideo || Lightbox.isModal) {
Lightbox.updateDetails();
if (Lightbox.isLightframe) {
$('#frameContainer').show();
if ($.browser.safari) {
$('#lightboxFrame').css({zIndex: '10500'}).show();
}
else {
$('#lightboxFrame').css({zIndex: '10500'}).fadeIn(Lightbox.fadeInSpeed);
}
try {
document.getElementById("lightboxFrame").src = Lightbox.imageArray[Lightbox.activeImage][0];
} catch(e) {}
}
else {
if (Lightbox.isVideo) {
$("#modalContainer").html(Lightbox.modalHTML);
$("#modalContainer").click(function() { return false; } );
}
else {
$("#modalContainer").load(Lightbox.imageArray[Lightbox.activeImage][0]);
$('#modalContainer').unbind('click');
}
$('#modalContainer').css({zIndex: '10500'}).show();
}
}
// Handle display of image content.
else {
$('#imageContainer').show();
if($.browser.safari) {
$('#lightboxImage').css({zIndex: '10500'}).show();
}
else {
$('#lightboxImage').css({zIndex: '10500'}).fadeIn(Lightbox.fadeInSpeed);
}
Lightbox.updateDetails();
this.preloadNeighborImages();
}
Lightbox.inprogress = false;
// Slideshow specific stuff.
if (Lightbox.isSlideshow) {
if (!Lightbox.loopSlides && Lightbox.activeImage == (Lightbox.total - 1)) {
if (Lightbox.autoExit) {
Lightbox.slideIdArray[Lightbox.slideIdCount++] = setTimeout(function () {Lightbox.end('slideshow');}, Lightbox.slideInterval);
}
}
else {
if (!Lightbox.isPaused) {
Lightbox.slideIdArray[Lightbox.slideIdCount++] = setTimeout(function () {Lightbox.changeData(Lightbox.activeImage + 1);}, Lightbox.slideInterval);
}
}
if (Lightbox.showPlayPause && Lightbox.total > 1 && !Lightbox.isPaused) {
$('#lightshowPause').show();
$('#lightshowPlay').hide();
}
else if (Lightbox.showPlayPause && Lightbox.total > 1) {
$('#lightshowPause').hide();
$('#lightshowPlay').show();
}
}
// Adjust the page overlay size.
var arrayPageSize = Lightbox.getPageSize();
var arrayPageScroll = Lightbox.getPageScroll();
var pageHeight = arrayPageSize[1];
if (Lightbox.isZoomedIn && arrayPageSize[1] > arrayPageSize[3]) {
var lightboxTop = (Lightbox.topPosition == '' ? (arrayPageSize[3] / 10) : Lightbox.topPosition) * 1;
pageHeight = pageHeight + arrayPageScroll[1] + lightboxTop;
}
$('#overlay').css({height: pageHeight + 'px', width: arrayPageSize[0] + 'px'});
// Gecko browsers (e.g. Firefox, SeaMonkey, etc) don't handle pdfs as
// expected.
if ($.browser.mozilla) {
if (Lightbox.imageArray[Lightbox.activeImage][0].indexOf(".pdf") != -1) {
setTimeout(function () {
document.getElementById("lightboxFrame").src = Lightbox.imageArray[Lightbox.activeImage][0];
}, 1000);
}
}
},
// updateDetails()
// Display caption, image number, and bottom nav.
updateDetails: function() {
$("#imageDataContainer").hide();
var caption = Lightbox.imageArray[Lightbox.activeImage][1];
if (!caption) caption = '&nbsp;';
$('#caption').html(caption).css({zIndex: '10500'}).show();
// If image is part of set display 'Image x of x'.
var s = Drupal.settings.lightbox2;
var numberDisplay = null;
if (Lightbox.total > 1) {
var currentImage = Lightbox.activeImage + 1;
if (!Lightbox.isLightframe) {
numberDisplay = s.image_count.replace(/\!current/, currentImage).replace(/\!total/, Lightbox.total);
}
else {
numberDisplay = s.page_count.replace(/\!current/, currentImage).replace(/\!total/, Lightbox.total);
}
$('#numberDisplay').html(numberDisplay).css({zIndex: '10500'}).show();
}
$("#imageDataContainer").hide().slideDown(Lightbox.slideDownSpeed);
if (Lightbox.rtl) {
$("#bottomNav").css({float: 'left'});
}
Lightbox.updateNav();
},
// updateNav()
// Display appropriate previous and next hover navigation.
updateNav: function() {
$('#hoverNav').css({zIndex: '10500'}).show();
var prevLink = '#prevLink';
var nextLink = '#nextLink';
// Slideshow is separated as we need to show play / pause button.
if (Lightbox.isSlideshow) {
if ((Lightbox.total > 1 && Lightbox.loopSlides) || Lightbox.activeImage !== 0) {
$(prevLink).css({zIndex: '10500'}).show().click(function() {
if (Lightbox.pauseOnPrevClick) {
Lightbox.togglePlayPause("lightshowPause", "lightshowPlay");
}
Lightbox.changeData(Lightbox.activeImage - 1); return false;
});
}
else {
$(prevLink).hide();
}
// If not last image in set, display next image button.
if ((Lightbox.total > 1 && Lightbox.loopSlides) || Lightbox.activeImage != (Lightbox.total - 1)) {
$(nextLink).css({zIndex: '10500'}).show().click(function() {
if (Lightbox.pauseOnNextClick) {
Lightbox.togglePlayPause("lightshowPause", "lightshowPlay");
}
Lightbox.changeData(Lightbox.activeImage + 1); return false;
});
}
// Safari browsers need to have hide() called again.
else {
$(nextLink).hide();
}
}
// All other types of content.
else {
if (Lightbox.isLightframe && !Lightbox.alternative_layout) {
$('#frameHoverNav').css({zIndex: '10500'}).show();
$('#hoverNav').css({zIndex: '10500'}).hide();
prevLink = '#framePrevLink';
nextLink = '#frameNextLink';
}
// If not first image in set, display prev image button.
if ((Lightbox.total > 1 && Lightbox.loopItems) || Lightbox.activeImage !== 0) {
$(prevLink).css({zIndex: '10500'}).show().click(function() {
Lightbox.changeData(Lightbox.activeImage - 1); return false;
});
}
// Safari browsers need to have hide() called again.
else {
$(prevLink).hide();
}
// If not last image in set, display next image button.
if ((Lightbox.total > 1 && Lightbox.loopItems) || Lightbox.activeImage != (Lightbox.total - 1)) {
$(nextLink).css({zIndex: '10500'}).show().click(function() {
Lightbox.changeData(Lightbox.activeImage + 1); return false;
});
}
// Safari browsers need to have hide() called again.
else {
$(nextLink).hide();
}
}
if (!Lightbox.isModal) {
this.enableKeyboardNav();
}
},
// enableKeyboardNav()
enableKeyboardNav: function() {
$(document).bind("keydown", this.keyboardAction);
},
// disableKeyboardNav()
disableKeyboardNav: function() {
$(document).unbind("keydown", this.keyboardAction);
},
// keyboardAction()
keyboardAction: function(e) {
if (e === null) { // IE.
keycode = event.keyCode;
escapeKey = 27;
}
else { // Mozilla.
keycode = e.keyCode;
escapeKey = e.DOM_VK_ESCAPE;
}
key = String.fromCharCode(keycode).toLowerCase();
// Close lightbox.
if (key == 'x' || key == 'o' || key == 'c' || keycode == escapeKey) {
Lightbox.end('forceClose');
// Display previous image (p, <-).
}
else if (key == 'p' || keycode == 37) {
if ((Lightbox.total > 1 && ((Lightbox.isSlideshow && Lightbox.loopSlides) || (!Lightbox.isSlideshow && Lightbox.loopItems))) || Lightbox.activeImage !== 0) {
Lightbox.changeData(Lightbox.activeImage - 1);
}
// Display next image (n, ->).
}
else if (key == 'n' || keycode == 39) {
if ((Lightbox.total > 1 && ((Lightbox.isSlideshow && Lightbox.loopSlides) || (!Lightbox.isSlideshow && Lightbox.loopItems))) || Lightbox.activeImage != (Lightbox.total - 1)) {
Lightbox.changeData(Lightbox.activeImage + 1);
}
}
// Zoom in.
else if (key == 'z' && !Lightbox.disableResize && !Lightbox.disableZoom && !Lightbox.isSlideshow && !Lightbox.isLightframe) {
if (Lightbox.isZoomedIn) {
Lightbox.changeData(Lightbox.activeImage, false);
}
else if (!Lightbox.isZoomedIn) {
Lightbox.changeData(Lightbox.activeImage, true);
}
return false;
}
// Toggle play / pause (space).
else if (keycode == 32 && Lightbox.isSlideshow) {
if (Lightbox.isPaused) {
Lightbox.togglePlayPause("lightshowPlay", "lightshowPause");
}
else {
Lightbox.togglePlayPause("lightshowPause", "lightshowPlay");
}
return false;
}
},
preloadNeighborImages: function() {
if ((Lightbox.total - 1) > Lightbox.activeImage) {
preloadNextImage = new Image();
preloadNextImage.src = Lightbox.imageArray[Lightbox.activeImage + 1][0];
}
if (Lightbox.activeImage > 0) {
preloadPrevImage = new Image();
preloadPrevImage.src = Lightbox.imageArray[Lightbox.activeImage - 1][0];
}
},
end: function(caller) {
var closeClick = (caller == 'slideshow' ? false : true);
if (Lightbox.isSlideshow && Lightbox.isPaused && !closeClick) {
return;
}
// To prevent double clicks on navigation links.
if (Lightbox.inprogress === true && caller != 'forceClose') {
return;
}
Lightbox.disableKeyboardNav();
$('#lightbox').hide();
$("#overlay").fadeOut();
Lightbox.isPaused = true;
Lightbox.inprogress = false;
// Replaces calls to showSelectBoxes() and showFlash() in original
// lightbox2.
Lightbox.toggleSelectsFlash('visible');
if (Lightbox.isSlideshow) {
for (var i = 0; i < Lightbox.slideIdCount; i++) {
window.clearTimeout(Lightbox.slideIdArray[i]);
}
$('#lightshowPause, #lightshowPlay').hide();
}
else if (Lightbox.isLightframe) {
document.getElementById("lightboxFrame").src = '';
if ($.browser.safari) {
var iFrame = document.getElementById("lightboxFrame");
var parent = iFrame.parentNode;
parent.removeChild(iFrame);
parent.appendChild(iFrame);
}
$('#lightboxFrame, #frameContainer').hide();
}
else if (Lightbox.isVideo || Lightbox.isModal) {
$('#modalContainer').hide();
$('#modalContainer').html("");
}
},
// getPageScroll()
// Returns array with x,y page scroll values.
// Core code from - quirksmode.com.
getPageScroll : function() {
var xScroll, yScroll;
if (self.pageYOffset) {
yScroll = self.pageYOffset;
xScroll = self.pageXOffset;
}
else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict.
yScroll = document.documentElement.scrollTop;
xScroll = document.documentElement.scrollLeft;
}
else if (document.body) {// All other Explorers.
yScroll = document.body.scrollTop;
xScroll = document.body.scrollLeft;
}
arrayPageScroll = [xScroll,yScroll];
return arrayPageScroll;
},
// getPageSize()
// Returns array with page width, height and window width, height.
// Core code from - quirksmode.com.
// Edit for Firefox by pHaez.
getPageSize : function() {
var xScroll, yScroll;
if (document.body.scrollHeight > document.body.offsetHeight) { // all but Explorer Mac
xScroll = document.body.scrollWidth;
yScroll = document.body.scrollHeight;
}
else if (window.innerHeight && window.scrollMaxY) {
xScroll = window.innerWidth + window.scrollMaxX;
yScroll = window.innerHeight + window.scrollMaxY;
}
// Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari.
else {
xScroll = document.body.offsetWidth;
yScroll = document.body.offsetHeight;
}
var windowWidth, windowHeight;
if (self.innerHeight) { // All except Explorer.
if (document.documentElement.clientWidth) {
windowWidth = document.documentElement.clientWidth;
}
else {
windowWidth = self.innerWidth;
}
windowHeight = self.innerHeight;
}
// Explorer 6 Strict Mode.
else if (document.documentElement && document.documentElement.clientHeight) {
windowWidth = document.documentElement.clientWidth;
windowHeight = document.documentElement.clientHeight;
}
else if (document.body) { // Other Explorers.
windowWidth = document.body.clientWidth;
windowHeight = document.body.clientHeight;
}
// For small pages with total height less then height of the viewport.
if (yScroll < windowHeight) {
pageHeight = windowHeight;
}
else {
pageHeight = yScroll;
}
// For small pages with total width less then width of the viewport.
if (xScroll < windowWidth) {
pageWidth = windowWidth;
}
else {
pageWidth = xScroll;
}
arrayPageSize = [pageWidth, pageHeight, windowWidth, windowHeight];
return arrayPageSize;
},
// pause(numberMillis)
pause : function(ms) {
var date = new Date();
var curDate = null;
do { curDate = new Date(); }
while (curDate - date < ms);
},
// toggleSelectsFlash()
// Hide / unhide select lists and flash objects as they appear above the
// lightbox in some browsers.
toggleSelectsFlash: function (state) {
if (state == 'visible') {
$("select.lightbox_hidden, embed.lightbox_hidden, object.lightbox_hidden").show();
}
else if (state == 'hide') {
$("select:visible, embed:visible, object:visible").addClass("lightbox_hidden");
$("select.lightbox_hidden, embed.lightbox_hidden, object.lightbox_hidden").hide();
}
},
// parseRel()
parseRel: function (link) {
var parts = [];
parts["rel"] = $(link).attr('rel').match(/\w+/)[0];
parts["title"] = parts["group"] = parts["style"] = null;
if ($(link).attr('rel').match(/\[(.*)\]/)) {
var info = $(link).attr('rel').match(/\[(.*?)\]/)[1].split('|');
parts["group"] = info[0];
parts["style"] = info[1];
}
if ($(link).attr('rel').match(/\[.*\]\[(.*)\]/)) {
parts["title"] = $(link).attr('rel').match(/\[.*\]\[(.*)\]/)[1];
}
return parts;
},
// setStyles()
setStyles: function(item, styles) {
var stylesArray = styles.split(';');
for (var i = 0; i< stylesArray.length; i++) {
if (stylesArray[i].indexOf('width:') >= 0) {
var w = stylesArray[i].replace('width:', '');
item.width = jQuery.trim(w);
}
else if (stylesArray[i].indexOf('height:') >= 0) {
var h = stylesArray[i].replace('height:', '');
item.height = jQuery.trim(h);
}
else if (stylesArray[i].indexOf('scrolling:') >= 0) {
var scrolling = stylesArray[i].replace('scrolling:', '');
item.scrolling = jQuery.trim(scrolling);
}
else if (stylesArray[i].indexOf('overflow:') >= 0) {
var overflow = stylesArray[i].replace('overflow:', '');
item.overflow = jQuery.trim(overflow);
}
}
return item;
},
// togglePlayPause()
// Hide the pause / play button as appropriate. If pausing the slideshow also
// clear the timers, otherwise move onto the next image.
togglePlayPause: function(hideId, showId) {
if (Lightbox.isSlideshow && hideId == "lightshowPause") {
for (var i = 0; i < Lightbox.slideIdCount; i++) {
window.clearTimeout(Lightbox.slideIdArray[i]);
}
}
$('#' + hideId).hide();
$('#' + showId).show();
if (hideId == "lightshowPlay") {
Lightbox.isPaused = false;
if (!Lightbox.loopSlides && Lightbox.activeImage == (Lightbox.total - 1)) {
Lightbox.end();
}
else {
Lightbox.changeData(Lightbox.activeImage + 1);
}
}
else {
Lightbox.isPaused = true;
}
}
};
// Initialize the lightbox.
Drupal.behaviors.initLightbox = function (context) {
Lightbox.initialize();
};
;// $Id: panels.js,v 1.2.4.1 2009/10/05 22:40:35 merlinofchaos Exp $
(function ($) {
Drupal.Panels = {};
Drupal.Panels.autoAttach = function() {
if ($.browser.msie) {
// If IE, attach a hover event so we can see our admin links.
$("div.panel-pane").hover(
function() {
$('div.panel-hide', this).addClass("panel-hide-hover"); return true;
},
function() {
$('div.panel-hide', this).removeClass("panel-hide-hover"); return true;
}
);
$("div.admin-links").hover(
function() {
$(this).addClass("admin-links-hover"); return true;
},
function(){
$(this).removeClass("admin-links-hover"); return true;
}
);
}
};
$(Drupal.Panels.autoAttach);
})(jQuery);
;// $Id: jquery.form.js,v 1.2 2007/11/19 10:05:48 goba Exp $
/*
* jQuery Form Plugin
* version: 2.01 (10/31/2007)
* @requires jQuery v1.1 or later
*
* Examples at: http://malsup.com/jquery/form/
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(5($){$.7.1j=5(o){2(P o==\'5\')o={L:o};o=$.2h({1h:4.X(\'2i\')||1E.2u.3D(),I:4.X(\'2g\')||\'29\'},o||{});3 p={};$.M.N(\'R.2P.2L\',[4,o,p]);2(p.1Q)6 4;3 a=4.1z(o.2r);2(o.V){H(3 n 3u o.V)a.C({z:n,A:o.V[n]})}2(o.28&&o.28(a,4,o)===E)6 4;$.M.N(\'R.K.36\',[a,4,o,p]);2(p.1Q)6 4;3 q=$.1x(a);2(o.I.31()==\'29\'){o.1h+=(o.1h.2Z(\'?\')>=0?\'&\':\'?\')+q;o.V=B}8 o.V=q;3 r=4,U=[];2(o.1r)U.C(5(){r.1r()});2(o.1o)U.C(5(){r.1o()});2(!o.18&&o.14){3 u=o.L||5(){};U.C(5(a){2(4.1N)$(o.14).X("1M",a).1N().D(u,1L);8 $(o.14).2t(a).D(u,1L)})}8 2(o.L)U.C(o.L);o.L=5(a,b){H(3 i=0,F=U.G;i<F;i++)U[i](a,b,r)};3 v=$(\'19:3v\',4).15();3 w=E;H(3 j=0;j<v.G;j++)2(v[j])w=T;2(o.2f||w){2($.1i.3o&&o.2a)$.3l(o.2a,1l);8 1l()}8 $.3h(o);$.M.N(\'R.K.3f\',[4,o]);6 4;5 1l(){3 d=r[0];3 f=$.2h({},$.39,o);3 h=\'35\'+$.7.1j.1a++;3 i=$(\'<2f 33="\'+h+\'" z="\'+h+\'" />\');3 j=i[0];3 k=$.1i.20&&1E.20.30()<9;2($.1i.1X||k)j.2Y=\'2W:E;1w.2U("");\';i.2S({2R:\'2Q\',23:\'-24\',1R:\'-24\'});3 l={Z:B,1b:B,2K:0,2J:\'n/a\',2H:5(){},2F:5(){},2E:5(){}};3 g=f.2B;2(g&&!$.1O++)$.M.N("2x");2(g)$.M.N("2w",[l,f]);3 m=0;3 n=0;1f(5(){i.2v(\'1n\');j.1K?j.1K(\'1J\',12):j.2s(\'1I\',12,E);3 a=d.1H?\'1H\':\'2q\';3 t=r.X(\'14\');r.X({14:h,2g:\'3C\',2i:f.1h});d[a]=\'3B/R-V\';2(f.1G)1f(5(){n=T;12()},f.1G);d.K();r.X(\'14\',t)},10);5 12(){2(m++)6;j.2o?j.2o(\'1J\',12):j.3A(\'1I\',12,E);3 a=T;3z{2(n)3x\'1G\';3 b,O;O=j.2n?j.2n.1w:j.2l?j.2l:j.1w;l.Z=O.1n?O.1n.1M:B;l.1b=O.2k?O.2k:O;2(f.18==\'2j\'||f.18==\'3s\'){3 c=O.1D(\'1C\')[0];b=c?c.A:l.Z;2(f.18==\'2j\')3r("V = "+b);8 $.3q(b)}8 2(f.18==\'2m\'){b=l.1b;2(!b&&l.Z!=B)b=2d(l.Z)}8{b=l.Z}}3p(e){a=E;$.3n(f,l,\'2b\',e)}2(a){f.L(b,\'L\');2(g)$.M.N("3m",[l,f])}2(g)$.M.N("3k",[l,f]);2(g&&!--$.1O)$.M.N("3j");2(f.27)f.27(l,a?\'L\':\'2b\');1f(5(){i.3i();l.1b=B},3g)};5 2d(s,a){2(1E.26){a=25 26(\'3d.3c\');a.3b=\'E\';a.3a(s)}8 a=(25 38()).37(s,\'1A/2m\');6(a&&a.22&&a.22.1e!=\'34\')?a:B}}};$.7.1j.1a=0;$.7.W=5(a){6 4.21().K(1m).D(5(){4.1u=$.7.W.1a++;$.7.W.1t[4.1u]=a;$(":K,19:Y",4).1Z(1s)})};$.7.W.1a=1;$.7.W.1t={};5 1s(e){3 a=4.R;a.Q=4;2(4.I==\'Y\'){2(e.1Y!=S){a.11=e.1Y;a.16=e.2X}8 2(P $.7.1U==\'5\'){3 b=$(4).1U();a.11=e.1V-b.1R;a.16=e.1W-b.23}8{a.11=e.1V-4.2V;a.16=e.1W-4.32}}1f(5(){a.Q=a.11=a.16=B},10)};5 1m(){3 a=4.1u;3 b=$.7.W.1t[a];$(4).1j(b);6 E};$.7.21=5(){4.1T(\'K\',1m);6 4.D(5(){$(":K,19:Y",4).1T(\'1Z\',1s)})};$.7.1z=5(b){3 a=[];2(4.G==0)6 a;3 c=4[0];3 d=b?c.1D(\'*\'):c.2T;2(!d)6 a;H(3 i=0,F=d.G;i<F;i++){3 e=d[i];3 n=e.z;2(!n)1v;2(b&&c.Q&&e.I=="Y"){2(!e.1d&&c.Q==e)a.C({z:n+\'.x\',A:c.11},{z:n+\'.y\',A:c.16});1v}3 v=$.15(e,T);2(v&&v.1c==1g){H(3 j=0,1S=v.G;j<1S;j++)a.C({z:n,A:v[j]})}8 2(v!==B&&P v!=\'S\')a.C({z:n,A:v})}2(!b&&c.Q){3 f=c.1D("19");H(3 i=0,F=f.G;i<F;i++){3 g=f[i];3 n=g.z;2(n&&!g.1d&&g.I=="Y"&&c.Q==g)a.C({z:n+\'.x\',A:c.11},{z:n+\'.y\',A:c.16})}}6 a};$.7.2O=5(a){6 $.1x(4.1z(a))};$.7.2N=5(b){3 a=[];4.D(5(){3 n=4.z;2(!n)6;3 v=$.15(4,b);2(v&&v.1c==1g){H(3 i=0,F=v.G;i<F;i++)a.C({z:n,A:v[i]})}8 2(v!==B&&P v!=\'S\')a.C({z:4.z,A:v})});6 $.1x(a)};$.7.15=5(a){H(3 b=[],i=0,F=4.G;i<F;i++){3 c=4[i];3 v=$.15(c,a);2(v===B||P v==\'S\'||(v.1c==1g&&!v.G))1v;v.1c==1g?$.3e(b,v):b.C(v)}6 b};$.15=5(b,c){3 n=b.z,t=b.I,13=b.1e.1F();2(P c==\'S\')c=T;2(c&&(!n||b.1d||t==\'17\'||t==\'2M\'||(t==\'1q\'||t==\'1B\')&&!b.1p||(t==\'K\'||t==\'Y\')&&b.R&&b.R.Q!=b||13==\'J\'&&b.1y==-1))6 B;2(13==\'J\'){3 d=b.1y;2(d<0)6 B;3 a=[],1k=b.2I;3 e=(t==\'J-2e\');3 f=(e?d+1:1k.G);H(3 i=(e?d:0);i<f;i++){3 g=1k[i];2(g.2c){3 v=$.1i.1X&&!(g.2G[\'A\'].3t)?g.1A:g.A;2(e)6 v;a.C(v)}}6 a}6 b.A};$.7.1o=5(){6 4.D(5(){$(\'19,J,1C\',4).2p()})};$.7.2p=$.7.2D=5(){6 4.D(5(){3 t=4.I,13=4.1e.1F();2(t==\'1A\'||t==\'3w\'||13==\'1C\')4.A=\'\';8 2(t==\'1q\'||t==\'1B\')4.1p=E;8 2(13==\'J\')4.1y=-1})};$.7.1r=5(){6 4.D(5(){2(P 4.17==\'5\'||(P 4.17==\'2C\'&&!4.17.3y))4.17()})};$.7.2A=5(b){2(b==S)b=T;6 4.D(5(){
;// $Id: ahah.js,v 1.7.2.1 2008/02/11 14:46:27 goba Exp $
/**
* Provides AJAX-like page updating via AHAH (Asynchronous HTML and HTTP).
*
* AHAH is a method of making a request via Javascript while viewing an HTML
* page. The request returns a small chunk of HTML, which is then directly
* injected into the page.
*
* Drupal uses this file to enhance form elements with #ahah[path] and
* #ahah[wrapper] properties. If set, this file will automatically be included
* to provide AHAH capabilities.
*/
/**
* Attaches the ahah behavior to each ahah form element.
*/
Drupal.behaviors.ahah = function(context) {
for (var base in Drupal.settings.ahah) {
if (!$('#'+ base + '.ahah-processed').size()) {
var element_settings = Drupal.settings.ahah[base];
$(element_settings.selector).each(function() {
element_settings.element = this;
var ahah = new Drupal.ahah(base, element_settings);
});
$('#'+ base).addClass('ahah-processed');
}
}
};
/**
* AHAH object.
*/
Drupal.ahah = function(base, element_settings) {
// Set the properties for this object.
this.element = element_settings.element;
this.selector = element_settings.selector;
this.event = element_settings.event;
this.keypress = element_settings.keypress;
this.url = element_settings.url;
this.wrapper = '#'+ element_settings.wrapper;
this.effect = element_settings.effect;
this.method = element_settings.method;
this.progress = element_settings.progress;
this.button = element_settings.button || { };
if (this.effect == 'none') {
this.showEffect = 'show';
this.hideEffect = 'hide';
this.showSpeed = '';
}
else if (this.effect == 'fade') {
this.showEffect = 'fadeIn';
this.hideEffect = 'fadeOut';
this.showSpeed = 'slow';
}
else {
this.showEffect = this.effect + 'Toggle';
this.hideEffect = this.effect + 'Toggle';
this.showSpeed = 'slow';
}
// Record the form action and target, needed for iFrame file uploads.
var form = $(this.element).parents('form');
this.form_action = form.attr('action');
this.form_target = form.attr('target');
this.form_encattr = form.attr('encattr');
// Set the options for the ajaxSubmit function.
// The 'this' variable will not persist inside of the options object.
var ahah = this;
var options = {
url: ahah.url,
data: ahah.button,
beforeSubmit: function(form_values, element_settings, options) {
return ahah.beforeSubmit(form_values, element_settings, options);
},
success: function(response, status) {
// Sanity check for browser support (object expected).
// When using iFrame uploads, responses must be returned as a string.
if (typeof(response) == 'string') {
response = Drupal.parseJson(response);
}
return ahah.success(response, status);
},
complete: function(response, status) {
if (status == 'error' || status == 'parsererror') {
return ahah.error(response, ahah.url);
}
},
dataType: 'json',
type: 'POST'
};
// Bind the ajaxSubmit function to the element event.
$(element_settings.element).bind(element_settings.event, function() {
$(element_settings.element).parents('form').ajaxSubmit(options);
return false;
});
// If necessary, enable keyboard submission so that AHAH behaviors
// can be triggered through keyboard input as well as e.g. a mousedown
// action.
if (element_settings.keypress) {
$(element_settings.element).keypress(function(event) {
// Detect enter key.
if (event.keyCode == 13) {
$(element_settings.element).trigger(element_settings.event);
return false;
}
});
}
};
/**
* Handler for the form redirection submission.
*/
Drupal.ahah.prototype.beforeSubmit = function (form_values, element, options) {
// Disable the element that received the change.
$(this.element).addClass('progress-disabled').attr('disabled', true);
// Insert progressbar or throbber.
if (this.progress.type == 'bar') {
var progressBar = new Drupal.progressBar('ahah-progress-' + this.element.id, eval(this.progress.update_callback), this.progress.method, eval(this.progress.error_callback));
if (this.progress.message) {
progressBar.setProgress(-1, this.progress.message);
}
if (this.progress.url) {
progressBar.startMonitoring(this.progress.url, this.progress.interval || 1500);
}
this.progress.element = $(progressBar.element).addClass('ahah-progress ahah-progress-bar');
this.progress.object = progressBar;
$(this.element).after(this.progress.element);
}
else if (this.progress.type == 'throbber') {
this.progress.element = $('<div class="ahah-progress ahah-progress-throbber"><div class="throbber">&nbsp;</div></div>');
if (this.progress.message) {
$('.throbber', this.progress.element).after('<div class="message">' + this.progress.message + '</div>')
}
$(this.element).after(this.progress.element);
}
};
/**
* Handler for the form redirection completion.
*/
Drupal.ahah.prototype.success = function (response, status) {
var wrapper = $(this.wrapper);
var form = $(this.element).parents('form');
// Manually insert HTML into the jQuery object, using $() directly crashes
// Safari with long string lengths. http://dev.jquery.com/ticket/1152
var new_content = $('<div></div>').html(response.data);
// Restore the previous action and target to the form.
form.attr('action', this.form_action);
this.form_target ? form.attr('target', this.form_target) : form.removeAttr('target');
this.form_encattr ? form.attr('target', this.form_encattr) : form.removeAttr('encattr');
// Remove the progress element.
if (this.progress.element) {
$(this.progress.element).remove();
}
if (this.progress.object) {
this.progress.object.stopMonitoring();
}
$(this.element).removeClass('progress-disabled').attr('disabled', false);
// Add the new content to the page.
Drupal.freezeHeight();
if (this.method == 'replace') {
wrapper.empty().append(new_content);
}
else {
wrapper[this.method](new_content);
}
// Immediately hide the new content if we're using any effects.
if (this.showEffect != 'show') {
new_content.hide();
}
// Determine what effect use and what content will receive the effect, then
// show the new content. For browser compatibility, Safari is excluded from
// using effects on table rows.
if (($.browser.safari && $("tr.ahah-new-content", new_content).size() > 0)) {
new_content.show();
}
else if ($('.ahah-new-content', new_content).size() > 0) {
$('.ahah-new-content', new_content).hide();
new_content.show();
$(".ahah-new-content", new_content)[this.showEffect](this.showSpeed);
}
else if (this.showEffect != 'show') {
new_content[this.showEffect](this.showSpeed);
}
// Attach all javascript behaviors to the new content, if it was successfully
// added to the page, this if statement allows #ahah[wrapper] to be optional.
if (new_content.parents('html').length > 0) {
Drupal.attachBehaviors(new_content);
}
Drupal.unfreezeHeight();
};
/**
* Handler for the form redirection error.
*/
Drupal.ahah.prototype.error = function (response, uri) {
alert(Drupal.ahahError(response, uri));
// Resore the previous action and target to the form.
$(this.element).parent('form').attr( { action: this.form_action, target: this.form_target} );
// Remove the progress element.
if (this.progress.element) {
$(this.progress.element).remove();
}
if (this.progress.object) {
this.progress.object.stopMonitoring();
}
// Undo hide.
$(this.wrapper).show();
// Re-enable the element.
$(this.element).removeClass('progess-disabled').attr('disabled', false);
};
;// $Id: progress.js,v 1.20 2008/01/04 11:53:21 goba Exp $
/**
* A progressbar object. Initialized with the given id. Must be inserted into
* the DOM afterwards through progressBar.element.
*
* method is the function which will perform the HTTP request to get the
* progress bar state. Either "GET" or "POST".
*
* e.g. pb = new progressBar('myProgressBar');
* some_element.appendChild(pb.element);
*/
Drupal.progressBar = function (id, updateCallback, method, errorCallback) {
var pb = this;
this.id = id;
this.method = method || "GET";
this.updateCallback = updateCallback;
this.errorCallback = errorCallback;
this.element = document.createElement('div');
this.element.id = id;
this.element.className = 'progress';
$(this.element).html('<div class="bar"><div class="filled"></div></div>'+
'<div class="percentage"></div>'+
'<div class="message">&nbsp;</div>');
};
/**
* Set the percentage and status message for the progressbar.
*/
Drupal.progressBar.prototype.setProgress = function (percentage, message) {
if (percentage >= 0 && percentage <= 100) {
$('div.filled', this.element).css('width', percentage +'%');
$('div.percentage', this.element).html(percentage +'%');
}
$('div.message', this.element).html(message);
if (this.updateCallback) {
this.updateCallback(percentage, message, this);
}
};
/**
* Start monitoring progress via Ajax.
*/
Drupal.progressBar.prototype.startMonitoring = function (uri, delay) {
this.delay = delay;
this.uri = uri;
this.sendPing();
};
/**
* Stop monitoring progress via Ajax.
*/
Drupal.progressBar.prototype.stopMonitoring = function () {
clearTimeout(this.timer);
// This allows monitoring to be stopped from within the callback
this.uri = null;
};
/**
* Request progress data from server.
*/
Drupal.progressBar.prototype.sendPing = function () {
if (this.timer) {
clearTimeout(this.timer);
}
if (this.uri) {
var pb = this;
// When doing a post request, you need non-null data. Otherwise a
// HTTP 411 or HTTP 406 (with Apache mod_security) error may result.
$.ajax({
type: this.method,
url: this.uri,
data: '',
dataType: 'json',
success: function (progress) {
// Display errors
if (progress.status == 0) {
pb.displayError(progress.data);
return;
}
// Update display
pb.setProgress(progress.percentage, progress.message);
// Schedule next timer
pb.timer = setTimeout(function() { pb.sendPing(); }, pb.delay);
},
error: function (xmlhttp) {
pb.displayError(Drupal.ahahError(xmlhttp, pb.uri));
}
});
}
};
/**
* Display errors on the page.
*/
Drupal.progressBar.prototype.displayError = function (string) {
var error = document.createElement('div');
error.className = 'error';
error.innerHTML = string;
$(this.element).before(error).hide();
if (this.errorCallback) {
this.errorCallback(this);
}
};
;// $Id: autocomplete.js,v 1.23 2008/01/04 11:53:21 goba Exp $
/**
* Attaches the autocomplete behavior to all required fields
*/
Drupal.behaviors.autocomplete = function (context) {
var acdb = [];
$('input.autocomplete:not(.autocomplete-processed)', context).each(function () {
var uri = this.value;
if (!acdb[uri]) {
acdb[uri] = new Drupal.ACDB(uri);
}
var input = $('#' + this.id.substr(0, this.id.length - 13))
.attr('autocomplete', 'OFF')[0];
$(input.form).submit(Drupal.autocompleteSubmit);
new Drupal.jsAC(input, acdb[uri]);
$(this).addClass('autocomplete-processed');
});
};
/**
* Prevents the form from submitting if the suggestions popup is open
* and closes the suggestions popup when doing so.
*/
Drupal.autocompleteSubmit = function () {
return $('#autocomplete').each(function () {
this.owner.hidePopup();
}).size() == 0;
};
/**
* An AutoComplete object
*/
Drupal.jsAC = function (input, db) {
var ac = this;
this.input = input;
this.db = db;
$(this.input)
.keydown(function (event) { return ac.onkeydown(this, event); })
.keyup(function (event) { ac.onkeyup(this, event); })
.blur(function () { ac.hidePopup(); ac.db.cancel(); });
};
/**
* Handler for the "keydown" event
*/
Drupal.jsAC.prototype.onkeydown = function (input, e) {
if (!e) {
e = window.event;
}
switch (e.keyCode) {
case 40: // down arrow
this.selectDown();
return false;
case 38: // up arrow
this.selectUp();
return false;
default: // all other keys
return true;
}
};
/**
* Handler for the "keyup" event
*/
Drupal.jsAC.prototype.onkeyup = function (input, e) {
if (!e) {
e = window.event;
}
switch (e.keyCode) {
case 16: // shift
case 17: // ctrl
case 18: // alt
case 20: // caps lock
case 33: // page up
case 34: // page down
case 35: // end
case 36: // home
case 37: // left arrow
case 38: // up arrow
case 39: // right arrow
case 40: // down arrow
return true;
case 9: // tab
case 13: // enter
case 27: // esc
this.hidePopup(e.keyCode);
return true;
default: // all other keys
if (input.value.length > 0)
this.populatePopup();
else
this.hidePopup(e.keyCode);
return true;
}
};
/**
* Puts the currently highlighted suggestion into the autocomplete field
*/
Drupal.jsAC.prototype.select = function (node) {
this.input.value = node.autocompleteValue;
};
/**
* Highlights the next suggestion
*/
Drupal.jsAC.prototype.selectDown = function () {
if (this.selected && this.selected.nextSibling) {
this.highlight(this.selected.nextSibling);
}
else {
var lis = $('li', this.popup);
if (lis.size() > 0) {
this.highlight(lis.get(0));
}
}
};
/**
* Highlights the previous suggestion
*/
Drupal.jsAC.prototype.selectUp = function () {
if (this.selected && this.selected.previousSibling) {
this.highlight(this.selected.previousSibling);
}
};
/**
* Highlights a suggestion
*/
Drupal.jsAC.prototype.highlight = function (node) {
if (this.selected) {
$(this.selected).removeClass('selected');
}
$(node).addClass('selected');
this.selected = node;
};
/**
* Unhighlights a suggestion
*/
Drupal.jsAC.prototype.unhighlight = function (node) {
$(node).removeClass('selected');
this.selected = false;
};
/**
* Hides the autocomplete suggestions
*/
Drupal.jsAC.prototype.hidePopup = function (keycode) {
// Select item if the right key or mousebutton was pressed
if (this.selected && ((keycode && keycode != 46 && keycode != 8 && keycode != 27) || !keycode)) {
this.input.value = this.selected.autocompleteValue;
}
// Hide popup
var popup = this.popup;
if (popup) {
this.popup = null;
$(popup).fadeOut('fast', function() { $(popup).remove(); });
}
this.selected = false;
};
/**
* Positions the suggestions popup and starts a search
*/
Drupal.jsAC.prototype.populatePopup = function () {
// Show popup
if (this.popup) {
$(this.popup).remove();
}
this.selected = false;
this.popup = document.createElement('div');
this.popup.id = 'autocomplete';
this.popup.owner = this;
$(this.popup).css({
marginTop: this.input.offsetHeight +'px',
width: (this.input.offsetWidth - 4) +'px',
display: 'none'
});
$(this.input).before(this.popup);
// Do search
this.db.owner = this;
this.db.search(this.input.value);
};
/**
* Fills the suggestion popup with any matches received
*/
Drupal.jsAC.prototype.found = function (matches) {
// If no value in the textfield, do not show the popup.
if (!this.input.value.length) {
return false;
}
// Prepare matches
var ul = document.createElement('ul');
var ac = this;
for (key in matches) {
var li = document.createElement('li');
$(li)
.html('<div>'+ matches[key] +'</div>')
.mousedown(function () { ac.select(this); })
.mouseover(function () { ac.highlight(this); })
.mouseout(function () { ac.unhighlight(this); });
li.autocompleteValue = key;
$(ul).append(li);
}
// Show popup with matches, if any
if (this.popup) {
if (ul.childNodes.length > 0) {
$(this.popup).empty().append(ul).show();
}
else {
$(this.popup).css({visibility: 'hidden'});
this.hidePopup();
}
}
};
Drupal.jsAC.prototype.setStatus = function (status) {
switch (status) {
case 'begin':
$(this.input).addClass('throbbing');
break;
case 'cancel':
case 'error':
case 'found':
$(this.input).removeClass('throbbing');
break;
}
};
/**
* An AutoComplete DataBase object
*/
Drupal.ACDB = function (uri) {
this.uri = uri;
this.delay = 300;
this.cache = {};
};
/**
* Performs a cached and delayed search
*/
Drupal.ACDB.prototype.search = function (searchString) {
var db = this;
this.searchString = searchString;
// See if this key has been searched for before
if (this.cache[searchString]) {
return this.owner.found(this.cache[searchString]);
}
// Initiate delayed search
if (this.timer) {
clearTimeout(this.timer);
}
this.timer = setTimeout(function() {
db.owner.setStatus('begin');
// Ajax GET request for autocompletion
$.ajax({
type: "GET",
url: db.uri +'/'+ Drupal.encodeURIComponent(searchString),
dataType: 'json',
success: function (matches) {
if (typeof matches['status'] == 'undefined' || matches['status'] != 0) {
db.cache[searchString] = matches;
// Verify if these are still the matches the user wants to see
if (db.searchString == searchString) {
db.owner.found(matches);
}
db.owner.setStatus('found');
}
},
error: function (xmlhttp) {
alert(Drupal.ahahError(xmlhttp, db.uri));
}
});
}, this.delay);
};
/**
* Cancels the current autocomplete request
*/
Drupal.ACDB.prototype.cancel = function() {
if (this.owner) this.owner.setStatus('cancel');
if (this.timer) clearTimeout(this.timer);
this.searchString = '';
};
;// $Id: collapse.js,v 1.17 2008/01/29 10:58:25 goba Exp $
/**
* Toggle the visibility of a fieldset using smooth animations
*/
Drupal.toggleFieldset = function(fieldset) {
if ($(fieldset).is('.collapsed')) {
// Action div containers are processed separately because of a IE bug
// that alters the default submit button behavior.
var content = $('> div:not(.action)', fieldset);
$(fieldset).removeClass('collapsed');
content.hide();
content.slideDown( {
duration: 'fast',
easing: 'linear',
complete: function() {
Drupal.collapseScrollIntoView(this.parentNode);
this.parentNode.animating = false;
$('div.action', fieldset).show();
},
step: function() {
// Scroll the fieldset into view
Drupal.collapseScrollIntoView(this.parentNode);
}
});
}
else {
$('div.action', fieldset).hide();
var content = $('> div:not(.action)', fieldset).slideUp('fast', function() {
$(this.parentNode).addClass('collapsed');
this.parentNode.animating = false;
});
}
};
/**
* Scroll a given fieldset into view as much as possible.
*/
Drupal.collapseScrollIntoView = function (node) {
var h = self.innerHeight || document.documentElement.clientHeight || $('body')[0].clientHeight || 0;
var offset = self.pageYOffset || document.documentElement.scrollTop || $('body')[0].scrollTop || 0;
var posY = $(node).offset().top;
var fudge = 55;
if (posY + node.offsetHeight + fudge > h + offset) {
if (node.offsetHeight > h) {
window.scrollTo(0, posY);
} else {
window.scrollTo(0, posY + node.offsetHeight - h + fudge);
}
}
};
Drupal.behaviors.collapse = function (context) {
$('fieldset.collapsible > legend:not(.collapse-processed)', context).each(function() {
var fieldset = $(this.parentNode);
// Expand if there are errors inside
if ($('input.error, textarea.error, select.error', fieldset).size() > 0) {
fieldset.removeClass('collapsed');
}
// Turn the legend into a clickable link and wrap the contents of the fieldset
// in a div for easier animation
var text = this.innerHTML;
$(this).empty().append($('<a href="#">'+ text +'</a>').click(function() {
var fieldset = $(this).parents('fieldset:first')[0];
// Don't animate multiple times
if (!fieldset.animating) {
fieldset.animating = true;
Drupal.toggleFieldset(fieldset);
}
return false;
}))
.after($('<div class="fieldset-wrapper"></div>')
.append(fieldset.children(':not(legend):not(.action)')))
.addClass('collapse-processed');
});
};
;// $Id: teaser.js,v 1.12.2.1 2009/05/20 11:50:54 goba Exp $
/**
* Auto-attach for teaser behavior.
*
* Note: depends on resizable textareas.
*/
Drupal.behaviors.teaser = function(context) {
// This breaks in Konqueror. Prevent it from running.
if (/KDE/.test(navigator.vendor)) {
return;
}
$('textarea.teaser:not(.teaser-processed)', context).each(function() {
var teaser = $(this).addClass('teaser-processed');
// Move teaser textarea before body, and remove its form-item wrapper.
var body = $('#'+ Drupal.settings.teaser[this.id]);
var checkbox = $('#'+ Drupal.settings.teaserCheckbox[this.id]).parent();
var checked = $(checkbox).children('input').attr('checked') ? true : false;
var parent = teaser[0].parentNode;
$(body).before(teaser);
$(parent).remove();
function trim(text) {
return text.replace(/^\s+/g, '').replace(/\s+$/g, '');
}
// Join the teaser back to the body.
function join_teaser() {
if (teaser.val()) {
body.val(trim(teaser.val()) +'\r\n\r\n'+ trim(body.val()));
}
// Empty, hide and disable teaser.
teaser[0].value = '';
$(teaser).attr('disabled', 'disabled');
$(teaser).parent().slideUp('fast');
// Change label.
$(this).val(Drupal.t('Split summary at cursor'));
// Hide separate teaser checkbox.
$(checkbox).hide();
// Force a hidden checkbox to be checked (to ensure that the body is
// correctly processed on form submit when teaser/body are in joined
// state), and remember the current checked status.
checked = $(checkbox).children('input').attr('checked') ? true : false;
$(checkbox).children('input').attr('checked', true);
}
// Split the teaser from the body.
function split_teaser() {
body[0].focus();
var selection = Drupal.getSelection(body[0]);
var split = selection.start;
var text = body.val();
// Note: using val() fails sometimes. jQuery bug?
teaser[0].value = trim(text.slice(0, split));
body[0].value = trim(text.slice(split));
// Reveal and enable teaser
$(teaser).attr('disabled', '');
$(teaser).parent().slideDown('fast');
// Change label
$(this).val(Drupal.t('Join summary'));
// Show separate teaser checkbox, restore checked value.
$(checkbox).show().children('input').attr('checked', checked);
}
// Add split/join button.
var button = $('<div class="teaser-button-wrapper"><input type="button" class="teaser-button" /></div>');
var include = $('#'+ this.id.substring(0, this.id.length - 2) +'include');
$(include).parent().parent().before(button);
// Extract the teaser from the body, if set. Otherwise, stay in joined mode.
var text = body.val().split('<!--break-->');
if (text.length >= 2) {
teaser[0].value = trim(text.shift());
body[0].value = trim(text.join('<!--break-->'));
$(teaser).attr('disabled', '');
$('input', button).val(Drupal.t('Join summary')).toggle(join_teaser, split_teaser);
}
else {
$('input', button).val(Drupal.t('Split summary at cursor')).toggle(split_teaser, join_teaser);
$(checkbox).hide().children('input').attr('checked', true);
}
// Make sure that textarea.js has done its magic to ensure proper visibility state.
if (Drupal.behaviors.textarea && teaser.is(('.form-textarea:not(.textarea-processed)'))) {
Drupal.behaviors.textarea(teaser.parentNode);
}
// Set initial visibility
if ($(teaser).is('[@disabled]')) {
$(teaser).parent().hide();
}
});
};
;// $Id: textarea.js,v 1.22 2008/01/17 19:31:56 goba Exp $
Drupal.behaviors.textarea = function(context) {
$('textarea.resizable:not(.textarea-processed)', context).each(function() {
// Avoid non-processed teasers.
if ($(this).is(('textarea.teaser:not(.teaser-processed)'))) {
return false;
}
var textarea = $(this).addClass('textarea-processed'), staticOffset = null;
// When wrapping the text area, work around an IE margin bug. See:
// http://jaspan.com/ie-inherited-margin-bug-form-elements-and-haslayout
$(this).wrap('<div class="resizable-textarea"><span></span></div>')
.parent().append($('<div class="grippie"></div>').mousedown(startDrag));
var grippie = $('div.grippie', $(this).parent())[0];
grippie.style.marginRight = (grippie.offsetWidth - $(this)[0].offsetWidth) +'px';
function startDrag(e) {
staticOffset = textarea.height() - e.pageY;
textarea.css('opacity', 0.25);
$(document).mousemove(performDrag).mouseup(endDrag);
return false;
}
function performDrag(e) {
textarea.height(Math.max(32, staticOffset + e.pageY) + 'px');
return false;
}
function endDrag(e) {
$(document).unbind("mousemove", performDrag).unbind("mouseup", endDrag);
textarea.css('opacity', 1);
}
});
};
;