(function ($) {
/**
* 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 = {
attach: function (context, settings) {
for (var base in settings.tableDrag) {
$('#' + base, context).once('tabledrag', 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, settings.tableDrag[base]);
});
}
}
};
/**
* 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 (var group in tableSettings) {
for (var 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');
var testRow = $('
').addClass('draggable').appendTo(table);
var testCell = $(' | ').appendTo(testRow).prepend(indent).prepend(indent);
this.indentAmount = $('.indentation', testCell).get(1).offsetLeft - $('.indentation', testCell).get(0).offsetLeft;
testRow.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); });
// Add a link before the table for users to show or hide weight columns.
$(table).before($('')
.attr('title', Drupal.t('Re-order rows by numerical weight instead of dragging.'))
.click(function () {
if ($.cookie('Drupal.tableDrag.showWeight') == 1) {
self.hideColumns();
}
else {
self.showColumns();
}
return false;
})
.wrap('')
.parent()
);
// Initialize the specified columns (for example, weight or parent columns)
// to show or hide according to user preference. This aids accessibility
// so that, e.g., screen reader users can choose to enter weight values and
// manipulate form elements directly, rather than using drag-and-drop..
self.initColumns();
// 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 pointermove', function (event) { return self.dragRow(event, self); });
$(document).bind('mouseup pointerup', function (event) { return self.dropRow(event, self); });
$(document).bind('touchmove', function (event) { return self.dragRow(event.originalEvent.touches[0], self); });
$(document).bind('touchend', function (event) { return self.dropRow(event.originalEvent.touches[0], self); });
};
/**
* Initialize columns containing form elements to be hidden by default,
* according to the settings for this tableDrag instance.
*
* Identify and mark each cell with a CSS class so we can easily toggle
* show/hide it. Finally, hide columns if user does not have a
* 'Drupal.tableDrag.showWeight' cookie.
*/
Drupal.tableDrag.prototype.initColumns = 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.length && this.tableSettings[group][d].hidden) {
var hidden = this.tableSettings[group][d].hidden;
var cell = field.closest('td');
break;
}
}
// Mark the column containing this field so it can be hidden.
if (hidden && cell[0]) {
// 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;
$('> thead > tr, > tbody > tr, > tr', this.table).each(function () {
// Get the columnIndex and adjust for any colspans in this row.
var index = columnIndex;
var cells = $(this).children();
cells.each(function (n) {
if (n < index && this.colSpan && this.colSpan > 1) {
index -= this.colSpan - 1;
}
});
if (index > 0) {
cell = cells.filter(':nth-child(' + index + ')');
if (cell[0].colSpan && cell[0].colSpan > 1) {
// If this cell has a colspan, mark it so we can reduce the colspan.
cell.addClass('tabledrag-has-colspan');
}
else {
// Mark this cell so we can hide it.
cell.addClass('tabledrag-hide');
}
}
});
}
}
// Now hide cells and reduce colspans unless cookie indicates previous choice.
// Set a cookie if it is not already present.
if ($.cookie('Drupal.tableDrag.showWeight') === null) {
$.cookie('Drupal.tableDrag.showWeight', 0, {
// Workaround lack of support for the SameSite attribute in jQuery Cookie.
path: Drupal.settings.basePath + '; SameSite=Lax',
// The cookie expires in one year.
expires: 365
});
this.hideColumns();
}
// Check cookie value and show/hide weight columns accordingly.
else {
if ($.cookie('Drupal.tableDrag.showWeight') == 1) {
this.showColumns();
}
else {
this.hideColumns();
}
}
};
/**
* Hide the columns containing weight/parent form elements.
* Undo showColumns().
*/
Drupal.tableDrag.prototype.hideColumns = function () {
// Hide weight/parent cells and headers.
$('.tabledrag-hide', 'table.tabledrag-processed').css('display', 'none');
// Show TableDrag handles.
$('.tabledrag-handle', 'table.tabledrag-processed').css('display', '');
// Reduce the colspan of any effected multi-span columns.
$('.tabledrag-has-colspan', 'table.tabledrag-processed').each(function () {
this.colSpan = this.colSpan - 1;
});
// Change link text.
$('.tabledrag-toggle-weight').text(Drupal.t('Show row weights'));
// Change cookie (including workaround for SameSite attribute).
$.cookie('Drupal.tableDrag.showWeight', 0, {
path: Drupal.settings.basePath + '; SameSite=Lax',
// The cookie expires in one year.
expires: 365
});
// Trigger an event to allow other scripts to react to this display change.
$('table.tabledrag-processed').trigger('columnschange', 'hide');
};
/**
* Show the columns containing weight/parent form elements
* Undo hideColumns().
*/
Drupal.tableDrag.prototype.showColumns = function () {
// Show weight/parent cells and headers.
$('.tabledrag-hide', 'table.tabledrag-processed').css('display', '');
// Hide TableDrag handles.
$('.tabledrag-handle', 'table.tabledrag-processed').css('display', 'none');
// Increase the colspan for any columns where it was previously reduced.
$('.tabledrag-has-colspan', 'table.tabledrag-processed').each(function () {
this.colSpan = this.colSpan + 1;
});
// Change link text.
$('.tabledrag-toggle-weight').text(Drupal.t('Hide row weights'));
// Change cookie (including workaround for SameSite attribute).
$.cookie('Drupal.tableDrag.showWeight', 1, {
path: Drupal.settings.basePath + '; SameSite=Lax',
// The cookie expires in one year.
expires: 365
});
// Trigger an event to allow other scripts to react to this display change.
$('table.tabledrag-processed').trigger('columnschange', 'show');
};
/**
* Find the target used within a particular row and group.
*/
Drupal.tableDrag.prototype.rowSettings = function (group, row) {
var field = $('.' + group, row);
for (var 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 = {};
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 = $('
').attr('title', Drupal.t('Drag to re-order'));
// Insert the handle after indentations (if any).
if ($('td:first .indentation:last', item).length) {
$('td:first .indentation:last', item).after(handle);
// Update the total width of indentation in this entire table.
self.indentCount = Math.max($('.indentation', item).length, 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.bind('mousedown touchstart pointerdown', function (event) {
if (event.originalEvent.type == "touchstart") {
event = event.originalEvent.touches[0];
}
// Create a new dragObject recording the event information.
self.dragObject = {};
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.table).offset().top;
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).length) {
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, 10));
}
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;
var nextGroup = new self.row(nextRow, 'keyboard', self.indentEnabled, self.maxDepth, false);
if (nextGroup) {
$(nextGroup.group).each(function () {
groupHeight += $(this).is(':hidden') ? 0 : this.offsetHeight;
});
var 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, 10));
}
}
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, 10));
}
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 suppress 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);
// 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 (var n in self.rowObject.children) {
self.updateField(self.rowObject.children[n], group);
}
}
}
self.rowObject.markChanged();
if (self.changed == false) {
$(Drupal.theme('tableDragChangedWarning')).insertBefore(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 mouse coordinates from the event (allowing for browser differences).
*/
Drupal.tableDrag.prototype.mouseCoords = function (event) {
// Match both null and undefined, but not zero, by using != null.
// See https://stackoverflow.com/questions/2647867/how-to-determine-if-variable-is-undefined-or-null
if (event.pageX != null && event.pageY != null) {
return {x: event.pageX, y: event.pageY};
}
// Complete support for pointer events was only introduced to jQuery in
// version 1.11.1; between versions 1.7 and 1.11.0 pointer events have the
// pageX and pageY properties undefined. In those cases, the properties must
// be retrieved from the event.originalEvent object instead.
if (event.originalEvent && event.originalEvent.pageX != null && event.originalEvent.pageY != null) {
return {x: event.originalEvent.pageX, y: event.originalEvent.pageY};
}
// Some old browsers do not support MouseEvent.pageX and *.pageY at all.
// See https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageY
// For those, we look at event.clientX and event.clientY instead.
if (event.clientX == null || event.clientY == null) {
// In some jQuery versions, some events created by jQuery do not have
// clientX and clientY. But the original event might have.
if (!event.originalEvent) {
throw new Error("The event has no coordinates, and no event.originalEvent.");
}
event = event.originalEvent;
if (event.clientX == null || event.clientY == null) {
throw new Error("The original event has no coordinates.");
}
}
// Copied from jQuery.event.fix() in jQuery 1.4.1.
// In newer jQuery versions, this code is in jQuery.event.mouseHooks.filter().
var doc = document.documentElement, body = document.body;
var pageX = event.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
var pageY = event.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
return {x: pageX, y: pageY};
};
/**
* 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 = $(target).offset();
var mousePos = this.mouseCoords(event);
return { x: mousePos.x - docPos.left, y: mousePos.y - docPos.top };
};
/**
* 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).not(':hidden');
for (var n = 0; n < rows.length; n++) {
var row = rows[n];
var indentDiff = 0;
var rowY = $(row).offset().top;
// Because Safari does not 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 (row.offsetHeight == 0) {
var rowHeight = parseInt(row.firstChild.offsetHeight, 10) / 2;
}
// Other browsers.
else {
var rowHeight = parseInt(row.offsetHeight, 10) / 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 (var n in this.rowObject.group) {
if (this.rowObject.group[n] == row) {
return null;
}
}
}
else {
// Do not allow a row to be swapped with itself.
if (row == this.rowObject.element) {
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 separately.
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 its 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).length == $('.indentations', changedRow)) {
sourceRow = previousRow;
}
}
else {
sourceRow = previousRow;
}
}
else if ($(nextRow).is('.draggable') && $('.' + group, nextRow).length) {
if (this.indentEnabled) {
if ($('.indentations', nextRow).length == $('.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 guaranteed to
// be at the root level. Find the first item, then compare this row
// against it as a sibling.
sourceRow = $(this.table).find('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).closest('tr')).length;
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 = [];
$('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(), 10) || 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:visible, > tr.draggable:visible', this.table)
.removeClass('odd even')
.filter(':odd').addClass('even').end()
.filter(':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 = [tableRow];
this.groupDepth = $('.indentation', tableRow).length;
this.changed = false;
this.table = $(tableRow).closest('table').get(0);
this.indentEnabled = indentEnabled;
this.maxDepth = maxDepth;
this.direction = ''; // Direction the row is being moved.
if (this.indentEnabled) {
this.indents = $('.indentation', tableRow).length;
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]).length, 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 = [];
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) {
Drupal.detachBehaviors(this.group, Drupal.settings, 'move');
$(row)[position](this.group);
Drupal.attachBehaviors(this.group, Drupal.settings);
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).length : 0;
// Maximum indentation:
if (!prevRow || $(prevRow).is(':not(.draggable)') || $(this.element).is('.tabledrag-root')) {
// Do not indent:
// - the first row in the table,
// - rows dragged below a non-draggable row,
// - 'root' rows.
maxIndent = 0;
}
else {
// Do not go deeper than as a child of the previous row.
maxIndent = $('.indentation', prevRow).length + ($(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) {
var prevRow = $(this.element).prev('tr').get(0);
var 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 = [];
var directions = ['prev', 'next'];
var rowIndentation = this.indents;
for (var d = 0; d < directions.length; d++) {
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 indentation.
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 (var 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 '*';
};
Drupal.theme.prototype.tableDragIndentation = function () {
return '
';
};
Drupal.theme.prototype.tableDragChangedWarning = function () {
return '' + Drupal.theme('tableDragChangedMarker') + ' ' + Drupal.t('Changes made in this table will not be saved until the form is submitted.') + '
';
};
})(jQuery);
;
/* $Id: lightbox.js,v 1.5.2.6.2.136 2010/09/24 08:39:40 snpower Exp $ */
/**
* jQuery Lightbox
* @author
* Stella Power,
*
* Based on Lightbox v2.03.3 by Lokesh Dhakar
*
* Also partially based on the jQuery Lightbox by Warren Krewenki
*
*
* 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;
(function($) {
Lightbox = {
auto_modal : false,
overlayOpacity : 0.8, // Controls transparency of shadow overlay.
overlayColor : '000', // Controls colour of shadow overlay.
disableCloseClick : true,
// 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.
minWidth: 240,
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,
keysClose : ['c', 'x', 27],
keysPrevious : ['p', 37],
keysNext : ['n', 39],
keysZoom : ['z'],
keysPlayPause : [32],
// Slideshow options.
slideInterval : 5000, // In milliseconds.
showPlayPause : true,
autoStart : 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,
flvPlayer : '/flvplayer.swf',
flvFlashvars : '',
isModal : false,
isVideo : false,
videoId : false,
modalWidth : 400,
modalHeight : 400,
modalHTML : null,
// initialize()
// Constructor runs on completion of the DOM loading.
// 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.disableCloseClick = s.disable_close_click;
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.keysClose = s.keys_close.split(" ");
Lightbox.keysPrevious = s.keys_previous.split(" ");
Lightbox.keysNext = s.keys_next.split(" ");
Lightbox.keysZoom = s.keys_zoom.split(" ");
Lightbox.keysPlayPause = s.keys_play_pause.split(" ");
Lightbox.disableResize = s.disable_resize;
Lightbox.disableZoom = s.disable_zoom;
Lightbox.slideInterval = s.slideshow_interval;
Lightbox.showPlayPause = s.show_play_pause;
Lightbox.showCaption = s.show_caption;
Lightbox.autoStart = s.slideshow_automatic_start;
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;
if (s.enable_video) {
Lightbox.flvPlayer = s.flvPlayer;
Lightbox.flvFlashvars = s.flvFlashvars;
}
// Make the lightbox divs.
var layout_class = (s.use_alt_layout ? 'lightbox2-alt-layout' : 'lightbox2-orig-layout');
var output = '\
';
var loading = '';
var modal = '';
var frame = '';
var imageContainer = '';
var details = '';
var bottomNav = '';
var image = '';
var hoverNav = '';
var frameNav = '';
var hoverNav = '';
var frameNav = '';
var caption = '';
var numberDisplay = '';
var close = '';
var zoom = '';
var zoomOut = '';
var pause = '';
var play = '';
$("body").append(output);
$('#outerImageContainer').append(modal + frame + imageContainer + loading);
if (!s.use_alt_layout) {
$('#imageContainer').append(image + hoverNav);
$('#imageData').append(details + bottomNav);
$('#imageDetails').append(caption + numberDisplay);
$('#bottomNav').append(frameNav + close + zoom + zoomOut + pause + play);
}
else {
$('#outerImageContainer').append(bottomNav);
$('#imageContainer').append(image);
$('#bottomNav').append(close + zoom + zoomOut);
$('#imageData').append(hoverNav + details);
$('#imageDetails').append(caption + numberDisplay + pause + play);
}
// Setup onclick handlers.
if (Lightbox.disableCloseClick) {
$('#lightbox2-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.alternative_layout) {
$('#bottomNavZoom, #bottomNavZoomOut').css({'bottom': Lightbox.borderSize + 'px', 'right': Lightbox.borderSize + 'px'});
}
else if (Lightbox.rtl == 1 && Drupal.settings.lightbox2.useragent.search('MSIE') !== -1) {
$('#bottomNavZoom, #bottomNavZoomOut').css({'left': '0px'});
}
// 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(context) {
if (context == undefined || context == null) {
context = document;
}
// Attach lightbox to any links with rel 'lightbox', 'lightshow' or
// 'lightframe', etc.
$("a[rel^='lightbox']:not(.lightbox-processed), area[rel^='lightbox']:not(.lightbox-processed)", context).addClass('lightbox-processed').click(function(e) {
if (Lightbox.disableCloseClick) {
$('#lightbox').unbind('click');
$('#lightbox').click(function() { Lightbox.end('forceClose'); } );
}
Lightbox.start(this, false, false, false, false);
if (e.preventDefault) { e.preventDefault(); }
return false;
});
$("a[rel^='lightshow']:not(.lightbox-processed), area[rel^='lightshow']:not(.lightbox-processed)", context).addClass('lightbox-processed').click(function(e) {
if (Lightbox.disableCloseClick) {
$('#lightbox').unbind('click');
$('#lightbox').click(function() { Lightbox.end('forceClose'); } );
}
Lightbox.start(this, true, false, false, false);
if (e.preventDefault) { e.preventDefault(); }
return false;
});
$("a[rel^='lightframe']:not(.lightbox-processed), area[rel^='lightframe']:not(.lightbox-processed)", context).addClass('lightbox-processed').click(function(e) {
if (Lightbox.disableCloseClick) {
$('#lightbox').unbind('click');
$('#lightbox').click(function() { Lightbox.end('forceClose'); } );
}
Lightbox.start(this, false, true, false, false);
if (e.preventDefault) { e.preventDefault(); }
return false;
});
if (Lightbox.enableVideo) {
$("a[rel^='lightvideo']:not(.lightbox-processed), area[rel^='lightvideo']:not(.lightbox-processed)", context).addClass('lightbox-processed').click(function(e) {
if (Lightbox.disableCloseClick) {
$('#lightbox').unbind('click');
$('#lightbox').click(function() { Lightbox.end('forceClose'); } );
}
Lightbox.start(this, false, false, true, false);
if (e.preventDefault) { e.preventDefault(); }
return false;
});
}
$("a[rel^='lightmodal']:not(.lightbox-processed), area[rel^='lightmodal']:not(.lightbox-processed)", context).addClass('lightbox-processed').click(function(e) {
$('#lightbox').unbind('click');
// Add classes from the link to the lightbox div - don't include lightbox-processed
$('#lightbox').addClass($(this).attr('class'));
$('#lightbox').removeClass('lightbox-processed');
Lightbox.start(this, false, false, false, true);
if (e.preventDefault) { e.preventDefault(); }
return false;
});
$("#lightboxAutoModal:not(.lightbox-processed)", context).addClass('lightbox-processed').click(function(e) {
Lightbox.auto_modal = true;
$('#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 = !Lightbox.autoStart;
// Replaces hideSelectBoxes() and hideFlash() calls in original lightbox2.
Lightbox.toggleSelectsFlash('hide');
// Stretch overlay to fill page and fade in.
var arrayPageSize = Lightbox.getPageSize();
$("#lightbox2-overlay").hide().css({
'width': '100%',
'zIndex': '10090',
'height': arrayPageSize[1] + 'px',
'backgroundColor' : '#' + Lightbox.overlayColor
});
// Detect OS X FF2 opacity + flash issue.
if (lightvideo && this.detectMacFF2()) {
$("#lightbox2-overlay").removeClass("overlay_default");
$("#lightbox2-overlay").addClass("overlay_macff2");
$("#lightbox2-overlay").css({'opacity' : null});
}
else {
$("#lightbox2-overlay").removeClass("overlay_macff2");
$("#lightbox2-overlay").addClass("overlay_default");
$("#lightbox2-overlay").css({'opacity' : Lightbox.overlayOpacity});
}
$("#lightbox2-overlay").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;
if (rel_parts["flashvars"]) {
Lightbox.flvFlashvars = Lightbox.flvFlashvars + '&' + rel_parts["flashvars"];
}
// Set the title for image alternative text.
var alt = imageLink.title;
if (!alt) {
var img = $(imageLink).find("img");
if (img && $(img).attr("alt")) {
alt = $(img).attr("alt");
}
else {
alt = title;
}
}
if ($(imageLink).attr('id') == 'lightboxAutoModal') {
rel_style = rel_parts["style"];
Lightbox.imageArray.push(['#lightboxAutoModal > *', title, alt, rel_style, 1]);
}
else {
// Handle lightbox images with no grouping.
if ((rel == 'lightbox' || rel == 'lightshow') && !rel_group) {
Lightbox.imageArray.push([imageLink.href, title, alt]);
}
// Handle other items with no grouping.
else if (!rel_group) {
rel_style = rel_parts["style"];
Lightbox.imageArray.push([imageLink.href, title, alt, rel_style]);
}
// Handle grouped items.
else {
// Loop through anchors and add them to imageArray.
for (i = 0; i < anchors.length; i++) {
anchor = anchors[i];
if (anchor.href && typeof(anchor.href) == "string" && $(anchor).attr('rel')) {
var rel_data = Lightbox.parseRel(anchor);
var anchor_title = (rel_data["title"] ? rel_data["title"] : anchor.title);
img_alt = anchor.title;
if (!img_alt) {
var anchor_img = $(anchor).find("img");
if (anchor_img && $(anchor_img).attr("alt")) {
img_alt = $(anchor_img).attr("alt");
}
else {
img_alt = title;
}
}
if (rel_data["rel"] == rel) {
if (rel_data["group"] == rel_group) {
if (Lightbox.isLightframe || Lightbox.isModal || Lightbox.isVideo) {
rel_style = rel_data["style"];
}
Lightbox.imageArray.push([anchor.href, anchor_title, img_alt, 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];
$('#frameContainer, #modalContainer, #lightboxImage').hide();
$('#hoverNav, #prevLink, #nextLink, #frameHoverNav, #framePrevLink, #frameNextLink').hide();
$('#imageDataContainer, #numberDisplay, #bottomNavZoom, #bottomNavZoomOut').hide();
$('#outerImageContainer').css({'width': '250px', 'height': '250px'});
$('#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').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) {
$("#lightbox #imageDataContainer").removeClass('lightbox2-alt-layout-data');
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][2];
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][2];
}
// Set up frame size, etc.
else if (Lightbox.isLightframe) {
$("#lightbox #imageDataContainer").addClass('lightbox2-alt-layout-data');
var src = Lightbox.imageArray[Lightbox.activeImage][0];
$('#frameContainer').html('');
// Enable swf support in Gecko browsers.
if (Drupal.settings.lightbox2.useragent.search('Mozilla') !== -1 && src.indexOf('.swf') != -1) {
setTimeout(function () {
document.getElementById("lightboxFrame").src = Lightbox.imageArray[Lightbox.activeImage][0];
}, 1000);
}
if (!Lightbox.iframe_border) {
$('#lightboxFrame').css({'border': 'none'});
$('#lightboxFrame').attr('frameborder', '0');
}
var iframe = document.getElementById('lightboxFrame');
var iframeStyles = Lightbox.imageArray[Lightbox.activeImage][3];
iframe = Lightbox.setStyles(iframe, iframeStyles);
Lightbox.resizeContainer(parseInt(iframe.width, 10), parseInt(iframe.height, 10));
}
else if (Lightbox.isVideo || Lightbox.isModal) {
$("#lightbox #imageDataContainer").addClass('lightbox2-alt-layout-data');
var container = document.getElementById('modalContainer');
var modalStyles = Lightbox.imageArray[Lightbox.activeImage][3];
container = Lightbox.setStyles(container, modalStyles);
if (Lightbox.isVideo) {
Lightbox.modalHeight = parseInt(container.height, 10) - 10;
Lightbox.modalWidth = parseInt(container.width, 10) - 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) {
imgWidth = (imgWidth < Lightbox.minWidth ? Lightbox.minWidth : imgWidth);
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;
$('#modalContainer').css({'width': imgWidth, 'height': imgHeight});
// 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 (Drupal.settings.lightbox2.useragent.search('MSIE') !== -1) {
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 (Drupal.settings.lightbox2.useragent.search('Safari') !== -1 || Lightbox.fadeInSpeed === 0) {
$('#lightboxFrame').css({'zIndex': '10500'}).show();
}
else {
$('#lightboxFrame').css({'zIndex': '10500'}).fadeIn(Lightbox.fadeInSpeed);
}
}
else {
if (Lightbox.isVideo) {
$("#modalContainer").html(Lightbox.modalHTML).click(function(){return false;}).css('zIndex', '10500').show();
}
else {
var src = unescape(Lightbox.imageArray[Lightbox.activeImage][0]);
if (Lightbox.imageArray[Lightbox.activeImage][4]) {
$(src).appendTo("#modalContainer");
$('#modalContainer').css({'zIndex': '10500'}).show();
}
else {
// Use a callback to show the new image, otherwise you get flicker.
$("#modalContainer").hide().load(src, function () {$('#modalContainer').css({'zIndex': '10500'}).show();});
}
$('#modalContainer').unbind('click');
}
// This might be needed in the Lightframe section above.
//$('#modalContainer').css({'zIndex': '10500'}).show();
}
}
// Handle display of image content.
else {
$('#imageContainer').show();
if (Drupal.settings.lightbox2.useragent.search('Safari') !== -1 || Lightbox.fadeInSpeed === 0) {
$('#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.total > 1) {
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;
}
$('#lightbox2-overlay').css({'height': pageHeight + 'px', 'width': arrayPageSize[0] + 'px'});
// Gecko browsers (e.g. Firefox, SeaMonkey, etc) don't handle pdfs as
// expected.
if (Drupal.settings.lightbox2.useragent.search('Mozilla') !== -1) {
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 s = Drupal.settings.lightbox2;
if (s.show_caption) {
var caption = Lightbox.filterXSS(Lightbox.imageArray[Lightbox.activeImage][1]);
if (!caption) caption = '';
$('#caption').html(caption).css({'zIndex': '10500'}).show();
}
// If image is part of set display 'Image x of x'.
var numberDisplay = null;
if (s.image_count && Lightbox.total > 1) {
var currentImage = Lightbox.activeImage + 1;
if (!Lightbox.isLightframe && !Lightbox.isModal && !Lightbox.isVideo) {
numberDisplay = s.image_count.replace(/\!current/, currentImage).replace(/\!total/, Lightbox.total);
}
else if (Lightbox.isVideo) {
numberDisplay = s.video_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();
}
else {
$('#numberDisplay').hide();
}
$("#imageDataContainer").hide().slideDown(Lightbox.slideDownSpeed, function() {
$("#bottomNav").show();
});
if (Lightbox.rtl == 1) {
$("#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.isModal || Lightbox.isVideo) && !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) {
// Unbind any other click handlers, otherwise this adds a new click handler
// each time the arrow is clicked.
$(prevLink).css({'zIndex': '10500'}).show().unbind().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)) {
// Unbind any other click handlers, otherwise this adds a new click handler
// each time the arrow is clicked.
$(nextLink).css({'zIndex': '10500'}).show().unbind().click(function() {
Lightbox.changeData(Lightbox.activeImage + 1); return false;
});
}
// Safari browsers need to have hide() called again.
else {
$(nextLink).hide();
}
}
// Don't enable keyboard shortcuts so forms will work.
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 (Lightbox.checkKey(Lightbox.keysClose, key, keycode)) {
Lightbox.end('forceClose');
}
// Display previous image (p, <-).
else if (Lightbox.checkKey(Lightbox.keysPrevious, key, keycode)) {
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 (Lightbox.checkKey(Lightbox.keysNext, key, keycode)) {
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 (Lightbox.checkKey(Lightbox.keysZoom, key, keycode) && !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 (Lightbox.checkKey(Lightbox.keysPlayPause, key, keycode) && 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();
$("#lightbox2-overlay").fadeOut();
Lightbox.isPaused = true;
Lightbox.inprogress = false;
Lightbox.imageArray = [];
Lightbox.imageNum = 0;
// 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) {
$('#frameContainer').empty().hide();
}
else if (Lightbox.isVideo || Lightbox.isModal) {
if (!Lightbox.auto_modal) {
$('#modalContainer').hide().html("");
}
Lightbox.auto_modal = false;
}
},
// getPageScroll()
// Returns array with x,y page scroll values.
// Core code from - quirksmode.com.
getPageScroll : function() {
var xScroll, yScroll;
if (self.pageYOffset || self.pageXOffset) {
yScroll = self.pageYOffset;
xScroll = self.pageXOffset;
}
else if (document.documentElement && (document.documentElement.scrollTop || document.documentElement.scrollLeft)) { // 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 (window.innerHeight && window.scrollMaxY) {
xScroll = window.innerWidth + window.scrollMaxX;
yScroll = window.innerHeight + window.scrollMaxY;
}
else if (document.body.scrollHeight > document.body.offsetHeight) { // All but Explorer Mac.
xScroll = document.body.scrollWidth;
yScroll = document.body.scrollHeight;
}
else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari.
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;
}
else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode.
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 than height of the viewport.
if (yScroll < windowHeight) {
pageHeight = windowHeight;
}
else {
pageHeight = yScroll;
}
// For small pages with total width less than width of the viewport.
if (xScroll < windowWidth) {
pageWidth = xScroll;
}
else {
pageWidth = windowWidth;
}
arrayPageSize = new Array(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").not('#lightboxAutoModal select, #lightboxAutoModal embed, #lightboxAutoModal object').addClass("lightbox_hidden");
$("select.lightbox_hidden, embed.lightbox_hidden, object.lightbox_hidden").hide();
}
},
// parseRel()
parseRel: function (link) {
var parts = [];
parts["rel"] = parts["title"] = parts["group"] = parts["style"] = parts["flashvars"] = null;
if (!$(link).attr('rel')) return parts;
parts["rel"] = $(link).attr('rel').match(/\w+/)[0];
if ($(link).attr('rel').match(/\[(.*)\]/)) {
var info = $(link).attr('rel').match(/\[(.*?)\]/)[1].split('|');
parts["group"] = info[0];
parts["style"] = info[1];
if (parts["style"] != undefined && parts["style"].match(/flashvars:\s?(.*?);/)) {
parts["flashvars"] = parts["style"].match(/flashvars:\s?(.*?);/)[1];
}
}
if ($(link).attr('rel').match(/\[.*\]\[([\s\S]*)\]/)) {
var title = $(link).attr('rel').match(/\[.*\]\[([\s\S]*)\]/)[1];
parts["title"] = title.replace(/\n/g, '
');
}
return parts;
},
// setStyles()
setStyles: function(item, styles) {
item.width = Lightbox.iframe_width;
item.height = Lightbox.iframe_height;
item.scrolling = "auto";
if (!styles) return item;
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 if (Lightbox.total > 1) {
Lightbox.changeData(Lightbox.activeImage + 1);
}
}
else {
Lightbox.isPaused = true;
}
},
triggerLightbox: function (rel_type, rel_group) {
if (rel_type.length) {
if (rel_group && rel_group.length) {
$("a[rel^='" + rel_type +"\[" + rel_group + "\]'], area[rel^='" + rel_type +"\[" + rel_group + "\]']").eq(0).trigger("click");
}
else {
$("a[rel^='" + rel_type +"'], area[rel^='" + rel_type +"']").eq(0).trigger("click");
}
}
},
detectMacFF2: function() {
var ua = navigator.userAgent.toLowerCase();
if (/firefox[\/\s](\d+\.\d+)/.test(ua)) {
var ffversion = new Number(RegExp.$1);
if (ffversion < 3 && ua.indexOf('mac') != -1) {
return true;
}
}
return false;
},
checkKey: function(keys, key, code) {
return (jQuery.inArray(key, keys) != -1 || jQuery.inArray(String(code), keys) != -1);
},
filterXSS: function(str, allowed_tags) {
var output = "";
var prefix = Drupal.settings.pathPrefix;
if (!prefix) prefix = '';
$.ajax({
url: Drupal.settings.basePath + prefix + '?q=system/lightbox2/filter-xss',
data: {
'string' : str,
'allowed_tags' : allowed_tags
},
type: "POST",
async: false,
dataType: "json",
success: function(data) {
output = data;
}
});
return output;
}
};
// Initialize the lightbox.
Drupal.behaviors.initLightbox = {
attach: function(context) {
$('body:not(.lightbox-processed)', context).addClass('lightbox-processed').each(function() {
Lightbox.initialize();
return false; // Break the each loop.
});
// Attach lightbox to any links with lightbox rels.
Lightbox.initList(context);
$('#lightboxAutoModal', context).triggerHandler('click');
}
};
})(jQuery);
;
(function ($) {
/**
* 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;
// The WAI-ARIA setting aria-live="polite" will announce changes after users
// have completed their current activity and not interrupt the screen reader.
this.element = $('').attr('id', id);
this.element.html('' +
'' +
'
');
};
/**
* 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.ajaxError(xmlhttp, pb.uri));
}
});
}
};
/**
* Display errors on the page.
*/
Drupal.progressBar.prototype.displayError = function (string) {
var error = $('').html(string);
$(this.element).before(error).hide();
if (this.errorCallback) {
this.errorCallback(this);
}
};
})(jQuery);
;
(function ($) {
/**
* Attaches sticky table headers.
*/
Drupal.behaviors.tableHeader = {
attach: function (context, settings) {
if (!$.support.positionFixed) {
return;
}
$('table.sticky-enabled', context).once('tableheader', function () {
$(this).data("drupal-tableheader", new Drupal.tableHeader(this));
});
}
};
/**
* Constructor for the tableHeader object. Provides sticky table headers.
*
* @param table
* DOM object for the table to add a sticky header to.
*/
Drupal.tableHeader = function (table) {
var self = this;
this.originalTable = $(table);
this.originalHeader = $(table).children('thead');
this.originalHeaderCells = this.originalHeader.find('> tr > th');
this.displayWeight = null;
// React to columns change to avoid making checks in the scroll callback.
this.originalTable.bind('columnschange', function (e, display) {
// This will force header size to be calculated on scroll.
self.widthCalculated = (self.displayWeight !== null && self.displayWeight === display);
self.displayWeight = display;
});
// Clone the table header so it inherits original jQuery properties. Hide
// the table to avoid a flash of the header clone upon page load.
this.stickyTable = $('')
.insertBefore(this.originalTable)
.css({ position: 'fixed', top: '0px' });
this.stickyHeader = this.originalHeader.clone(true)
.hide()
.appendTo(this.stickyTable);
this.stickyHeaderCells = this.stickyHeader.find('> tr > th');
this.originalTable.addClass('sticky-table');
$(window)
.bind('scroll.drupal-tableheader', $.proxy(this, 'eventhandlerRecalculateStickyHeader'))
.bind('resize.drupal-tableheader', { calculateWidth: true }, $.proxy(this, 'eventhandlerRecalculateStickyHeader'))
// Make sure the anchor being scrolled into view is not hidden beneath the
// sticky table header. Adjust the scrollTop if it does.
.bind('drupalDisplaceAnchor.drupal-tableheader', function () {
window.scrollBy(0, -self.stickyTable.outerHeight());
})
// Make sure the element being focused is not hidden beneath the sticky
// table header. Adjust the scrollTop if it does.
.bind('drupalDisplaceFocus.drupal-tableheader', function (event) {
if (self.stickyVisible && event.clientY < (self.stickyOffsetTop + self.stickyTable.outerHeight()) && event.$target.closest('sticky-header').length === 0) {
window.scrollBy(0, -self.stickyTable.outerHeight());
}
})
.triggerHandler('resize.drupal-tableheader');
// We hid the header to avoid it showing up erroneously on page load;
// we need to unhide it now so that it will show up when expected.
this.stickyHeader.show();
};
/**
* Call the header offset function to prevent use of eval().
*
* @param accessor
* The callback function name.
* @return
* The callback result.
*/
Drupal.tableHeader.callHeaderOffsetFunction = function(accessor) {
accessor = accessor.split('.');
var callback = window;
for (var i = 0, len = accessor.length - 1; i < len; i++) {
if (typeof callback[accessor[i]] !== 'function' && typeof callback[accessor[i]] != 'object') {
return 0;
}
callback = callback[accessor[i]];
}
if (typeof callback[accessor[accessor.length - 1]] === 'function') {
return callback[accessor[accessor.length - 1]]();
}
return 0;
};
/**
* Event handler: recalculates position of the sticky table header.
*
* @param event
* Event being triggered.
*/
Drupal.tableHeader.prototype.eventhandlerRecalculateStickyHeader = function (event) {
var self = this;
var calculateWidth = event.data && event.data.calculateWidth;
// Reset top position of sticky table headers to the current top offset.
this.stickyOffsetTop = Drupal.settings.tableHeaderOffset ? Drupal.tableHeader.callHeaderOffsetFunction(Drupal.settings.tableHeaderOffset) : 0;
this.stickyTable.css('top', this.stickyOffsetTop + 'px');
// Save positioning data.
var viewHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
if (calculateWidth || this.viewHeight !== viewHeight) {
this.viewHeight = viewHeight;
this.vPosition = this.originalTable.offset().top - 4 - this.stickyOffsetTop;
this.hPosition = this.originalTable.offset().left;
this.vLength = this.originalTable[0].clientHeight - 100;
calculateWidth = true;
}
// Track horizontal positioning relative to the viewport and set visibility.
var hScroll = document.documentElement.scrollLeft || document.body.scrollLeft;
var vOffset = (document.documentElement.scrollTop || document.body.scrollTop) - this.vPosition;
this.stickyVisible = vOffset > 0 && vOffset < this.vLength;
this.stickyTable.css({ left: (-hScroll + this.hPosition) + 'px', visibility: this.stickyVisible ? 'visible' : 'hidden' });
// Only perform expensive calculations if the sticky header is actually
// visible or when forced.
if (this.stickyVisible && (calculateWidth || !this.widthCalculated)) {
this.widthCalculated = true;
var $that = null;
var $stickyCell = null;
var display = null;
var cellWidth = null;
// Resize header and its cell widths.
// Only apply width to visible table cells. This prevents the header from
// displaying incorrectly when the sticky header is no longer visible.
for (var i = 0, il = this.originalHeaderCells.length; i < il; i += 1) {
$that = $(this.originalHeaderCells[i]);
$stickyCell = this.stickyHeaderCells.eq($that.index());
display = $that.css('display');
if (display !== 'none') {
cellWidth = $that.css('width');
// Exception for IE7.
if (cellWidth === 'auto') {
cellWidth = $that[0].clientWidth + 'px';
}
$stickyCell.css({'width': cellWidth, 'display': display});
}
else {
$stickyCell.css('display', 'none');
}
}
this.stickyTable.css('width', this.originalTable.outerWidth());
}
};
})(jQuery);
;
/**
* @file
* Javascript functions for the Entityqueue module.
*/
(function($) {
Drupal.behaviors.entityqueueWidget = {
attach: function(context, settings) {
for (var base in settings.tableDrag) {
$('#' + base, context).once('entityqueue-tabledrag', function () {
var tabledrag = Drupal.tableDrag[base],
changed = settings.entityqueue_changed;
if (changed && changed.hasOwnProperty(tabledrag.table.id)) {
tabledrag.changed = true;
var $warning = $(Drupal.theme('tableDragChangedWarning'));
$warning.insertBefore(tabledrag.table);
}
});
}
}
};
})(jQuery);
;
(function ($) {
/**
* Attaches the autocomplete behavior to all required fields.
*/
Drupal.behaviors.autocomplete = {
attach: function (context, settings) {
var acdb = [];
$('input.autocomplete', context).once('autocomplete', 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')
.attr('aria-autocomplete', 'list');
$($input[0].form).submit(Drupal.autocompleteSubmit);
$input.parent()
.attr('role', 'application')
.append($('')
.attr('id', $input.attr('id') + '-autocomplete-aria-live')
);
new Drupal.jsAC($input, acdb[uri]);
});
}
};
/**
* 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();
}).length == 0;
};
/**
* An AutoComplete object.
*/
Drupal.jsAC = function ($input, db) {
var ac = this;
this.input = $input[0];
this.ariaLive = $('#' + this.input.id + '-autocomplete-aria-live');
this.db = db;
$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 && !input.readOnly) {
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).data('autocompleteValue');
$(this.input).trigger('autocompleteSelect', [node]);
};
/**
* Highlights the next suggestion.
*/
Drupal.jsAC.prototype.selectDown = function () {
if (this.selected && this.selected.nextSibling) {
this.highlight(this.selected.nextSibling);
}
else if (this.popup) {
var lis = $('li', this.popup);
if (lis.length > 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;
$(this.ariaLive).html($(this.selected).html());
};
/**
* Unhighlights a suggestion.
*/
Drupal.jsAC.prototype.unhighlight = function (node) {
$(node).removeClass('selected');
this.selected = false;
$(this.ariaLive).empty();
};
/**
* 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.select(this.selected);
}
// Hide popup.
var popup = this.popup;
if (popup) {
this.popup = null;
$(popup).fadeOut('fast', function () { $(popup).remove(); });
}
this.selected = false;
$(this.ariaLive).empty();
};
/**
* Positions the suggestions popup and starts a search.
*/
Drupal.jsAC.prototype.populatePopup = function () {
var $input = $(this.input);
var position = $input.position();
// Show popup.
if (this.popup) {
$(this.popup).remove();
}
this.selected = false;
this.popup = $('')[0];
this.popup.owner = this;
$(this.popup).css({
top: parseInt(position.top + this.input.offsetHeight, 10) + 'px',
left: parseInt(position.left, 10) + 'px',
width: $input.innerWidth() + 'px',
display: 'none'
});
$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 = $('');
var ac = this;
for (key in matches) {
$('')
.html($('').html(matches[key]))
.mousedown(function () { ac.hidePopup(this); })
.mouseover(function () { ac.highlight(this); })
.mouseout(function () { ac.unhighlight(this); })
.data('autocompleteValue', key)
.appendTo(ul);
}
// Show popup with matches, if any.
if (this.popup) {
if (ul.children().length) {
$(this.popup).empty().append(ul).show();
$(this.ariaLive).html(Drupal.t('Autocomplete popup'));
}
else {
$(this.popup).css({ visibility: 'hidden' });
this.hidePopup();
}
}
};
Drupal.jsAC.prototype.setStatus = function (status) {
switch (status) {
case 'begin':
$(this.input).addClass('throbbing');
$(this.ariaLive).html(Drupal.t('Searching for matches...'));
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 string needs to be searched for anyway. The pattern ../ is
// stripped since it may be misinterpreted by the browser.
searchString = searchString.replace(/^\s+|\.{2,}\/|\s+$/g, '');
// Skip empty search strings, or search strings ending with a comma, since
// that is the separator between search terms.
if (searchString.length <= 0 ||
searchString.charAt(searchString.length - 1) == ',') {
return;
}
// 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. We use Drupal.encodePath instead of
// encodeURIComponent to allow autocomplete search terms to contain slashes.
$.ajax({
type: 'GET',
url: Drupal.sanitizeAjaxUrl(db.uri + '/' + Drupal.encodePath(searchString)),
dataType: 'json',
jsonp: false,
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) {
Drupal.displayAjaxError(Drupal.ajaxError(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 = '';
};
})(jQuery);
;
/**
* @file
* Attaches behaviors for the Chosen module.
*/
(function($) {
Drupal.behaviors.chosen = {
attach: function(context, settings) {
settings.chosen = settings.chosen || Drupal.settings.chosen;
// Prepare selector and add unwantend selectors.
var selector = settings.chosen.selector;
// Function to prepare all the options together for the chosen() call.
var getElementOptions = function (element) {
var options = $.extend({}, settings.chosen.options);
// The width default option is considered the minimum width, so this
// must be evaluated for every option.
if (settings.chosen.minimum_width > 0) {
if ($(element).width() < settings.chosen.minimum_width) {
options.width = settings.chosen.minimum_width + 'px';
}
else {
options.width = $(element).width() + 'px';
}
}
// Some field widgets have cardinality, so we must respect that.
// @see chosen_pre_render_select()
if ($(element).attr('multiple') && $(element).data('cardinality')) {
options.max_selected_options = $(element).data('cardinality');
}
return options;
};
// Process elements that have opted-in for Chosen.
// @todo Remove support for the deprecated chosen-widget class.
$('select.chosen-enable, select.chosen-widget', context).once('chosen', function() {
options = getElementOptions(this);
$(this).chosen(options);
});
$(selector, context)
// Disabled on:
// - Field UI
// - WYSIWYG elements
// - Tabledrag weights
// - Elements that have opted-out of Chosen
// - Elements already processed by Chosen.
.not('#field-ui-field-overview-form select, #field-ui-display-overview-form select, .wysiwyg, .draggable select[name$="[weight]"], .draggable select[name$="[position]"], .chosen-disable, .chosen-processed')
.filter(function() {
// Filter out select widgets that do not meet the minimum number of
// options.
var minOptions = $(this).attr('multiple') ? settings.chosen.minimum_multiple : settings.chosen.minimum_single;
if (!minOptions) {
// Zero value means no minimum.
return true;
}
else {
return $(this).find('option').length >= minOptions;
}
})
.once('chosen', function() {
options = getElementOptions(this);
$(this).chosen(options);
});
}
};
})(jQuery);
;