/*
This file contains the full javascript for the various jQuery plugins used by this template.
Each plugin is licensed according to the information contained in the individual copyright notice.
*/
/*!
* jQuery Cookie Plugin
* https://github.com/carhartl/jquery-cookie
*
* Copyright 2011, Klaus Hartl
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://www.opensource.org/licenses/mit-license.php
* http://www.opensource.org/licenses/GPL-2.0
*/
(function($) {
$.cookie = function(key, value, options) {
// key and at least value given, set cookie...
if (arguments.length > 1 && (!/Object/.test(Object.prototype.toString.call(value)) || value === null || value === undefined)) {
options = $.extend({}, options);
if (value === null || value === undefined) {
options.expires = -1;
}
if (typeof options.expires === 'number') {
var days = options.expires, t = options.expires = new Date();
t.setDate(t.getDate() + days);
}
value = String(value);
return (document.cookie = [
encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value),
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
options.path ? '; path=' + options.path : '',
options.domain ? '; domain=' + options.domain : '',
options.secure ? '; secure' : ''
].join(''));
}
// key and possibly options given, get cookie...
options = value || {};
var decode = options.raw ? function(s) { return s; } : decodeURIComponent;
var pairs = document.cookie.split('; ');
for (var i = 0, pair; pair = pairs[i] && pairs[i].split('='); i++) {
if (decode(pair[0]) === key) return decode(pair[1] || ''); // IE saves cookies with empty string as "c; ", e.g. without "=" as opposed to EOMB, thus pair[1] may be undefined
}
return null;
};
})(jQuery);
/*
json2.js
2011-10-19
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See http://www.JSON.org/js.html
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
This file creates a global JSON object containing two methods: stringify
and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
values are stringified for objects. It can be a
function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
level. If it is a string (such as '\t' or ' '),
it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
or undefined if nothing should be serialized. The toJSON method
will be passed the key associated with the value, and this will be
bound to the value
For example, this would serialize Dates as ISO strings.
Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
};
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
object. The value that is returned from your method will be
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
If the replacer parameter is an array of strings, then it will be
used to select the members to be serialized. It filters the results
such that only members with keys listed in the replacer array are
stringified.
Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
The optional space parameter produces a stringification of the
value that is filled with line breaks and indentation to make it
easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
the indentation will be that many spaces.
Example:
text = JSON.stringify(['e', {pluribus: 'unum'}]);
// text is '["e",{"pluribus":"unum"}]'
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
text = JSON.stringify([new Date()], function (key, value) {
return this[key] instanceof Date ?
'Date(' + this[key] + ')' : value;
});
// text is '["Date(---current time---)"]'
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
transform the results. It receives each of the keys and values,
and its return value is used instead of the original value.
If it returns what it received, then the structure is not modified.
If it returns undefined then the member is deleted.
Example:
// Parse the text. Values that look like ISO date strings will
// be converted to Date objects.
myData = JSON.parse(text, function (key, value) {
var a;
if (typeof value === 'string') {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
var d;
if (typeof value === 'string' &&
value.slice(0, 5) === 'Date(' &&
value.slice(-1) === ')') {
d = new Date(value.slice(5, -1));
if (d) {
return d;
}
}
return value;
});
This is a reference implementation. You are free to copy, modify, or
redistribute.
*/
/*jslint evil: true, regexp: true */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
test, toJSON, toString, valueOf
*/
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
var JSON;
if (!JSON) {
JSON = {};
}
(function () {
'use strict';
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
if (typeof Date.prototype.toJSON !== 'function') {
Date.prototype.toJSON = function (key) {
return isFinite(this.valueOf())
? this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z'
: null;
};
String.prototype.toJSON =
Number.prototype.toJSON =
Boolean.prototype.toJSON = function (key) {
return this.valueOf();
};
}
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
gap,
indent,
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
rep;
function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
escapable.lastIndex = 0;
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string'
? c
: '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' : '"' + string + '"';
}
function str(key, holder) {
// Produce a string from holder[key].
var i, // The loop counter.
k, // The member key.
v, // The member value.
length,
mind = gap,
partial,
value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case 'string':
return quote(value);
case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
// If the type is 'object', we might be dealing with an object or an array or
// null.
case 'object':
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
if (!value) {
return 'null';
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent;
partial = [];
// Is the value an array?
if (Object.prototype.toString.apply(value) === '[object Array]') {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || 'null';
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0
? '[]'
: gap
? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
: '[' + partial.join(',') + ']';
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be stringified.
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
if (typeof rep[i] === 'string') {
k = rep[i];
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
} else {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0
? '{}'
: gap
? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
: '{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i;
gap = '';
indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
// If the space parameter is a string, it will be used as the indent string.
} else if (typeof space === 'string') {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
return str('', {'': value});
};
}
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j;
function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
text = String(text);
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
if (/^[\],:{}\s]*$/
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval('(' + text + ')');
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return typeof reviver === 'function'
? walk({'': j}, '')
: j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError('JSON.parse');
};
}
}());
/*
* qTip2 - Pretty powerful tooltips
* http://craigsworks.com/projects/qtip2/
*
* Version: nightly
* Copyright 2009-2010 Craig Michael Thompson - http://craigsworks.com
*
* Dual licensed under MIT or GPLv2 licenses
* http://en.wikipedia.org/wiki/MIT_License
* http://en.wikipedia.org/wiki/GNU_General_Public_License
*
* Date: Tue Apr 10 11:58:19.0000000000 2012
*/
/*jslint browser: true, onevar: true, undef: true, nomen: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: true */
/*global window: false, jQuery: false, console: false, define: false */
// Uses AMD or browser globals to create a jQuery plugin.
(function(factory) {
if(typeof define === 'function' && define.amd) {
define(['jquery'], factory);
}
else {
factory(jQuery);
}
}
(function($) {
"use strict"; // Enable ECMAScript "strict" operation for this function. See more: http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/
// Munge the primitives - Paul Irish tip
var TRUE = true,
FALSE = false,
NULL = null,
undefined,
// Shortcut vars
QTIP, PLUGINS, MOUSE,
usedIDs = {},
uitooltip = 'ui-tooltip',
widget = 'ui-widget',
disabled = 'ui-state-disabled',
selector = 'div.qtip.'+uitooltip,
defaultClass = uitooltip + '-default',
focusClass = uitooltip + '-focus',
hoverClass = uitooltip + '-hover',
fluidClass = uitooltip + '-fluid',
hideOffset = '-31000px',
replaceSuffix = '_replacedByqTip',
oldtitle = 'oldtitle',
trackingBound;
/* Thanks to Paul Irish for this one: http://paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/ */
function log() {
log.history = log.history || [];
log.history.push(arguments);
// Make sure console is present
if('object' === typeof console) {
// Setup console and arguments
var c = console[ console.warn ? 'warn' : 'log' ],
args = Array.prototype.slice.call(arguments), a;
// Add qTip2 marker to first argument if it's a string
if(typeof arguments[0] === 'string') { args[0] = 'qTip2: ' + args[0]; }
// Apply console.warn or .log if not supported
a = c.apply ? c.apply(console, args) : c(args);
}
}
// Option object sanitizer
function sanitizeOptions(opts)
{
var content;
if(!opts || 'object' !== typeof opts) { return FALSE; }
if(opts.metadata === NULL || 'object' !== typeof opts.metadata) {
opts.metadata = {
type: opts.metadata
};
}
if('content' in opts) {
if(opts.content === NULL || 'object' !== typeof opts.content || opts.content.jquery) {
opts.content = {
text: opts.content
};
}
content = opts.content.text || FALSE;
if(!$.isFunction(content) && ((!content && !content.attr) || content.length < 1 || ('object' === typeof content && !content.jquery))) {
opts.content.text = FALSE;
}
if('title' in opts.content) {
if(opts.content.title === NULL || 'object' !== typeof opts.content.title) {
opts.content.title = {
text: opts.content.title
};
}
content = opts.content.title.text || FALSE;
if(!$.isFunction(content) && ((!content && !content.attr) || content.length < 1 || ('object' === typeof content && !content.jquery))) {
opts.content.title.text = FALSE;
}
}
}
if('position' in opts) {
if(opts.position === NULL || 'object' !== typeof opts.position) {
opts.position = {
my: opts.position,
at: opts.position
};
}
}
if('show' in opts) {
if(opts.show === NULL || 'object' !== typeof opts.show) {
if(opts.show.jquery) {
opts.show = { target: opts.show };
}
else {
opts.show = { event: opts.show };
}
}
}
if('hide' in opts) {
if(opts.hide === NULL || 'object' !== typeof opts.hide) {
if(opts.hide.jquery) {
opts.hide = { target: opts.hide };
}
else {
opts.hide = { event: opts.hide };
}
}
}
if('style' in opts) {
if(opts.style === NULL || 'object' !== typeof opts.style) {
opts.style = {
classes: opts.style
};
}
}
// Sanitize plugin options
$.each(PLUGINS, function() {
if(this.sanitize) { this.sanitize(opts); }
});
return opts;
}
/*
* Core plugin implementation
*/
function QTip(target, options, id, attr)
{
// Declare this reference
var self = this,
docBody = document.body,
tooltipID = uitooltip + '-' + id,
isPositioning = 0,
isDrawing = 0,
tooltip = $(),
namespace = '.qtip-' + id,
elements, cache;
// Setup class attributes
self.id = id;
self.rendered = FALSE;
self.elements = elements = { target: target };
self.timers = { img: {} };
self.options = options;
self.checks = {};
self.plugins = {};
self.cache = cache = {
event: {},
target: $(),
disabled: FALSE,
attr: attr,
onTarget: FALSE
};
/*
* Private core functions
*/
function convertNotation(notation)
{
var i = 0, obj, option = options,
// Split notation into array
levels = notation.split('.');
// Loop through
while( option = option[ levels[i++] ] ) {
if(i < levels.length) { obj = option; }
}
return [obj || options, levels.pop()];
}
function setWidget() {
var on = options.style.widget;
tooltip.toggleClass(widget, on).toggleClass(defaultClass, options.style.def && !on);
elements.content.toggleClass(widget+'-content', on);
if(elements.titlebar){
elements.titlebar.toggleClass(widget+'-header', on);
}
if(elements.button){
elements.button.toggleClass(uitooltip+'-icon', !on);
}
}
function removeTitle(reposition)
{
if(elements.title) {
elements.titlebar.remove();
elements.titlebar = elements.title = elements.button = NULL;
// Reposition if enabled
if(reposition !== FALSE) { self.reposition(); }
}
}
function createButton()
{
var button = options.content.title.button,
isString = typeof button === 'string',
close = isString ? button : 'Close tooltip';
if(elements.button) { elements.button.remove(); }
// Use custom button if one was supplied by user, else use default
if(button.jquery) {
elements.button = button;
}
else {
elements.button = $('', {
'class': 'ui-state-default ui-tooltip-close ' + (options.style.widget ? '' : uitooltip+'-icon'),
'title': close,
'aria-label': close
})
.prepend(
$('', {
'class': 'ui-icon ui-icon-close',
'html': '×'
})
);
}
// Create button and setup attributes
elements.button.appendTo(elements.titlebar)
.attr('role', 'button')
.click(function(event) {
if(!tooltip.hasClass(disabled)) { self.hide(event); }
return FALSE;
});
// Redraw the tooltip when we're done
self.redraw();
}
function createTitle()
{
var id = tooltipID+'-title';
// Destroy previous title element, if present
if(elements.titlebar) { removeTitle(); }
// Create title bar and title elements
elements.titlebar = $('
', {
'class': uitooltip + '-titlebar ' + (options.style.widget ? 'ui-widget-header' : '')
})
.append(
elements.title = $('', {
'id': id,
'class': uitooltip + '-title',
'aria-atomic': TRUE
})
)
.insertBefore(elements.content)
// Button-specific events
.delegate('.ui-tooltip-close', 'mousedown keydown mouseup keyup mouseout', function(event) {
$(this).toggleClass('ui-state-active ui-state-focus', event.type.substr(-4) === 'down');
})
.delegate('.ui-tooltip-close', 'mouseover mouseout', function(event){
$(this).toggleClass('ui-state-hover', event.type === 'mouseover');
});
// Create button if enabled
if(options.content.title.button) { createButton(); }
// Redraw the tooltip dimensions if it's rendered
else if(self.rendered){ self.redraw(); }
}
function updateButton(button)
{
var elem = elements.button,
title = elements.title;
// Make sure tooltip is rendered and if not, return
if(!self.rendered) { return FALSE; }
if(!button) {
elem.remove();
}
else {
if(!title) {
createTitle();
}
createButton();
}
}
function updateTitle(content, reposition)
{
var elem = elements.title;
// Make sure tooltip is rendered and if not, return
if(!self.rendered || !content) { return FALSE; }
// Use function to parse content
if($.isFunction(content)) {
content = content.call(target, cache.event, self);
}
// Remove title if callback returns false or null/undefined (but not '')
if(content === FALSE || (!content && content !== '')) { return removeTitle(FALSE); }
// Append new content if its a DOM array and show it if hidden
else if(content.jquery && content.length > 0) {
elem.empty().append(content.css({ display: 'block' }));
}
// Content is a regular string, insert the new content
else { elem.html(content); }
// Redraw and reposition
self.redraw();
if(reposition !== FALSE && self.rendered && tooltip[0].offsetWidth > 0) {
self.reposition(cache.event);
}
}
function updateContent(content, reposition)
{
var elem = elements.content;
// Make sure tooltip is rendered and content is defined. If not return
if(!self.rendered || !content) { return FALSE; }
// Use function to parse content
if($.isFunction(content)) {
content = content.call(target, cache.event, self) || '';
}
// Append new content if its a DOM array and show it if hidden
if(content.jquery && content.length > 0) {
elem.empty().append(content.css({ display: 'block' }));
}
// Content is a regular string, insert the new content
else { elem.html(content); }
// Image detection
function detectImages(next) {
var images, srcs = {};
function imageLoad(image) {
// Clear src from object and any timers and events associated with the image
if(image) {
delete srcs[image.src];
clearTimeout(self.timers.img[image.src]);
$(image).unbind(namespace);
}
// If queue is empty after image removal, update tooltip and continue the queue
if($.isEmptyObject(srcs)) {
self.redraw();
if(reposition !== FALSE) {
self.reposition(cache.event);
}
next();
}
}
// Find all content images without dimensions, and if no images were found, continue
if((images = elem.find('img[src]:not([height]):not([width])')).length === 0) { return imageLoad(); }
// Apply timer to each image to poll for dimensions
images.each(function(i, elem) {
// Skip if the src is already present
if(srcs[elem.src] !== undefined) { return; }
// Keep track of how many times we poll for image dimensions.
// If it doesn't return in a reasonable amount of time, it's better
// to display the tooltip, rather than hold up the queue.
var iterations = 0, maxIterations = 3;
(function timer(){
// When the dimensions are found, remove the image from the queue
if(elem.height || elem.width || (iterations > maxIterations)) { return imageLoad(elem); }
// Increase iterations and restart timer
iterations += 1;
self.timers.img[elem.src] = setTimeout(timer, 700);
}());
// Also apply regular load/error event handlers
$(elem).bind('error'+namespace+' load'+namespace, function(){ imageLoad(this); });
// Store the src and element in our object
srcs[elem.src] = elem;
});
}
/*
* If we're still rendering... insert into 'fx' queue our image dimension
* checker which will halt the showing of the tooltip until image dimensions
* can be detected properly.
*/
if(self.rendered < 0) { tooltip.queue('fx', detectImages); }
// We're fully rendered, so reset isDrawing flag and proceed without queue delay
else { isDrawing = 0; detectImages($.noop); }
return self;
}
function assignEvents()
{
var posOptions = options.position,
targets = {
show: options.show.target,
hide: options.hide.target,
viewport: $(posOptions.viewport),
document: $(document),
body: $(document.body),
window: $(window)
},
events = {
show: $.trim('' + options.show.event).split(' '),
hide: $.trim('' + options.hide.event).split(' ')
},
IE6 = $.browser.msie && parseInt($.browser.version, 10) === 6;
// Define show event method
function showMethod(event)
{
if(tooltip.hasClass(disabled)) { return FALSE; }
// Clear hide timers
clearTimeout(self.timers.show);
clearTimeout(self.timers.hide);
// Start show timer
var callback = function(){ self.toggle(TRUE, event); };
if(options.show.delay > 0) {
self.timers.show = setTimeout(callback, options.show.delay);
}
else{ callback(); }
}
// Define hide method
function hideMethod(event)
{
if(tooltip.hasClass(disabled) || isPositioning || isDrawing) { return FALSE; }
// Check if new target was actually the tooltip element
var relatedTarget = $(event.relatedTarget || event.target),
ontoTooltip = relatedTarget.closest(selector)[0] === tooltip[0],
ontoTarget = relatedTarget[0] === targets.show[0];
// Clear timers and stop animation queue
clearTimeout(self.timers.show);
clearTimeout(self.timers.hide);
// Prevent hiding if tooltip is fixed and event target is the tooltip. Or if mouse positioning is enabled and cursor momentarily overlaps
if((posOptions.target === 'mouse' && ontoTooltip) || (options.hide.fixed && ((/mouse(out|leave|move)/).test(event.type) && (ontoTooltip || ontoTarget)))) {
try { event.preventDefault(); event.stopImmediatePropagation(); } catch(e) {} return;
}
// If tooltip has displayed, start hide timer
if(options.hide.delay > 0) {
self.timers.hide = setTimeout(function(){ self.hide(event); }, options.hide.delay);
}
else{ self.hide(event); }
}
// Define inactive method
function inactiveMethod(event)
{
if(tooltip.hasClass(disabled)) { return FALSE; }
// Clear timer
clearTimeout(self.timers.inactive);
self.timers.inactive = setTimeout(function(){ self.hide(event); }, options.hide.inactive);
}
function repositionMethod(event) {
if(self.rendered && tooltip[0].offsetWidth > 0) { self.reposition(event); }
}
// On mouseenter/mouseleave...
tooltip.bind('mouseenter'+namespace+' mouseleave'+namespace, function(event) {
var state = event.type === 'mouseenter';
// Focus the tooltip on mouseenter (z-index stacking)
if(state) { self.focus(event); }
// Add hover class
tooltip.toggleClass(hoverClass, state);
});
// Enable hide.fixed
if(options.hide.fixed) {
// Add tooltip as a hide target
targets.hide = targets.hide.add(tooltip);
// Clear hide timer on tooltip hover to prevent it from closing
tooltip.bind('mouseover'+namespace, function() {
if(!tooltip.hasClass(disabled)) { clearTimeout(self.timers.hide); }
});
}
// If using mouseout/mouseleave as a hide event...
if(/mouse(out|leave)/i.test(options.hide.event)) {
// Hide tooltips when leaving current window/frame (but not select/option elements)
if(options.hide.leave === 'window') {
targets.window.bind('mouseout'+namespace+' blur'+namespace, function(event) {
if(/select|option/.test(event.target) && !event.relatedTarget) { self.hide(event); }
});
}
}
/*
* Make sure hoverIntent functions properly by using mouseleave to clear show timer if
* mouseenter/mouseout is used for show.event, even if it isn't in the users options.
*/
else if(/mouse(over|enter)/i.test(options.show.event)) {
targets.hide.bind('mouseleave'+namespace, function(event) {
clearTimeout(self.timers.show);
});
}
// Hide tooltip on document mousedown if unfocus events are enabled
if(('' + options.hide.event).indexOf('unfocus') > -1) {
posOptions.container.closest('html').bind('mousedown'+namespace, function(event) {
var elem = $(event.target),
enabled = self.rendered && !tooltip.hasClass(disabled) && tooltip[0].offsetWidth > 0,
isAncestor = elem.parents(selector).filter(tooltip[0]).length > 0;
if(elem[0] !== target[0] && elem[0] !== tooltip[0] && !isAncestor &&
!target.has(elem[0]).length && !elem.attr('disabled')
) {
self.hide(event);
}
});
}
// Check if the tooltip hides when inactive
if('number' === typeof options.hide.inactive) {
// Bind inactive method to target as a custom event
targets.show.bind('qtip-'+id+'-inactive', inactiveMethod);
// Define events which reset the 'inactive' event handler
$.each(QTIP.inactiveEvents, function(index, type){
targets.hide.add(elements.tooltip).bind(type+namespace+'-inactive', inactiveMethod);
});
}
// Apply hide events
$.each(events.hide, function(index, type) {
var showIndex = $.inArray(type, events.show),
targetHide = $(targets.hide);
// Both events and targets are identical, apply events using a toggle
if((showIndex > -1 && targetHide.add(targets.show).length === targetHide.length) || type === 'unfocus')
{
targets.show.bind(type+namespace, function(event) {
if(tooltip[0].offsetWidth > 0) { hideMethod(event); }
else { showMethod(event); }
});
// Don't bind the event again
delete events.show[ showIndex ];
}
// Events are not identical, bind normally
else { targets.hide.bind(type+namespace, hideMethod); }
});
// Apply show events
$.each(events.show, function(index, type) {
targets.show.bind(type+namespace, showMethod);
});
// Check if the tooltip hides when mouse is moved a certain distance
if('number' === typeof options.hide.distance) {
// Bind mousemove to target to detect distance difference
targets.show.add(tooltip).bind('mousemove'+namespace, function(event) {
var origin = cache.origin || {},
limit = options.hide.distance,
abs = Math.abs;
// Check if the movement has gone beyond the limit, and hide it if so
if(abs(event.pageX - origin.pageX) >= limit || abs(event.pageY - origin.pageY) >= limit) {
self.hide(event);
}
});
}
// Mouse positioning events
if(posOptions.target === 'mouse') {
// Cache mousemove coords on show targets
targets.show.bind('mousemove'+namespace, function(event) {
MOUSE = { pageX: event.pageX, pageY: event.pageY, type: 'mousemove' };
});
// If mouse adjustment is on...
if(posOptions.adjust.mouse) {
// Apply a mouseleave event so we don't get problems with overlapping
if(options.hide.event) {
// Hide when we leave the tooltip and not onto the show target
tooltip.bind('mouseleave'+namespace, function(event) {
if((event.relatedTarget || event.target) !== targets.show[0]) { self.hide(event); }
});
// Track if we're on the target or not
elements.target.bind('mouseenter'+namespace+' mouseleave'+namespace, function(event) {
cache.onTarget = event.type === 'mouseenter';
});
}
// Update tooltip position on mousemove
targets.document.bind('mousemove'+namespace, function(event) {
// Update the tooltip position only if the tooltip is visible and adjustment is enabled
if(self.rendered && cache.onTarget && !tooltip.hasClass(disabled) && tooltip[0].offsetWidth > 0) {
self.reposition(event || MOUSE);
}
});
}
}
// Adjust positions of the tooltip on window resize if enabled
if(posOptions.adjust.resize || targets.viewport.length) {
($.event.special.resize ? targets.viewport : targets.window).bind('resize'+namespace, repositionMethod);
}
// Adjust tooltip position on scroll if screen adjustment is enabled
if(targets.viewport.length || (IE6 && tooltip.css('position') === 'fixed')) {
targets.viewport.bind('scroll'+namespace, repositionMethod);
}
}
function unassignEvents()
{
var targets = [
options.show.target[0],
options.hide.target[0],
self.rendered && elements.tooltip[0],
options.position.container[0],
options.position.viewport[0],
window,
document
];
// Check if tooltip is rendered
if(self.rendered) {
$([]).pushStack( $.grep(targets, function(i){ return typeof i === 'object'; }) ).unbind(namespace);
}
// Tooltip isn't yet rendered, remove render event
else { options.show.target.unbind(namespace+'-create'); }
}
// Setup builtin .set() option checks
self.checks.builtin = {
// Core checks
'^id$': function(obj, o, v) {
var id = v === TRUE ? QTIP.nextid : v,
tooltipID = uitooltip + '-' + id;
if(id !== FALSE && id.length > 0 && !$('#'+tooltipID).length) {
tooltip[0].id = tooltipID;
elements.content[0].id = tooltipID + '-content';
elements.title[0].id = tooltipID + '-title';
}
},
// Content checks
'^content.text$': function(obj, o, v){ updateContent(v); },
'^content.title.text$': function(obj, o, v) {
// Remove title if content is null
if(!v) { return removeTitle(); }
// If title isn't already created, create it now and update
if(!elements.title && v) { createTitle(); }
updateTitle(v);
},
'^content.title.button$': function(obj, o, v){ updateButton(v); },
// Position checks
'^position.(my|at)$': function(obj, o, v){
// Parse new corner value into Corner objecct
if('string' === typeof v) {
obj[o] = new PLUGINS.Corner(v);
}
},
'^position.container$': function(obj, o, v){
if(self.rendered) { tooltip.appendTo(v); }
},
// Show checks
'^show.ready$': function() {
if(!self.rendered) { self.render(1); }
else { self.toggle(TRUE); }
},
// Style checks
'^style.classes$': function(obj, o, v) {
tooltip.attr('class', uitooltip + ' qtip ui-helper-reset ' + v);
},
'^style.widget|content.title': setWidget,
// Events check
'^events.(render|show|move|hide|focus|blur)$': function(obj, o, v) {
tooltip[($.isFunction(v) ? '' : 'un') + 'bind']('tooltip'+o, v);
},
// Properties which require event reassignment
'^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)': function() {
var posOptions = options.position;
// Set tracking flag
tooltip.attr('tracking', posOptions.target === 'mouse' && posOptions.adjust.mouse);
// Reassign events
unassignEvents(); assignEvents();
}
};
/*
* Public API methods
*/
$.extend(self, {
render: function(show)
{
if(self.rendered) { return self; } // If tooltip has already been rendered, exit
var text = options.content.text,
title = options.content.title.text,
posOptions = options.position,
callback = $.Event('tooltiprender');
// Add ARIA attributes to target
$.attr(target[0], 'aria-describedby', tooltipID);
// Create tooltip element
tooltip = elements.tooltip = $('', {
'id': tooltipID,
'class': uitooltip + ' qtip ui-helper-reset ' + defaultClass + ' ' + options.style.classes + ' '+ uitooltip + '-pos-' + options.position.my.abbrev(),
'width': options.style.width || '',
'height': options.style.height || '',
'tracking': posOptions.target === 'mouse' && posOptions.adjust.mouse,
/* ARIA specific attributes */
'role': 'alert',
'aria-live': 'polite',
'aria-atomic': FALSE,
'aria-describedby': tooltipID + '-content',
'aria-hidden': TRUE
})
.toggleClass(disabled, cache.disabled)
.data('qtip', self)
.appendTo(options.position.container)
.append(
// Create content element
elements.content = $('', {
'class': uitooltip + '-content',
'id': tooltipID + '-content',
'aria-atomic': TRUE
})
);
// Set rendered flag and prevent redundant redraw/reposition calls for now
self.rendered = -1;
isDrawing = 1; isPositioning = 1;
// Create title...
if(title) {
createTitle();
// Update title only if its not a callback (called in toggle if so)
if(!$.isFunction(title)) { updateTitle(title, FALSE); }
}
// Set proper rendered flag and update content if not a callback function (called in toggle)
if(!$.isFunction(text)) { updateContent(text, FALSE); }
self.rendered = TRUE;
// Setup widget classes
setWidget();
// Assign passed event callbacks (before plugins!)
$.each(options.events, function(name, callback) {
if($.isFunction(callback)) {
tooltip.bind(name === 'toggle' ? 'tooltipshow tooltiphide' : 'tooltip'+name, callback);
}
});
// Initialize 'render' plugins
$.each(PLUGINS, function() {
if(this.initialize === 'render') { this(self); }
});
// Assign events
assignEvents();
/* Queue this part of the render process in our fx queue so we can
* load images before the tooltip renders fully.
*
* See: updateContent method
*/
tooltip.queue('fx', function(next) {
// Trigger tooltiprender event and pass original triggering event as original
callback.originalEvent = cache.event;
tooltip.trigger(callback, [self]);
// Reset flags
isDrawing = 0; isPositioning = 0;
// Redraw the tooltip manually now we're fully rendered
self.redraw();
// Show tooltip if needed
if(options.show.ready || show) {
self.toggle(TRUE, cache.event, FALSE);
}
next(); // Move on to next method in queue
});
return self;
},
get: function(notation)
{
var result, o;
switch(notation.toLowerCase())
{
case 'dimensions':
result = {
height: tooltip.outerHeight(), width: tooltip.outerWidth()
};
break;
case 'offset':
result = PLUGINS.offset(tooltip, options.position.container);
break;
default:
o = convertNotation(notation.toLowerCase());
result = o[0][ o[1] ];
result = result.precedance ? result.string() : result;
break;
}
return result;
},
set: function(option, value)
{
var rmove = /^position\.(my|at|adjust|target|container)|style|content|show\.ready/i,
rdraw = /^content\.(title|attr)|style/i,
reposition = FALSE,
redraw = FALSE,
checks = self.checks,
name;
function callback(notation, args) {
var category, rule, match;
for(category in checks) {
for(rule in checks[category]) {
if(match = (new RegExp(rule, 'i')).exec(notation)) {
args.push(match);
checks[category][rule].apply(self, args);
}
}
}
}
// Convert singular option/value pair into object form
if('string' === typeof option) {
name = option; option = {}; option[name] = value;
}
else { option = $.extend(TRUE, {}, option); }
// Set all of the defined options to their new values
$.each(option, function(notation, value) {
var obj = convertNotation( notation.toLowerCase() ), previous;
// Set new obj value
previous = obj[0][ obj[1] ];
obj[0][ obj[1] ] = 'object' === typeof value && value.nodeType ? $(value) : value;
// Set the new params for the callback
option[notation] = [obj[0], obj[1], value, previous];
// Also check if we need to reposition / redraw
reposition = rmove.test(notation) || reposition;
redraw = rdraw.test(notation) || redraw;
});
// Re-sanitize options
sanitizeOptions(options);
/*
* Execute any valid callbacks for the set options
* Also set isPositioning/isDrawing so we don't get loads of redundant repositioning
* and redraw calls.
*/
isPositioning = isDrawing = 1; $.each(option, callback); isPositioning = isDrawing = 0;
// Update position / redraw if needed
if(self.rendered && tooltip[0].offsetWidth > 0) {
if(reposition) {
self.reposition( options.position.target === 'mouse' ? NULL : cache.event );
}
if(redraw) { self.redraw(); }
}
return self;
},
toggle: function(state, event)
{
// Render the tooltip if showing and it isn't already
if(!self.rendered) { return state ? self.render(1) : self; }
var type = state ? 'show' : 'hide',
opts = options[type],
otherOpts = options[ !state ? 'show' : 'hide' ],
posOptions = options.position,
contentOptions = options.content,
visible = tooltip[0].offsetWidth > 0,
animate = state || opts.target.length === 1,
sameTarget = !event || opts.target.length < 2 || cache.target[0] === event.target,
delay, callback;
// Detect state if valid one isn't provided
if((typeof state).search('boolean|number')) { state = !visible; }
// Return if element is already in correct state
if(!tooltip.is(':animated') && visible === state && sameTarget) { return self; }
// Try to prevent flickering when tooltip overlaps show element
if(event) {
if((/over|enter/).test(event.type) && (/out|leave/).test(cache.event.type) &&
options.show.target.add(event.target).length === options.show.target.length &&
tooltip.has(event.relatedTarget).length) {
return self;
}
// Cache event
cache.event = $.extend({}, event);
}
// Call API methods
callback = $.Event('tooltip'+type);
callback.originalEvent = event ? cache.event : NULL;
tooltip.trigger(callback, [self, 90]);
if(callback.isDefaultPrevented()){ return self; }
// Set ARIA hidden status attribute
$.attr(tooltip[0], 'aria-hidden', !!!state);
// Execute state specific properties
if(state) {
// Store show origin coordinates
cache.origin = $.extend({}, MOUSE);
// Focus the tooltip
self.focus(event);
// Update tooltip content & title if it's a dynamic function
if($.isFunction(contentOptions.text)) { updateContent(contentOptions.text, FALSE); }
if($.isFunction(contentOptions.title.text)) { updateTitle(contentOptions.title.text, FALSE); }
// Cache mousemove events for positioning purposes (if not already tracking)
if(!trackingBound && posOptions.target === 'mouse' && posOptions.adjust.mouse) {
$(document).bind('mousemove.qtip', function(event) {
MOUSE = { pageX: event.pageX, pageY: event.pageY, type: 'mousemove' };
});
trackingBound = TRUE;
}
// Update the tooltip position
self.reposition(event, arguments[2]);
// Hide other tooltips if tooltip is solo, using it as the context
if((callback.solo = !!opts.solo)) { $(selector, opts.solo).not(tooltip).qtip('hide', callback); }
}
else {
// Clear show timer if we're hiding
clearTimeout(self.timers.show);
// Remove cached origin on hide
delete cache.origin;
// Remove mouse tracking event if not needed (all tracking qTips are hidden)
if(trackingBound && !$(selector+'[tracking="true"]:visible', opts.solo).not(tooltip).length) {
$(document).unbind('mousemove.qtip');
trackingBound = FALSE;
}
// Blur the tooltip
self.blur(event);
}
// Define post-animation, state specific properties
function after() {
if(state) {
// Prevent antialias from disappearing in IE by removing filter
if($.browser.msie) { tooltip[0].style.removeAttribute('filter'); }
// Remove overflow setting to prevent tip bugs
tooltip.css('overflow', '');
// Autofocus elements if enabled
if('string' === typeof opts.autofocus) {
$(opts.autofocus, tooltip).focus();
}
// If set, hide tooltip when inactive for delay period
opts.target.trigger('qtip-'+id+'-inactive');
}
else {
// Reset CSS states
tooltip.css({
display: '',
visibility: '',
opacity: '',
left: '',
top: ''
});
}
// Call API method
callback = $.Event('tooltip'+(state ? 'visible' : 'hidden'));
callback.originalEvent = event ? cache.event : NULL;
tooltip.trigger(callback, [self]);
}
// If no effect type is supplied, use a simple toggle
if(opts.effect === FALSE || animate === FALSE) {
tooltip[ type ]();
after.call(tooltip);
}
// Use custom function if provided
else if($.isFunction(opts.effect)) {
tooltip.stop(1, 1);
opts.effect.call(tooltip, self);
tooltip.queue('fx', function(n){ after(); n(); });
}
// Use basic fade function by default
else { tooltip.fadeTo(90, state ? 1 : 0, after); }
// If inactive hide method is set, active it
if(state) { opts.target.trigger('qtip-'+id+'-inactive'); }
return self;
},
show: function(event){ return self.toggle(TRUE, event); },
hide: function(event){ return self.toggle(FALSE, event); },
focus: function(event)
{
if(!self.rendered) { return self; }
var qtips = $(selector),
curIndex = parseInt(tooltip[0].style.zIndex, 10),
newIndex = QTIP.zindex + qtips.length,
cachedEvent = $.extend({}, event),
focusedElem, callback;
// Only update the z-index if it has changed and tooltip is not already focused
if(!tooltip.hasClass(focusClass))
{
// Call API method
callback = $.Event('tooltipfocus');
callback.originalEvent = cachedEvent;
tooltip.trigger(callback, [self, newIndex]);
// If default action wasn't prevented...
if(!callback.isDefaultPrevented()) {
// Only update z-index's if they've changed
if(curIndex !== newIndex) {
// Reduce our z-index's and keep them properly ordered
qtips.each(function() {
if(this.style.zIndex > curIndex) {
this.style.zIndex = this.style.zIndex - 1;
}
});
// Fire blur event for focused tooltip
qtips.filter('.' + focusClass).qtip('blur', cachedEvent);
}
// Set the new z-index
tooltip.addClass(focusClass)[0].style.zIndex = newIndex;
}
}
return self;
},
blur: function(event) {
var cachedEvent = $.extend({}, event),
callback;
// Set focused status to FALSE
tooltip.removeClass(focusClass);
// Trigger blur event
callback = $.Event('tooltipblur');
callback.originalEvent = cachedEvent;
tooltip.trigger(callback, [self]);
return self;
},
reposition: function(event, effect)
{
if(!self.rendered || isPositioning) { return self; }
// Set positioning flag
isPositioning = 1;
var target = options.position.target,
posOptions = options.position,
my = posOptions.my,
at = posOptions.at,
adjust = posOptions.adjust,
method = adjust.method.split(' '),
elemWidth = tooltip.outerWidth(),
elemHeight = tooltip.outerHeight(),
targetWidth = 0,
targetHeight = 0,
callback = $.Event('tooltipmove'),
fixed = tooltip.css('position') === 'fixed',
viewport = posOptions.viewport,
position = { left: 0, top: 0 },
container = posOptions.container,
flipoffset = FALSE,
tip = self.plugins.tip,
visible = tooltip[0].offsetWidth > 0,
readjust = {
// Axis detection and readjustment indicator
horizontal: method[0],
vertical: (method[1] = method[1] || method[0]),
enabled: viewport.jquery && target[0] !== window && target[0] !== docBody && adjust.method !== 'none',
// Reposition methods
left: function(posLeft) {
var isShift = readjust.horizontal === 'shift',
viewportScroll = -container.offset.left + viewport.offset.left + viewport.scrollLeft,
myWidth = my.x === 'left' ? elemWidth : my.x === 'right' ? -elemWidth : -elemWidth / 2,
atWidth = at.x === 'left' ? targetWidth : at.x === 'right' ? -targetWidth : -targetWidth / 2,
tipWidth = tip && tip.size ? tip.size.width || 0 : 0,
tipAdjust = tip && tip.corner && tip.corner.precedance === 'x' && !isShift ? tipWidth : 0,
overflowLeft = viewportScroll - posLeft + tipAdjust,
overflowRight = posLeft + elemWidth - viewport.width - viewportScroll + tipAdjust,
offset = myWidth - (my.precedance === 'x' || my.x === my.y ? atWidth : 0) - (at.x === 'center' ? targetWidth / 2 : 0),
isCenter = my.x === 'center';
// Optional 'shift' style repositioning
if(isShift) {
tipAdjust = tip && tip.corner && tip.corner.precedance === 'y' ? tipWidth : 0;
offset = (my.x === 'left' ? 1 : -1) * myWidth - tipAdjust;
// Adjust position but keep it within viewport dimensions
position.left += overflowLeft > 0 ? overflowLeft : overflowRight > 0 ? -overflowRight : 0;
position.left = Math.max(
-container.offset.left + viewport.offset.left + (tipAdjust && tip.corner.x === 'center' ? tip.offset : 0),
posLeft - offset,
Math.min(
Math.max(-container.offset.left + viewport.offset.left + viewport.width, posLeft + offset),
position.left
)
);
}
// Default 'flip' repositioning
else {
if(overflowLeft > 0 && (my.x !== 'left' || overflowRight > 0)) {
position.left -= offset;
}
else if(overflowRight > 0 && (my.x !== 'right' || overflowLeft > 0) ) {
position.left -= isCenter ? -offset : offset;
}
if(position.left !== posLeft && isCenter) { position.left -= adjust.x; }
// Make sure we haven't made things worse with the adjustment and return the adjusted difference
if(position.left < viewportScroll && -position.left > overflowRight) { position.left = posLeft; }
}
return position.left - posLeft;
},
top: function(posTop) {
var isShift = readjust.vertical === 'shift',
viewportScroll = -container.offset.top + viewport.offset.top + viewport.scrollTop,
myHeight = my.y === 'top' ? elemHeight : my.y === 'bottom' ? -elemHeight : -elemHeight / 2,
atHeight = at.y === 'top' ? targetHeight : at.y === 'bottom' ? -targetHeight : -targetHeight / 2,
tipHeight = tip && tip.size ? tip.size.height || 0 : 0,
tipAdjust = tip && tip.corner && tip.corner.precedance === 'y' && !isShift ? tipHeight : 0,
overflowTop = viewportScroll - posTop + tipAdjust,
overflowBottom = posTop + elemHeight - viewport.height - viewportScroll + tipAdjust,
offset = myHeight - (my.precedance === 'y' || my.x === my.y ? atHeight : 0) - (at.y === 'center' ? targetHeight / 2 : 0),
isCenter = my.y === 'center';
// Optional 'shift' style repositioning
if(isShift) {
tipAdjust = tip && tip.corner && tip.corner.precedance === 'x' ? tipHeight : 0;
offset = (my.y === 'top' ? 1 : -1) * myHeight - tipAdjust;
// Adjust position but keep it within viewport dimensions
position.top += overflowTop > 0 ? overflowTop : overflowBottom > 0 ? -overflowBottom : 0;
position.top = Math.max(
-container.offset.top + viewport.offset.top + (tipAdjust && tip.corner.x === 'center' ? tip.offset : 0),
posTop - offset,
Math.min(
Math.max(-container.offset.top + viewport.offset.top + viewport.height, posTop + offset),
position.top
)
);
}
// Default 'flip' repositioning
else {
if(overflowTop > 0 && (my.y !== 'top' || overflowBottom > 0)) {
position.top -= offset;
}
else if(overflowBottom > 0 && (my.y !== 'bottom' || overflowTop > 0) ) {
position.top -= isCenter ? -offset : offset;
}
if(position.top !== posTop && isCenter) { position.top -= adjust.y; }
// Make sure we haven't made things worse with the adjustment and return the adjusted difference
if(position.top < 0 && -position.top > overflowBottom) { position.top = posTop; }
}
return position.top - posTop;
}
},
win;
// Check if absolute position was passed
if($.isArray(target) && target.length === 2) {
// Force left top and set position
at = { x: 'left', y: 'top' };
position = { left: target[0], top: target[1] };
}
// Check if mouse was the target
else if(target === 'mouse' && ((event && event.pageX) || cache.event.pageX)) {
// Force left top to allow flipping
at = { x: 'left', y: 'top' };
// Use cached event if one isn't available for positioning
event = (event && (event.type === 'resize' || event.type === 'scroll') ? cache.event :
event && event.pageX && event.type === 'mousemove' ? event :
MOUSE && MOUSE.pageX && (adjust.mouse || !event || !event.pageX) ? { pageX: MOUSE.pageX, pageY: MOUSE.pageY } :
!adjust.mouse && cache.origin && cache.origin.pageX && options.show.distance ? cache.origin :
event) || event || cache.event || MOUSE || {};
// Use event coordinates for position
position = { top: event.pageY, left: event.pageX };
}
// Target wasn't mouse or absolute...
else {
// Check if event targetting is being used
if(target === 'event') {
if(event && event.target && event.type !== 'scroll' && event.type !== 'resize') {
target = cache.target = $(event.target);
}
else {
target = cache.target;
}
}
else {
target = cache.target = $(target.jquery ? target : elements.target);
}
// Parse the target into a jQuery object and make sure there's an element present
target = $(target).eq(0);
if(target.length === 0) { return self; }
// Check if window or document is the target
else if(target[0] === document || target[0] === window) {
targetWidth = PLUGINS.iOS ? window.innerWidth : target.width();
targetHeight = PLUGINS.iOS ? window.innerHeight : target.height();
if(target[0] === window) {
position = {
top: (viewport || target).scrollTop(),
left: (viewport || target).scrollLeft()
};
}
}
// Use Imagemap/SVG plugins if needed
else if(target.is('area') && PLUGINS.imagemap) {
position = PLUGINS.imagemap(target, at, readjust.enabled ? method : FALSE);
}
else if(target[0].namespaceURI === 'http://www.w3.org/2000/svg' && PLUGINS.svg) {
position = PLUGINS.svg(target, at);
}
else {
targetWidth = target.outerWidth();
targetHeight = target.outerHeight();
position = PLUGINS.offset(target, container);
}
// Parse returned plugin values into proper variables
if(position.offset) {
targetWidth = position.width;
targetHeight = position.height;
flipoffset = position.flipoffset;
position = position.offset;
}
// Adjust for position.fixed tooltips (and also iOS scroll bug in v3.2 - v4.0)
if((PLUGINS.iOS < 4.1 && PLUGINS.iOS > 3.1) || PLUGINS.iOS == 4.3 || (!PLUGINS.iOS && fixed)) {
win = $(window);
position.left -= win.scrollLeft();
position.top -= win.scrollTop();
}
// Adjust position relative to target
position.left += at.x === 'right' ? targetWidth : at.x === 'center' ? targetWidth / 2 : 0;
position.top += at.y === 'bottom' ? targetHeight : at.y === 'center' ? targetHeight / 2 : 0;
}
// Adjust position relative to tooltip
position.left += adjust.x + (my.x === 'right' ? -elemWidth : my.x === 'center' ? -elemWidth / 2 : 0);
position.top += adjust.y + (my.y === 'bottom' ? -elemHeight : my.y === 'center' ? -elemHeight / 2 : 0);
// Calculate collision offset values if viewport positioning is enabled
if(readjust.enabled) {
// Cache our viewport details
viewport = {
elem: viewport,
height: viewport[ (viewport[0] === window ? 'h' : 'outerH') + 'eight' ](),
width: viewport[ (viewport[0] === window ? 'w' : 'outerW') + 'idth' ](),
scrollLeft: fixed ? 0 : viewport.scrollLeft(),
scrollTop: fixed ? 0 : viewport.scrollTop(),
offset: viewport.offset() || { left: 0, top: 0 }
};
container = {
elem: container,
scrollLeft: container.scrollLeft(),
scrollTop: container.scrollTop(),
offset: container.offset() || { left: 0, top: 0 }
};
// Adjust position based onviewport and adjustment options
position.adjusted = {
left: readjust.horizontal !== 'none' ? readjust.left(position.left) : 0,
top: readjust.vertical !== 'none' ? readjust.top(position.top) : 0
};
// Set tooltip position class
if(position.adjusted.left + position.adjusted.top) {
tooltip.attr('class', tooltip[0].className.replace(/ui-tooltip-pos-\w+/i, uitooltip + '-pos-' + my.abbrev()));
}
// Apply flip offsets supplied by positioning plugins
if(flipoffset && position.adjusted.left) { position.left += flipoffset.left; }
if(flipoffset && position.adjusted.top) { position.top += flipoffset.top; }
}
//Viewport adjustment is disabled, set values to zero
else { position.adjusted = { left: 0, top: 0 }; }
// Call API method
callback.originalEvent = $.extend({}, event);
tooltip.trigger(callback, [self, position, viewport.elem || viewport]);
if(callback.isDefaultPrevented()){ return self; }
delete position.adjusted;
// If effect is disabled, target it mouse, no animation is defined or positioning gives NaN out, set CSS directly
if(effect === FALSE || !visible || isNaN(position.left) || isNaN(position.top) || target === 'mouse' || !$.isFunction(posOptions.effect)) {
tooltip.css(position);
}
// Use custom function if provided
else if($.isFunction(posOptions.effect)) {
posOptions.effect.call(tooltip, self, $.extend({}, position));
tooltip.queue(function(next) {
// Reset attributes to avoid cross-browser rendering bugs
$(this).css({ opacity: '', height: '' });
if($.browser.msie) { this.style.removeAttribute('filter'); }
next();
});
}
// Set positioning flag
isPositioning = 0;
return self;
},
// Max/min width simulator function for all browsers.. yeaaah!
redraw: function()
{
if(self.rendered < 1 || isDrawing) { return self; }
var container = options.position.container,
perc, width, max, min;
// Set drawing flag
isDrawing = 1;
// If tooltip has a set height, just set it... like a boss!
if(options.style.height) { tooltip.css('height', options.style.height); }
// If tooltip has a set width, just set it... like a boss!
if(options.style.width) { tooltip.css('width', options.style.width); }
// Otherwise simualte max/min width...
else {
// Reset width and add fluid class
tooltip.css('width', '').addClass(fluidClass);
// Grab our tooltip width (add 1 so we don't get wrapping problems.. huzzah!)
width = tooltip.width() + 1;
// Grab our max/min properties
max = tooltip.css('max-width') || '';
min = tooltip.css('min-width') || '';
// Parse into proper pixel values
perc = (max + min).indexOf('%') > -1 ? container.width() / 100 : 0;
max = ((max.indexOf('%') > -1 ? perc : 1) * parseInt(max, 10)) || width;
min = ((min.indexOf('%') > -1 ? perc : 1) * parseInt(min, 10)) || 0;
// Determine new dimension size based on max/min/current values
width = max + min ? Math.min(Math.max(width, min), max) : width;
// Set the newly calculated width and remvoe fluid class
tooltip.css('width', Math.round(width)).removeClass(fluidClass);
}
// Set drawing flag
isDrawing = 0;
return self;
},
disable: function(state)
{
if('boolean' !== typeof state) {
state = !(tooltip.hasClass(disabled) || cache.disabled);
}
if(self.rendered) {
tooltip.toggleClass(disabled, state);
$.attr(tooltip[0], 'aria-disabled', state);
}
else {
cache.disabled = !!state;
}
return self;
},
enable: function() { return self.disable(FALSE); },
destroy: function()
{
var t = target[0],
title = $.attr(t, oldtitle),
elemAPI = target.data('qtip');
// Destroy tooltip and any associated plugins if rendered
if(self.rendered) {
tooltip.stop(1,0).remove();
$.each(self.plugins, function() {
if(this.destroy) { this.destroy(); }
});
}
// Clear timers and remove bound events
clearTimeout(self.timers.show);
clearTimeout(self.timers.hide);
unassignEvents();
// If the API if actually this qTip API...
if(!elemAPI || self === elemAPI) {
// Remove api object
$.removeData(t, 'qtip');
// Reset old title attribute if removed
if(options.suppress && title) {
$.attr(t, 'title', title);
target.removeAttr(oldtitle);
}
// Remove ARIA attributes
target.removeAttr('aria-describedby');
}
// Remove qTip events associated with this API
target.unbind('.qtip-'+id);
// Remove ID from sued id object
delete usedIDs[self.id];
return target;
}
});
}
// Initialization method
function init(id, opts)
{
var obj, posOptions, attr, config, title,
// Setup element references
elem = $(this),
docBody = $(document.body),
// Use document body instead of document element if needed
newTarget = this === document ? docBody : elem,
// Grab metadata from element if plugin is present
metadata = (elem.metadata) ? elem.metadata(opts.metadata) : NULL,
// If metadata type if HTML5, grab 'name' from the object instead, or use the regular data object otherwise
metadata5 = opts.metadata.type === 'html5' && metadata ? metadata[opts.metadata.name] : NULL,
// Grab data from metadata.name (or data-qtipopts as fallback) using .data() method,
html5 = elem.data(opts.metadata.name || 'qtipopts');
// If we don't get an object returned attempt to parse it manualyl without parseJSON
try { html5 = typeof html5 === 'string' ? (new Function("return " + html5))() : html5; }
catch(e) { log('Unable to parse HTML5 attribute data: ' + html5); }
// Merge in and sanitize metadata
config = $.extend(TRUE, {}, QTIP.defaults, opts,
typeof html5 === 'object' ? sanitizeOptions(html5) : NULL,
sanitizeOptions(metadata5 || metadata));
// Re-grab our positioning options now we've merged our metadata and set id to passed value
posOptions = config.position;
config.id = id;
// Setup missing content if none is detected
if('boolean' === typeof config.content.text) {
attr = elem.attr(config.content.attr);
// Grab from supplied attribute if available
if(config.content.attr !== FALSE && attr) { config.content.text = attr; }
// No valid content was found, abort render
else {
log('Unable to locate content for tooltip! Aborting render of tooltip on element: ', elem);
return FALSE;
}
}
// Setup target options
if(!posOptions.container.length) { posOptions.container = docBody; }
if(posOptions.target === FALSE) { posOptions.target = newTarget; }
if(config.show.target === FALSE) { config.show.target = newTarget; }
if(config.show.solo === TRUE) { config.show.solo = posOptions.container.closest('body'); }
if(config.hide.target === FALSE) { config.hide.target = newTarget; }
if(config.position.viewport === TRUE) { config.position.viewport = posOptions.container; }
// Ensure we only use a single container
posOptions.container = posOptions.container.eq(0);
// Convert position corner values into x and y strings
posOptions.at = new PLUGINS.Corner(posOptions.at);
posOptions.my = new PLUGINS.Corner(posOptions.my);
// Destroy previous tooltip if overwrite is enabled, or skip element if not
if($.data(this, 'qtip')) {
if(config.overwrite) {
elem.qtip('destroy');
}
else if(config.overwrite === FALSE) {
return FALSE;
}
}
// Remove title attribute and store it if present
if(config.suppress && (title = $.attr(this, 'title'))) {
$(this).removeAttr('title').attr(oldtitle, title);
}
// Initialize the tooltip and add API reference
obj = new QTip(elem, config, id, !!attr);
$.data(this, 'qtip', obj);
// Catch remove/removeqtip events on target element to destroy redundant tooltip
elem.bind('remove.qtip-'+id+' removeqtip.qtip-'+id, function(){ obj.destroy(); });
return obj;
}
// jQuery $.fn extension method
QTIP = $.fn.qtip = function(options, notation, newValue)
{
var command = ('' + options).toLowerCase(), // Parse command
returned = NULL,
args = $.makeArray(arguments).slice(1),
event = args[args.length - 1],
opts = this[0] ? $.data(this[0], 'qtip') : NULL;
// Check for API request
if((!arguments.length && opts) || command === 'api') {
return opts;
}
// Execute API command if present
else if('string' === typeof options)
{
this.each(function()
{
var api = $.data(this, 'qtip');
if(!api) { return TRUE; }
// Cache the event if possible
if(event && event.timeStamp) { api.cache.event = event; }
// Check for specific API commands
if((command === 'option' || command === 'options') && notation) {
if($.isPlainObject(notation) || newValue !== undefined) {
api.set(notation, newValue);
}
else {
returned = api.get(notation);
return FALSE;
}
}
// Execute API command
else if(api[command]) {
api[command].apply(api[command], args);
}
});
return returned !== NULL ? returned : this;
}
// No API commands. validate provided options and setup qTips
else if('object' === typeof options || !arguments.length)
{
opts = sanitizeOptions($.extend(TRUE, {}, options));
// Bind the qTips
return QTIP.bind.call(this, opts, event);
}
};
// $.fn.qtip Bind method
QTIP.bind = function(opts, event)
{
return this.each(function(i) {
var options, targets, events, namespace, api, id;
// Find next available ID, or use custom ID if provided
id = $.isArray(opts.id) ? opts.id[i] : opts.id;
id = !id || id === FALSE || id.length < 1 || usedIDs[id] ? QTIP.nextid++ : (usedIDs[id] = id);
// Setup events namespace
namespace = '.qtip-'+id+'-create';
// Initialize the qTip and re-grab newly sanitized options
api = init.call(this, id, opts);
if(api === FALSE) { return TRUE; }
options = api.options;
// Initialize plugins
$.each(PLUGINS, function() {
if(this.initialize === 'initialize') { this(api); }
});
// Determine hide and show targets
targets = { show: options.show.target, hide: options.hide.target };
events = {
show: $.trim('' + options.show.event).replace(/ /g, namespace+' ') + namespace,
hide: $.trim('' + options.hide.event).replace(/ /g, namespace+' ') + namespace
};
/*
* Make sure hoverIntent functions properly by using mouseleave as a hide event if
* mouseenter/mouseout is used for show.event, even if it isn't in the users options.
*/
if(/mouse(over|enter)/i.test(events.show) && !/mouse(out|leave)/i.test(events.hide)) {
events.hide += ' mouseleave' + namespace;
}
/*
* Also make sure initial mouse targetting works correctly by caching mousemove coords
* on show targets before the tooltip has rendered.
*
* Also set onTarget when triggered to keep mouse tracking working
*/
targets.show.bind('mousemove'+namespace, function(event) {
MOUSE = { pageX: event.pageX, pageY: event.pageY, type: 'mousemove' };
api.cache.onTarget = TRUE;
});
// Define hoverIntent function
function hoverIntent(event) {
function render() {
// Cache mouse coords,render and render the tooltip
api.render(typeof event === 'object' || options.show.ready);
// Unbind show and hide events
targets.show.add(targets.hide).unbind(namespace);
}
// Only continue if tooltip isn't disabled
if(api.cache.disabled) { return FALSE; }
// Cache the event data
api.cache.event = $.extend({}, event);
api.cache.target = event ? $(event.target) : [undefined];
// Start the event sequence
if(options.show.delay > 0) {
clearTimeout(api.timers.show);
api.timers.show = setTimeout(render, options.show.delay);
if(events.show !== events.hide) {
targets.hide.bind(events.hide, function() { clearTimeout(api.timers.show); });
}
}
else { render(); }
}
// Bind show events to target
targets.show.bind(events.show, hoverIntent);
// Prerendering is enabled, create tooltip now
if(options.show.ready || options.prerender) { hoverIntent(event); }
});
};
// Setup base plugins
PLUGINS = QTIP.plugins = {
// Corner object parser
Corner: function(corner) {
corner = ('' + corner).replace(/([A-Z])/, ' $1').replace(/middle/gi, 'center').toLowerCase();
this.x = (corner.match(/left|right/i) || corner.match(/center/) || ['inherit'])[0].toLowerCase();
this.y = (corner.match(/top|bottom|center/i) || ['inherit'])[0].toLowerCase();
var f = corner.charAt(0); this.precedance = (f === 't' || f === 'b' ? 'y' : 'x');
this.string = function() { return this.precedance === 'y' ? this.y+this.x : this.x+this.y; };
this.abbrev = function() {
var x = this.x.substr(0,1), y = this.y.substr(0,1);
return x === y ? x : (x === 'c' || (x !== 'c' && y !== 'c')) ? y + x : x + y;
};
this.clone = function() {
return { x: this.x, y: this.y, precedance: this.precedance, string: this.string, abbrev: this.abbrev, clone: this.clone };
};
},
// Custom (more correct for qTip!) offset calculator
offset: function(elem, container) {
var pos = elem.offset(),
docBody = elem.closest('body')[0],
parent = container, scrolled,
coffset, overflow;
function scroll(e, i) {
pos.left += i * e.scrollLeft();
pos.top += i * e.scrollTop();
}
if(parent) {
// Compensate for non-static containers offset
do {
if(parent.css('position') !== 'static') {
coffset = parent.position();
// Account for element positioning, borders and margins
pos.left -= coffset.left + (parseInt(parent.css('borderLeftWidth'), 10) || 0) + (parseInt(parent.css('marginLeft'), 10) || 0);
pos.top -= coffset.top + (parseInt(parent.css('borderTopWidth'), 10) || 0) + (parseInt(parent.css('marginTop'), 10) || 0);
// If this is the first parent element with an overflow of "scroll" or "auto", store it
if(!scrolled && (overflow = parent.css('overflow')) !== 'hidden' && overflow !== 'visible') { scrolled = parent; }
}
}
while((parent = $(parent[0].offsetParent)).length);
// Compensate for containers scroll if it also has an offsetParent
if(scrolled && scrolled[0] !== docBody) { scroll( scrolled, 1 ); }
}
return pos;
},
/*
* iOS 3.2 - 4.0 scroll fix detection used in offset() function.
*/
iOS: parseFloat(
('' + (/CPU.*OS ([0-9_]{1,3})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0,''])[1])
.replace('undefined', '3_2').replace('_','.')
) || FALSE,
/*
* jQuery-specific $.fn overrides
*/
fn: {
/* Allow other plugins to successfully retrieve the title of an element with a qTip applied */
attr: function(attr, val) {
if(this.length) {
var self = this[0],
title = 'title',
api = $.data(self, 'qtip');
if(attr === title && api && 'object' === typeof api && api.options.suppress) {
if(arguments.length < 2) {
return $.attr(self, oldtitle);
}
else {
// If qTip is rendered and title was originally used as content, update it
if(api && api.options.content.attr === title && api.cache.attr) {
api.set('content.text', val);
}
// Use the regular attr method to set, then cache the result
return this.attr(oldtitle, val);
}
}
}
return $.fn['attr'+replaceSuffix].apply(this, arguments);
},
/* Allow clone to correctly retrieve cached title attributes */
clone: function(keepData) {
var titles = $([]), title = 'title',
// Clone our element using the real clone method
elems = $.fn['clone'+replaceSuffix].apply(this, arguments);
// Grab all elements with an oldtitle set, and change it to regular title attribute, if keepData is false
if(!keepData) {
elems.filter('['+oldtitle+']').attr('title', function() {
return $.attr(this, oldtitle);
})
.removeAttr(oldtitle);
}
return elems;
}
}
};
// Apply the fn overrides above
$.each(PLUGINS.fn, function(name, func) {
if(!func || $.fn[name+replaceSuffix]) { return TRUE; }
var old = $.fn[name+replaceSuffix] = $.fn[name];
$.fn[name] = function() {
return func.apply(this, arguments) || old.apply(this, arguments);
};
});
/* Fire off 'removeqtip' handler in $.cleanData if jQuery UI not present (it already does similar).
* This snippet is taken directly from jQuery UI source code found here:
* http://code.jquery.com/ui/jquery-ui-git.js
*/
if(!$.ui) {
$['cleanData'+replaceSuffix] = $.cleanData;
$.cleanData = function( elems ) {
for(var i = 0, elem; (elem = elems[i]) !== undefined; i++) {
try { $( elem ).triggerHandler('removeqtip'); }
catch( e ) {}
}
$['cleanData'+replaceSuffix]( elems );
};
}
// Set global qTip properties
QTIP.version = 'nightly';
QTIP.nextid = 0;
QTIP.inactiveEvents = 'click dblclick mousedown mouseup mousemove mouseleave mouseenter'.split(' ');
QTIP.zindex = 15000;
// Define configuration defaults
QTIP.defaults = {
prerender: FALSE,
id: FALSE,
overwrite: TRUE,
suppress: TRUE,
content: {
text: TRUE,
attr: 'title',
title: {
text: FALSE,
button: FALSE
}
},
position: {
my: 'top left',
at: 'bottom right',
target: FALSE,
container: FALSE,
viewport: FALSE,
adjust: {
x: 0, y: 0,
mouse: TRUE,
resize: TRUE,
method: 'flip flip'
},
effect: function(api, pos, viewport) {
$(this).animate(pos, {
duration: 200,
queue: FALSE
});
}
},
show: {
target: FALSE,
event: 'mouseenter',
effect: TRUE,
delay: 90,
solo: FALSE,
ready: FALSE,
autofocus: FALSE
},
hide: {
target: FALSE,
event: 'mouseleave',
effect: TRUE,
delay: 0,
fixed: FALSE,
inactive: FALSE,
leave: 'window',
distance: FALSE
},
style: {
classes: '',
widget: FALSE,
width: FALSE,
height: FALSE,
def: TRUE
},
events: {
render: NULL,
move: NULL,
show: NULL,
hide: NULL,
toggle: NULL,
visible: NULL,
hidden: NULL,
focus: NULL,
blur: NULL
}
};
// Tip coordinates calculator
function calculateTip(corner, width, height)
{
var width2 = Math.ceil(width / 2), height2 = Math.ceil(height / 2),
// Define tip coordinates in terms of height and width values
tips = {
bottomright: [[0,0], [width,height], [width,0]],
bottomleft: [[0,0], [width,0], [0,height]],
topright: [[0,height], [width,0], [width,height]],
topleft: [[0,0], [0,height], [width,height]],
topcenter: [[0,height], [width2,0], [width,height]],
bottomcenter: [[0,0], [width,0], [width2,height]],
rightcenter: [[0,0], [width,height2], [0,height]],
leftcenter: [[width,0], [width,height], [0,height2]]
};
// Set common side shapes
tips.lefttop = tips.bottomright; tips.righttop = tips.bottomleft;
tips.leftbottom = tips.topright; tips.rightbottom = tips.topleft;
return tips[ corner.string() ];
}
function Tip(qTip, command)
{
var self = this,
opts = qTip.options.style.tip,
elems = qTip.elements,
tooltip = elems.tooltip,
cache = { top: 0, left: 0 },
size = {
width: opts.width,
height: opts.height
},
color = { },
border = opts.border || 0,
namespace = '.qtip-tip',
hasCanvas = !!($('')[0] || {}).getContext && !(window.external && window.external.IsInnovasysDesigner);
self.corner = NULL;
self.mimic = NULL;
self.border = border;
self.offset = opts.offset;
self.size = size;
// Add new option checks for the plugin
qTip.checks.tip = {
'^position.my|style.tip.(corner|mimic|border)$': function() {
// Make sure a tip can be drawn
if(!self.init()) {
self.destroy();
}
// Reposition the tooltip
qTip.reposition();
},
'^style.tip.(height|width)$': function() {
// Re-set dimensions and redraw the tip
size = {
width: opts.width,
height: opts.height
};
self.create();
self.update();
// Reposition the tooltip
qTip.reposition();
},
'^content.title.text|style.(classes|widget)$': function() {
if(elems.tip) {
self.update();
}
}
};
function reposition(event, api, pos, viewport) {
if(!elems.tip) { return; }
var newCorner = self.corner.clone(),
adjust = pos.adjusted,
method = qTip.options.position.adjust.method.split(' '),
horizontal = method[0],
vertical = method[1] || method[0],
shift = { left: FALSE, top: FALSE, x: 0, y: 0 },
offset, css = {}, props;
// Make sure our tip position isn't fixed e.g. doesn't adjust with viewport
if(self.corner.fixed !== TRUE) {
// Horizontal - Shift or flip method
if(horizontal === 'shift' && newCorner.precedance === 'x' && adjust.left && newCorner.y !== 'center') {
newCorner.precedance = newCorner.precedance === 'x' ? 'y' : 'x';
}
else if(horizontal === 'flip' && adjust.left){
newCorner.x = newCorner.x === 'center' ? (adjust.left > 0 ? 'left' : 'right') : (newCorner.x === 'left' ? 'right' : 'left');
}
// Vertical - Shift or flip method
if(vertical === 'shift' && newCorner.precedance === 'y' && adjust.top && newCorner.x !== 'center') {
newCorner.precedance = newCorner.precedance === 'y' ? 'x' : 'y';
}
else if(vertical === 'flip' && adjust.top) {
newCorner.y = newCorner.y === 'center' ? (adjust.top > 0 ? 'top' : 'bottom') : (newCorner.y === 'top' ? 'bottom' : 'top');
}
// Update and redraw the tip if needed (check cached details of last drawn tip)
if(newCorner.string() !== cache.corner.string() && (cache.top !== adjust.top || cache.left !== adjust.left)) {
self.update(newCorner, FALSE);
}
}
// Setup tip offset properties
offset = self.position(newCorner, adjust);
if(offset.right !== undefined) { offset.left = -offset.right; }
if(offset.bottom !== undefined) { offset.top = -offset.bottom; }
offset.user = Math.max(0, opts.offset);
// Viewport "shift" specific adjustments
if(shift.left = (horizontal === 'shift' && !!adjust.left)) {
if(newCorner.x === 'center') {
css['margin-left'] = shift.x = offset['margin-left'] - adjust.left;
}
else {
props = offset.right !== undefined ?
[ adjust.left, -offset.left ] : [ -adjust.left, offset.left ];
if( (shift.x = Math.max(props[0], props[1])) > props[0] ) {
pos.left -= adjust.left;
shift.left = FALSE;
}
css[ offset.right !== undefined ? 'right' : 'left' ] = shift.x;
}
}
if(shift.top = (vertical === 'shift' && !!adjust.top)) {
if(newCorner.y === 'center') {
css['margin-top'] = shift.y = offset['margin-top'] - adjust.top;
}
else {
props = offset.bottom !== undefined ?
[ adjust.top, -offset.top ] : [ -adjust.top, offset.top ];
if( (shift.y = Math.max(props[0], props[1])) > props[0] ) {
pos.top -= adjust.top;
shift.top = FALSE;
}
css[ offset.bottom !== undefined ? 'bottom' : 'top' ] = shift.y;
}
}
/*
* If the tip is adjusted in both dimensions, or in a
* direction that would cause it to be anywhere but the
* outer border, hide it!
*/
elems.tip.css(css).toggle(
!((shift.x && shift.y) || (newCorner.x === 'center' && shift.y) || (newCorner.y === 'center' && shift.x))
);
// Adjust position to accomodate tip dimensions
pos.left -= offset.left.charAt ? offset.user : horizontal !== 'shift' || shift.top || !shift.left && !shift.top ? offset.left : 0;
pos.top -= offset.top.charAt ? offset.user : vertical !== 'shift' || shift.left || !shift.left && !shift.top ? offset.top : 0;
// Cache details
cache.left = adjust.left; cache.top = adjust.top;
cache.corner = newCorner.clone();
}
/* border width calculator */
function borderWidth(corner, side, backup) {
side = !side ? corner[corner.precedance] : side;
var isFluid = tooltip.hasClass(fluidClass),
isTitleTop = elems.titlebar && corner.y === 'top',
elem = isTitleTop ? elems.titlebar : elems.content,
css = 'border-' + side + '-width',
val;
// Grab the border-width value (add fluid class if needed)
tooltip.addClass(fluidClass);
val = parseInt(elem.css(css), 10);
val = (backup ? val || parseInt(tooltip.css(css), 10) : val) || 0;
tooltip.toggleClass(fluidClass, isFluid);
return val;
}
function borderRadius(corner) {
var isTitleTop = elems.titlebar && corner.y === 'top',
elem = isTitleTop ? elems.titlebar : elems.content,
moz = $.browser.mozilla,
prefix = moz ? '-moz-' : $.browser.webkit ? '-webkit-' : '',
side = corner.y + (moz ? '' : '-') + corner.x,
css = prefix + (moz ? 'border-radius-' + side : 'border-' + side + '-radius');
return parseInt(elem.css(css), 10) || parseInt(tooltip.css(css), 10) || 0;
}
function calculateSize(corner) {
var y = corner.precedance === 'y',
width = size [ y ? 'width' : 'height' ],
height = size [ y ? 'height' : 'width' ],
isCenter = corner.string().indexOf('center') > -1,
base = width * (isCenter ? 0.5 : 1),
pow = Math.pow,
round = Math.round,
bigHyp, ratio, result,
smallHyp = Math.sqrt( pow(base, 2) + pow(height, 2) ),
hyp = [
(border / base) * smallHyp, (border / height) * smallHyp
];
hyp[2] = Math.sqrt( pow(hyp[0], 2) - pow(border, 2) );
hyp[3] = Math.sqrt( pow(hyp[1], 2) - pow(border, 2) );
bigHyp = smallHyp + hyp[2] + hyp[3] + (isCenter ? 0 : hyp[0]);
ratio = bigHyp / smallHyp;
result = [ round(ratio * height), round(ratio * width) ];
return { height: result[ y ? 0 : 1 ], width: result[ y ? 1 : 0 ] };
}
$.extend(self, {
init: function()
{
var enabled = self.detectCorner() && (hasCanvas || $.browser.msie);
// Determine tip corner and type
if(enabled) {
// Create a new tip and draw it
self.create();
self.update();
// Bind update events
tooltip.unbind(namespace).bind('tooltipmove'+namespace, reposition);
}
return enabled;
},
detectCorner: function()
{
var corner = opts.corner,
posOptions = qTip.options.position,
at = posOptions.at,
my = posOptions.my.string ? posOptions.my.string() : posOptions.my;
// Detect corner and mimic properties
if(corner === FALSE || (my === FALSE && at === FALSE)) {
return FALSE;
}
else {
if(corner === TRUE) {
self.corner = new PLUGINS.Corner(my);
}
else if(!corner.string) {
self.corner = new PLUGINS.Corner(corner);
self.corner.fixed = TRUE;
}
}
// Cache it
cache.corner = new PLUGINS.Corner( self.corner.string() );
return self.corner.string() !== 'centercenter';
},
detectColours: function(actual) {
var i, fill, border,
tip = elems.tip.css('cssText', ''),
corner = actual || self.corner,
precedance = corner[ corner.precedance ],
borderSide = 'border-' + precedance + '-color',
borderSideCamel = 'border' + precedance.charAt(0) + precedance.substr(1) + 'Color',
invalid = /rgba?\(0, 0, 0(, 0)?\)|transparent|#123456/i,
backgroundColor = 'background-color',
transparent = 'transparent',
important = ' !important',
bodyBorder = $(document.body).css('color'),
contentColour = qTip.elements.content.css('color'),
useTitle = elems.titlebar && (corner.y === 'top' || (corner.y === 'center' && tip.position().top + (size.height / 2) + opts.offset < elems.titlebar.outerHeight(1))),
colorElem = useTitle ? elems.titlebar : elems.content;
// Apply the fluid class so we can see our CSS values properly
tooltip.addClass(fluidClass);
// Detect tip colours from CSS styles
color.fill = fill = tip.css(backgroundColor);
color.border = border = tip[0].style[ borderSideCamel ] || tip.css(borderSide) || tooltip.css(borderSide);
// Make sure colours are valid
if(!fill || invalid.test(fill)) {
color.fill = colorElem.css(backgroundColor) || transparent;
if(invalid.test(color.fill)) {
color.fill = tooltip.css(backgroundColor) || fill;
}
}
if(!border || invalid.test(border) || border === bodyBorder) {
color.border = colorElem.css(borderSide) || transparent;
if(invalid.test(color.border)) {
color.border = border;
}
}
// Reset background and border colours
$('*', tip).add(tip).css('cssText', backgroundColor+':'+transparent+important+';border:0'+important+';');
// Remove fluid class
tooltip.removeClass(fluidClass);
},
create: function()
{
var width = size.width,
height = size.height,
vml;
// Remove previous tip element if present
if(elems.tip) { elems.tip.remove(); }
// Create tip element and prepend to the tooltip
elems.tip = $('', { 'class': 'ui-tooltip-tip' }).css({ width: width, height: height }).prependTo(tooltip);
// Create tip drawing element(s)
if(hasCanvas) {
// save() as soon as we create the canvas element so FF2 doesn't bork on our first restore()!
$('').appendTo(elems.tip)[0].getContext('2d').save();
}
else {
vml = '';
elems.tip.html(vml + vml);
// Prevent mousing down on the tip since it causes problems with .live() handling in IE due to VML
$('*', elems.tip).bind('click mousedown', function(event) { event.stopPropagation(); });
}
},
update: function(corner, position)
{
var tip = elems.tip,
inner = tip.children(),
width = size.width,
height = size.height,
regular = 'px solid ',
transparent = 'px dashed transparent', // Dashed IE6 border-transparency hack. Awesome!
mimic = opts.mimic,
round = Math.round,
precedance, context, coords, translate, newSize;
// Re-determine tip if not already set
if(!corner) { corner = cache.corner || self.corner; }
// Use corner property if we detect an invalid mimic value
if(mimic === FALSE) { mimic = corner; }
// Otherwise inherit mimic properties from the corner object as necessary
else {
mimic = new PLUGINS.Corner(mimic);
mimic.precedance = corner.precedance;
if(mimic.x === 'inherit') { mimic.x = corner.x; }
else if(mimic.y === 'inherit') { mimic.y = corner.y; }
else if(mimic.x === mimic.y) {
mimic[ corner.precedance ] = corner[ corner.precedance ];
}
}
precedance = mimic.precedance;
// Update our colours
self.detectColours(corner);
// Detect border width, taking into account colours
if(color.border !== 'transparent' && color.border !== '#123456') {
// Grab border width
border = borderWidth(corner, NULL, TRUE);
// If border width isn't zero, use border color as fill (1.0 style tips)
if(opts.border === 0 && border > 0) { color.fill = color.border; }
// Set border width (use detected border width if opts.border is true)
self.border = border = opts.border !== TRUE ? opts.border : border;
}
// Border colour was invalid, set border to zero
else { self.border = border = 0; }
// Calculate coordinates
coords = calculateTip(mimic, width , height);
// Determine tip size
self.size = newSize = calculateSize(corner);
tip.css(newSize);
// Calculate tip translation
if(corner.precedance === 'y') {
translate = [
round(mimic.x === 'left' ? border : mimic.x === 'right' ? newSize.width - width - border : (newSize.width - width) / 2),
round(mimic.y === 'top' ? newSize.height - height : 0)
];
}
else {
translate = [
round(mimic.x === 'left' ? newSize.width - width : 0),
round(mimic.y === 'top' ? border : mimic.y === 'bottom' ? newSize.height - height - border : (newSize.height - height) / 2)
];
}
// Canvas drawing implementation
if(hasCanvas) {
// Set the canvas size using calculated size
inner.attr(newSize);
// Grab canvas context and clear/save it
context = inner[0].getContext('2d');
context.restore(); context.save();
context.clearRect(0,0,3000,3000);
// Translate origin
context.translate(translate[0], translate[1]);
// Draw the tip
context.beginPath();
context.moveTo(coords[0][0], coords[0][1]);
context.lineTo(coords[1][0], coords[1][1]);
context.lineTo(coords[2][0], coords[2][1]);
context.closePath();
context.fillStyle = color.fill;
context.strokeStyle = color.border;
context.lineWidth = border * 2;
context.lineJoin = 'miter';
context.miterLimit = 100;
if(border) { context.stroke(); }
context.fill();
}
// VML (IE Proprietary implementation)
else {
// Setup coordinates string
coords = 'm' + coords[0][0] + ',' + coords[0][1] + ' l' + coords[1][0] +
',' + coords[1][1] + ' ' + coords[2][0] + ',' + coords[2][1] + ' xe';
// Setup VML-specific offset for pixel-perfection
translate[2] = border && /^(r|b)/i.test(corner.string()) ?
parseFloat($.browser.version, 10) === 8 ? 2 : 1 : 0;
// Set initial CSS
inner.css({
antialias: ''+(mimic.string().indexOf('center') > -1),
left: translate[0] - (translate[2] * Number(precedance === 'x')),
top: translate[1] - (translate[2] * Number(precedance === 'y')),
width: width + border,
height: height + border
})
.each(function(i) {
var $this = $(this);
// Set shape specific attributes
$this[ $this.prop ? 'prop' : 'attr' ]({
coordsize: (width+border) + ' ' + (height+border),
path: coords,
fillcolor: color.fill,
filled: !!i,
stroked: !!!i
})
.css({ display: border || i ? 'block' : 'none' });
// Check if border is enabled and add stroke element
if(!i && $this.html() === '') {
$this.html(
''
);
}
});
}
// Position if needed
if(position !== FALSE) { self.position(corner); }
},
// Tip positioning method
position: function(corner)
{
var tip = elems.tip,
position = {},
userOffset = Math.max(0, opts.offset),
precedance, dimensions, corners;
// Return if tips are disabled or tip is not yet rendered
if(opts.corner === FALSE || !tip) { return FALSE; }
// Inherit corner if not provided
corner = corner || self.corner;
precedance = corner.precedance;
// Determine which tip dimension to use for adjustment
dimensions = calculateSize(corner);
// Setup corners and offset array
corners = [ corner.x, corner.y ];
if(precedance === 'x') { corners.reverse(); }
// Calculate tip position
$.each(corners, function(i, side) {
var b, br;
if(side === 'center') {
b = precedance === 'y' ? 'left' : 'top';
position[ b ] = '50%';
position['margin-' + b] = -Math.round(dimensions[ precedance === 'y' ? 'width' : 'height' ] / 2) + userOffset;
}
else {
b = borderWidth(corner, side, TRUE);
br = borderRadius(corner);
position[ side ] = i ?
border ? borderWidth(corner, side) : 0 :
userOffset + (br > b ? br : 0);
}
});
// Adjust for tip dimensions
position[ corner[precedance] ] -= dimensions[ precedance === 'x' ? 'width' : 'height' ];
// Set and return new position
tip.css({ top: '', bottom: '', left: '', right: '', margin: '' }).css(position);
return position;
},
destroy: function()
{
// Remov tip and bound events
if(elems.tip) { elems.tip.remove(); }
tooltip.unbind(namespace);
}
});
self.init();
}
PLUGINS.tip = function(api)
{
var self = api.plugins.tip;
return 'object' === typeof self ? self : (api.plugins.tip = new Tip(api));
};
// Initialize tip on render
PLUGINS.tip.initialize = 'render';
// Setup plugin sanitization options
PLUGINS.tip.sanitize = function(options)
{
var style = options.style, opts;
if(style && 'tip' in style) {
opts = options.style.tip;
if(typeof opts !== 'object'){ options.style.tip = { corner: opts }; }
if(!(/string|boolean/i).test(typeof opts.corner)) { opts.corner = TRUE; }
if(typeof opts.width !== 'number'){ delete opts.width; }
if(typeof opts.height !== 'number'){ delete opts.height; }
if(typeof opts.border !== 'number' && opts.border !== TRUE){ delete opts.border; }
if(typeof opts.offset !== 'number'){ delete opts.offset; }
}
};
// Extend original qTip defaults
$.extend(TRUE, QTIP.defaults, {
style: {
tip: {
corner: TRUE,
mimic: FALSE,
width: 6,
height: 6,
border: TRUE,
offset: 0
}
}
});
}));
/*!
* ZeroClipboard
* The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface.
* Copyright (c) 2014 Jon Rohan, James M. Greene
* Licensed MIT
* http://zeroclipboard.org/
* v1.3.5
*/
(function (window) {
"use strict";
var currentElement;
var flashState = {
bridge: null,
version: "0.0.0",
disabled: null,
outdated: null,
ready: null
};
var _clipData = {};
var clientIdCounter = 0;
var _clientMeta = {};
var elementIdCounter = 0;
var _elementMeta = {};
var _amdModuleId = null;
var _cjsModuleId = null;
var _swfPath = function () {
var i, jsDir, tmpJsPath, jsPath, swfPath = "ZeroClipboard.swf";
if (document.currentScript && (jsPath = document.currentScript.src)) { } else {
var scripts = document.getElementsByTagName("script");
if ("readyState" in scripts[0]) {
for (i = scripts.length; i--;) {
if (scripts[i].readyState === "interactive" && (jsPath = scripts[i].src)) {
break;
}
}
} else if (document.readyState === "loading") {
jsPath = scripts[scripts.length - 1].src;
} else {
for (i = scripts.length; i--;) {
tmpJsPath = scripts[i].src;
if (!tmpJsPath) {
jsDir = null;
break;
}
tmpJsPath = tmpJsPath.split("#")[0].split("?")[0];
tmpJsPath = tmpJsPath.slice(0, tmpJsPath.lastIndexOf("/") + 1);
if (jsDir == null) {
jsDir = tmpJsPath;
} else if (jsDir !== tmpJsPath) {
jsDir = null;
break;
}
}
if (jsDir !== null) {
jsPath = jsDir;
}
}
}
if (jsPath) {
jsPath = jsPath.split("#")[0].split("?")[0];
swfPath = jsPath.slice(0, jsPath.lastIndexOf("/") + 1) + swfPath;
}
return swfPath;
}();
var _camelizeCssPropName = function () {
var matcherRegex = /\-([a-z])/g, replacerFn = function (match, group) {
return group.toUpperCase();
};
return function (prop) {
return prop.replace(matcherRegex, replacerFn);
};
}();
var _getStyle = function (el, prop) {
var value, camelProp, tagName, possiblePointers, i, len;
if (window.getComputedStyle) {
value = window.getComputedStyle(el, null).getPropertyValue(prop);
} else {
camelProp = _camelizeCssPropName(prop);
if (el.currentStyle) {
value = el.currentStyle[camelProp];
} else {
value = el.style[camelProp];
}
}
if (prop === "cursor") {
if (!value || value === "auto") {
tagName = el.tagName.toLowerCase();
if (tagName === "a") {
return "pointer";
}
}
}
return value;
};
var _elementMouseOver = function (event) {
if (!event) {
event = window.event;
}
var target;
if (this !== window) {
target = this;
} else if (event.target) {
target = event.target;
} else if (event.srcElement) {
target = event.srcElement;
}
ZeroClipboard.activate(target);
};
var _addEventHandler = function (element, method, func) {
if (!element || element.nodeType !== 1) {
return;
}
if (element.addEventListener) {
element.addEventListener(method, func, false);
} else if (element.attachEvent) {
element.attachEvent("on" + method, func);
}
};
var _removeEventHandler = function (element, method, func) {
if (!element || element.nodeType !== 1) {
return;
}
if (element.removeEventListener) {
element.removeEventListener(method, func, false);
} else if (element.detachEvent) {
element.detachEvent("on" + method, func);
}
};
var _addClass = function (element, value) {
if (!element || element.nodeType !== 1) {
return element;
}
if (element.classList) {
if (!element.classList.contains(value)) {
element.classList.add(value);
}
return element;
}
if (value && typeof value === "string") {
var classNames = (value || "").split(/\s+/);
if (element.nodeType === 1) {
if (!element.className) {
element.className = value;
} else {
var className = " " + element.className + " ", setClass = element.className;
for (var c = 0, cl = classNames.length; c < cl; c++) {
if (className.indexOf(" " + classNames[c] + " ") < 0) {
setClass += " " + classNames[c];
}
}
element.className = setClass.replace(/^\s+|\s+$/g, "");
}
}
}
return element;
};
var _removeClass = function (element, value) {
if (!element || element.nodeType !== 1) {
return element;
}
if (element.classList) {
if (element.classList.contains(value)) {
element.classList.remove(value);
}
return element;
}
if (value && typeof value === "string" || value === undefined) {
var classNames = (value || "").split(/\s+/);
if (element.nodeType === 1 && element.className) {
if (value) {
var className = (" " + element.className + " ").replace(/[\n\t]/g, " ");
for (var c = 0, cl = classNames.length; c < cl; c++) {
className = className.replace(" " + classNames[c] + " ", " ");
}
element.className = className.replace(/^\s+|\s+$/g, "");
} else {
element.className = "";
}
}
}
return element;
};
var _getZoomFactor = function () {
var rect, physicalWidth, logicalWidth, zoomFactor = 1;
if (typeof document.body.getBoundingClientRect === "function") {
rect = document.body.getBoundingClientRect();
physicalWidth = rect.right - rect.left;
logicalWidth = document.body.offsetWidth;
zoomFactor = Math.round(physicalWidth / logicalWidth * 100) / 100;
}
return zoomFactor;
};
var _getDOMObjectPosition = function (obj, defaultZIndex) {
var info = {
left: 0,
top: 0,
width: 0,
height: 0,
zIndex: _getSafeZIndex(defaultZIndex) - 1
};
if (obj.getBoundingClientRect) {
var rect = obj.getBoundingClientRect();
var pageXOffset, pageYOffset, zoomFactor;
if ("pageXOffset" in window && "pageYOffset" in window) {
pageXOffset = window.pageXOffset;
pageYOffset = window.pageYOffset;
} else {
zoomFactor = _getZoomFactor();
pageXOffset = Math.round(document.documentElement.scrollLeft / zoomFactor);
pageYOffset = Math.round(document.documentElement.scrollTop / zoomFactor);
}
var leftBorderWidth = document.documentElement.clientLeft || 0;
var topBorderWidth = document.documentElement.clientTop || 0;
info.left = rect.left + pageXOffset - leftBorderWidth;
info.top = rect.top + pageYOffset - topBorderWidth;
info.width = "width" in rect ? rect.width : rect.right - rect.left;
info.height = "height" in rect ? rect.height : rect.bottom - rect.top;
}
return info;
};
var _cacheBust = function (path, options) {
var cacheBust = options == null || options && options.cacheBust === true && options.useNoCache === true;
if (cacheBust) {
return (path.indexOf("?") === -1 ? "?" : "&") + "noCache=" + new Date().getTime();
} else {
return "";
}
};
var _vars = function (options) {
var i, len, domain, str = [], domains = [], trustedOriginsExpanded = [];
if (options.trustedOrigins) {
if (typeof options.trustedOrigins === "string") {
domains.push(options.trustedOrigins);
} else if (typeof options.trustedOrigins === "object" && "length" in options.trustedOrigins) {
domains = domains.concat(options.trustedOrigins);
}
}
if (options.trustedDomains) {
if (typeof options.trustedDomains === "string") {
domains.push(options.trustedDomains);
} else if (typeof options.trustedDomains === "object" && "length" in options.trustedDomains) {
domains = domains.concat(options.trustedDomains);
}
}
if (domains.length) {
for (i = 0, len = domains.length; i < len; i++) {
if (domains.hasOwnProperty(i) && domains[i] && typeof domains[i] === "string") {
domain = _extractDomain(domains[i]);
if (!domain) {
continue;
}
if (domain === "*") {
trustedOriginsExpanded = [domain];
break;
}
trustedOriginsExpanded.push.apply(trustedOriginsExpanded, [domain, "//" + domain, window.location.protocol + "//" + domain]);
}
}
}
if (trustedOriginsExpanded.length) {
str.push("trustedOrigins=" + encodeURIComponent(trustedOriginsExpanded.join(",")));
}
if (typeof options.jsModuleId === "string" && options.jsModuleId) {
str.push("jsModuleId=" + encodeURIComponent(options.jsModuleId));
}
return str.join("&");
};
var _inArray = function (elem, array, fromIndex) {
if (typeof array.indexOf === "function") {
return array.indexOf(elem, fromIndex);
}
var i, len = array.length;
if (typeof fromIndex === "undefined") {
fromIndex = 0;
} else if (fromIndex < 0) {
fromIndex = len + fromIndex;
}
for (i = fromIndex; i < len; i++) {
if (array.hasOwnProperty(i) && array[i] === elem) {
return i;
}
}
return -1;
};
var _prepClip = function (elements) {
if (typeof elements === "string") throw new TypeError("ZeroClipboard doesn't accept query strings.");
if (!elements.length) return [elements];
return elements;
};
var _dispatchCallback = function (func, context, args, async) {
if (async) {
window.setTimeout(function () {
func.apply(context, args);
}, 0);
} else {
func.apply(context, args);
}
};
var _getSafeZIndex = function (val) {
var zIndex, tmp;
if (val) {
if (typeof val === "number" && val > 0) {
zIndex = val;
} else if (typeof val === "string" && (tmp = parseInt(val, 10)) && !isNaN(tmp) && tmp > 0) {
zIndex = tmp;
}
}
if (!zIndex) {
if (typeof _globalConfig.zIndex === "number" && _globalConfig.zIndex > 0) {
zIndex = _globalConfig.zIndex;
} else if (typeof _globalConfig.zIndex === "string" && (tmp = parseInt(_globalConfig.zIndex, 10)) && !isNaN(tmp) && tmp > 0) {
zIndex = tmp;
}
}
return zIndex || 0;
};
var _deprecationWarning = function (deprecatedApiName, debugEnabled) {
if (deprecatedApiName && debugEnabled !== false && typeof console !== "undefined" && console && (console.warn || console.log)) {
var deprecationWarning = "`" + deprecatedApiName + "` is deprecated. See docs for more info:\n" + " https://github.com/zeroclipboard/zeroclipboard/blob/master/docs/instructions.md#deprecations";
if (console.warn) {
console.warn(deprecationWarning);
} else {
console.log(deprecationWarning);
}
}
};
var _extend = function () {
var i, len, arg, prop, src, copy, target = arguments[0] || {};
for (i = 1, len = arguments.length; i < len; i++) {
if ((arg = arguments[i]) != null) {
for (prop in arg) {
if (arg.hasOwnProperty(prop)) {
src = target[prop];
copy = arg[prop];
if (target === copy) {
continue;
}
if (copy !== undefined) {
target[prop] = copy;
}
}
}
}
}
return target;
};
var _extractDomain = function (originOrUrl) {
if (originOrUrl == null || originOrUrl === "") {
return null;
}
originOrUrl = originOrUrl.replace(/^\s+|\s+$/g, "");
if (originOrUrl === "") {
return null;
}
var protocolIndex = originOrUrl.indexOf("//");
originOrUrl = protocolIndex === -1 ? originOrUrl : originOrUrl.slice(protocolIndex + 2);
var pathIndex = originOrUrl.indexOf("/");
originOrUrl = pathIndex === -1 ? originOrUrl : protocolIndex === -1 || pathIndex === 0 ? null : originOrUrl.slice(0, pathIndex);
if (originOrUrl && originOrUrl.slice(-4).toLowerCase() === ".swf") {
return null;
}
return originOrUrl || null;
};
var _determineScriptAccess = function () {
var _extractAllDomains = function (origins, resultsArray) {
var i, len, tmp;
if (origins != null && resultsArray[0] !== "*") {
if (typeof origins === "string") {
origins = [origins];
}
if (typeof origins === "object" && "length" in origins) {
for (i = 0, len = origins.length; i < len; i++) {
if (origins.hasOwnProperty(i)) {
tmp = _extractDomain(origins[i]);
if (tmp) {
if (tmp === "*") {
resultsArray.length = 0;
resultsArray.push("*");
break;
}
if (_inArray(tmp, resultsArray) === -1) {
resultsArray.push(tmp);
}
}
}
}
}
}
};
var _accessLevelLookup = {
always: "always",
samedomain: "sameDomain",
never: "never"
};
return function (currentDomain, configOptions) {
var asaLower, allowScriptAccess = configOptions.allowScriptAccess;
if (typeof allowScriptAccess === "string" && (asaLower = allowScriptAccess.toLowerCase()) && /^always|samedomain|never$/.test(asaLower)) {
return _accessLevelLookup[asaLower];
}
var swfDomain = _extractDomain(configOptions.moviePath);
if (swfDomain === null) {
swfDomain = currentDomain;
}
var trustedDomains = [];
_extractAllDomains(configOptions.trustedOrigins, trustedDomains);
_extractAllDomains(configOptions.trustedDomains, trustedDomains);
var len = trustedDomains.length;
if (len > 0) {
if (len === 1 && trustedDomains[0] === "*") {
return "always";
}
if (_inArray(currentDomain, trustedDomains) !== -1) {
if (len === 1 && currentDomain === swfDomain) {
return "sameDomain";
}
return "always";
}
}
return "never";
};
}();
var _objectKeys = function (obj) {
if (obj == null) {
return [];
}
if (Object.keys) {
return Object.keys(obj);
}
var keys = [];
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
keys.push(prop);
}
}
return keys;
};
var _deleteOwnProperties = function (obj) {
if (obj) {
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
delete obj[prop];
}
}
}
return obj;
};
var _safeActiveElement = function () {
try {
return document.activeElement;
} catch (err) { }
return null;
};
var _detectFlashSupport = function () {
var hasFlash = false;
if (typeof flashState.disabled === "boolean") {
hasFlash = flashState.disabled === false;
} else {
if (typeof ActiveXObject === "function") {
try {
if (new ActiveXObject("ShockwaveFlash.ShockwaveFlash")) {
hasFlash = true;
}
} catch (error) { }
}
if (!hasFlash && navigator.mimeTypes["application/x-shockwave-flash"]) {
hasFlash = true;
}
}
return hasFlash;
};
function _parseFlashVersion(flashVersion) {
return flashVersion.replace(/,/g, ".").replace(/[^0-9\.]/g, "");
}
function _isFlashVersionSupported(flashVersion) {
return parseFloat(_parseFlashVersion(flashVersion)) >= 10;
}
var ZeroClipboard = function (elements, options) {
if (!(this instanceof ZeroClipboard)) {
return new ZeroClipboard(elements, options);
}
this.id = "" + clientIdCounter++;
_clientMeta[this.id] = {
instance: this,
elements: [],
handlers: {}
};
if (elements) {
this.clip(elements);
}
if (typeof options !== "undefined") {
_deprecationWarning("new ZeroClipboard(elements, options)", _globalConfig.debug);
ZeroClipboard.config(options);
}
this.options = ZeroClipboard.config();
if (typeof flashState.disabled !== "boolean") {
flashState.disabled = !_detectFlashSupport();
}
if (flashState.disabled === false && flashState.outdated !== true) {
if (flashState.bridge === null) {
flashState.outdated = false;
flashState.ready = false;
_bridge();
}
}
};
ZeroClipboard.prototype.setText = function (newText) {
if (newText && newText !== "") {
_clipData["text/plain"] = newText;
if (flashState.ready === true && flashState.bridge && typeof flashState.bridge.setText === "function") {
flashState.bridge.setText(newText);
} else {
flashState.ready = false;
}
}
return this;
};
ZeroClipboard.prototype.setSize = function (width, height) {
if (flashState.ready === true && flashState.bridge && typeof flashState.bridge.setSize === "function") {
flashState.bridge.setSize(width, height);
} else {
flashState.ready = false;
}
return this;
};
var _setHandCursor = function (enabled) {
if (flashState.ready === true && flashState.bridge && typeof flashState.bridge.setHandCursor === "function") {
flashState.bridge.setHandCursor(enabled);
} else {
flashState.ready = false;
}
};
ZeroClipboard.prototype.destroy = function () {
this.unclip();
this.off();
delete _clientMeta[this.id];
};
var _getAllClients = function () {
var i, len, client, clients = [], clientIds = _objectKeys(_clientMeta);
for (i = 0, len = clientIds.length; i < len; i++) {
client = _clientMeta[clientIds[i]].instance;
if (client && client instanceof ZeroClipboard) {
clients.push(client);
}
}
return clients;
};
ZeroClipboard.version = "1.3.5";
var _globalConfig = {
swfPath: _swfPath,
trustedDomains: window.location.host ? [window.location.host] : [],
cacheBust: true,
forceHandCursor: false,
zIndex: 999999999,
debug: true,
title: null,
autoActivate: true
};
ZeroClipboard.config = function (options) {
if (typeof options === "object" && options !== null) {
_extend(_globalConfig, options);
}
if (typeof options === "string" && options) {
if (_globalConfig.hasOwnProperty(options)) {
return _globalConfig[options];
}
return;
}
var copy = {};
for (var prop in _globalConfig) {
if (_globalConfig.hasOwnProperty(prop)) {
if (typeof _globalConfig[prop] === "object" && _globalConfig[prop] !== null) {
if ("length" in _globalConfig[prop]) {
copy[prop] = _globalConfig[prop].slice(0);
} else {
copy[prop] = _extend({}, _globalConfig[prop]);
}
} else {
copy[prop] = _globalConfig[prop];
}
}
}
return copy;
};
ZeroClipboard.destroy = function () {
ZeroClipboard.deactivate();
for (var clientId in _clientMeta) {
if (_clientMeta.hasOwnProperty(clientId) && _clientMeta[clientId]) {
var client = _clientMeta[clientId].instance;
if (client && typeof client.destroy === "function") {
client.destroy();
}
}
}
var htmlBridge = _getHtmlBridge(flashState.bridge);
if (htmlBridge && htmlBridge.parentNode) {
htmlBridge.parentNode.removeChild(htmlBridge);
flashState.ready = null;
flashState.bridge = null;
}
};
ZeroClipboard.activate = function (element) {
if (currentElement) {
_removeClass(currentElement, _globalConfig.hoverClass);
_removeClass(currentElement, _globalConfig.activeClass);
}
currentElement = element;
_addClass(element, _globalConfig.hoverClass);
_reposition();
var newTitle = _globalConfig.title || element.getAttribute("title");
if (newTitle) {
var htmlBridge = _getHtmlBridge(flashState.bridge);
if (htmlBridge) {
htmlBridge.setAttribute("title", newTitle);
}
}
var useHandCursor = _globalConfig.forceHandCursor === true || _getStyle(element, "cursor") === "pointer";
_setHandCursor(useHandCursor);
};
ZeroClipboard.deactivate = function () {
var htmlBridge = _getHtmlBridge(flashState.bridge);
if (htmlBridge) {
htmlBridge.style.left = "0px";
htmlBridge.style.top = "-9999px";
htmlBridge.removeAttribute("title");
}
if (currentElement) {
_removeClass(currentElement, _globalConfig.hoverClass);
_removeClass(currentElement, _globalConfig.activeClass);
currentElement = null;
}
};
var _bridge = function () {
var flashBridge, len;
var container = document.getElementById("global-zeroclipboard-html-bridge");
if (!container) {
var opts = ZeroClipboard.config();
opts.jsModuleId = typeof _amdModuleId === "string" && _amdModuleId || typeof _cjsModuleId === "string" && _cjsModuleId || null;
var allowScriptAccess = _determineScriptAccess(window.location.host, _globalConfig);
var flashvars = _vars(opts);
var swfUrl = _globalConfig.moviePath + _cacheBust(_globalConfig.moviePath, _globalConfig);
var html = ' ';
container = document.createElement("div");
container.id = "global-zeroclipboard-html-bridge";
container.setAttribute("class", "global-zeroclipboard-container");
container.style.position = "absolute";
container.style.left = "0px";
container.style.top = "-9999px";
container.style.width = "15px";
container.style.height = "15px";
container.style.zIndex = "" + _getSafeZIndex(_globalConfig.zIndex);
document.body.appendChild(container);
container.innerHTML = html;
}
flashBridge = document["global-zeroclipboard-flash-bridge"];
if (flashBridge && (len = flashBridge.length)) {
flashBridge = flashBridge[len - 1];
}
flashState.bridge = flashBridge || container.children[0].lastElementChild;
};
var _getHtmlBridge = function (flashBridge) {
var isFlashElement = /^OBJECT|EMBED$/;
var htmlBridge = flashBridge && flashBridge.parentNode;
while (htmlBridge && isFlashElement.test(htmlBridge.nodeName) && htmlBridge.parentNode) {
htmlBridge = htmlBridge.parentNode;
}
return htmlBridge || null;
};
var _reposition = function () {
if (currentElement) {
var pos = _getDOMObjectPosition(currentElement, _globalConfig.zIndex);
var htmlBridge = _getHtmlBridge(flashState.bridge);
if (htmlBridge) {
htmlBridge.style.top = pos.top + "px";
htmlBridge.style.left = pos.left + "px";
htmlBridge.style.width = pos.width + "px";
htmlBridge.style.height = pos.height + "px";
htmlBridge.style.zIndex = pos.zIndex + 1;
}
if (flashState.ready === true && flashState.bridge && typeof flashState.bridge.setSize === "function") {
flashState.bridge.setSize(pos.width, pos.height);
} else {
flashState.ready = false;
}
}
return this;
};
ZeroClipboard.prototype.on = function (eventName, func) {
var i, len, events, added = {}, handlers = _clientMeta[this.id] && _clientMeta[this.id].handlers;
if (typeof eventName === "string" && eventName) {
events = eventName.toLowerCase().split(/\s+/);
} else if (typeof eventName === "object" && eventName && typeof func === "undefined") {
for (i in eventName) {
if (eventName.hasOwnProperty(i) && typeof i === "string" && i && typeof eventName[i] === "function") {
this.on(i, eventName[i]);
}
}
}
if (events && events.length) {
for (i = 0, len = events.length; i < len; i++) {
eventName = events[i].replace(/^on/, "");
added[eventName] = true;
if (!handlers[eventName]) {
handlers[eventName] = [];
}
handlers[eventName].push(func);
}
if (added.noflash && flashState.disabled) {
_receiveEvent.call(this, "noflash", {});
}
if (added.wrongflash && flashState.outdated) {
_receiveEvent.call(this, "wrongflash", {
flashVersion: flashState.version
});
}
if (added.load && flashState.ready) {
_receiveEvent.call(this, "load", {
flashVersion: flashState.version
});
}
}
return this;
};
ZeroClipboard.prototype.off = function (eventName, func) {
var i, len, foundIndex, events, perEventHandlers, handlers = _clientMeta[this.id] && _clientMeta[this.id].handlers;
if (arguments.length === 0) {
events = _objectKeys(handlers);
} else if (typeof eventName === "string" && eventName) {
events = eventName.split(/\s+/);
} else if (typeof eventName === "object" && eventName && typeof func === "undefined") {
for (i in eventName) {
if (eventName.hasOwnProperty(i) && typeof i === "string" && i && typeof eventName[i] === "function") {
this.off(i, eventName[i]);
}
}
}
if (events && events.length) {
for (i = 0, len = events.length; i < len; i++) {
eventName = events[i].toLowerCase().replace(/^on/, "");
perEventHandlers = handlers[eventName];
if (perEventHandlers && perEventHandlers.length) {
if (func) {
foundIndex = _inArray(func, perEventHandlers);
while (foundIndex !== -1) {
perEventHandlers.splice(foundIndex, 1);
foundIndex = _inArray(func, perEventHandlers, foundIndex);
}
} else {
handlers[eventName].length = 0;
}
}
}
}
return this;
};
ZeroClipboard.prototype.handlers = function (eventName) {
var prop, copy = null, handlers = _clientMeta[this.id] && _clientMeta[this.id].handlers;
if (handlers) {
if (typeof eventName === "string" && eventName) {
return handlers[eventName] ? handlers[eventName].slice(0) : null;
}
copy = {};
for (prop in handlers) {
if (handlers.hasOwnProperty(prop) && handlers[prop]) {
copy[prop] = handlers[prop].slice(0);
}
}
}
return copy;
};
var _dispatchClientCallbacks = function (eventName, context, args, async) {
var handlers = _clientMeta[this.id] && _clientMeta[this.id].handlers[eventName];
if (handlers && handlers.length) {
var i, len, func, originalContext = context || this;
for (i = 0, len = handlers.length; i < len; i++) {
func = handlers[i];
context = originalContext;
if (typeof func === "string" && typeof window[func] === "function") {
func = window[func];
}
if (typeof func === "object" && func && typeof func.handleEvent === "function") {
context = func;
func = func.handleEvent;
}
if (typeof func === "function") {
_dispatchCallback(func, context, args, async);
}
}
}
return this;
};
ZeroClipboard.prototype.clip = function (elements) {
elements = _prepClip(elements);
for (var i = 0; i < elements.length; i++) {
if (elements.hasOwnProperty(i) && elements[i] && elements[i].nodeType === 1) {
if (!elements[i].zcClippingId) {
elements[i].zcClippingId = "zcClippingId_" + elementIdCounter++;
_elementMeta[elements[i].zcClippingId] = [this.id];
if (_globalConfig.autoActivate === true) {
_addEventHandler(elements[i], "mouseover", _elementMouseOver);
}
} else if (_inArray(this.id, _elementMeta[elements[i].zcClippingId]) === -1) {
_elementMeta[elements[i].zcClippingId].push(this.id);
}
var clippedElements = _clientMeta[this.id].elements;
if (_inArray(elements[i], clippedElements) === -1) {
clippedElements.push(elements[i]);
}
}
}
return this;
};
ZeroClipboard.prototype.unclip = function (elements) {
var meta = _clientMeta[this.id];
if (meta) {
var clippedElements = meta.elements;
var arrayIndex;
if (typeof elements === "undefined") {
elements = clippedElements.slice(0);
} else {
elements = _prepClip(elements);
}
for (var i = elements.length; i--;) {
if (elements.hasOwnProperty(i) && elements[i] && elements[i].nodeType === 1) {
arrayIndex = 0;
while ((arrayIndex = _inArray(elements[i], clippedElements, arrayIndex)) !== -1) {
clippedElements.splice(arrayIndex, 1);
}
var clientIds = _elementMeta[elements[i].zcClippingId];
if (clientIds) {
arrayIndex = 0;
while ((arrayIndex = _inArray(this.id, clientIds, arrayIndex)) !== -1) {
clientIds.splice(arrayIndex, 1);
}
if (clientIds.length === 0) {
if (_globalConfig.autoActivate === true) {
_removeEventHandler(elements[i], "mouseover", _elementMouseOver);
}
delete elements[i].zcClippingId;
}
}
}
}
}
return this;
};
ZeroClipboard.prototype.elements = function () {
var meta = _clientMeta[this.id];
return meta && meta.elements ? meta.elements.slice(0) : [];
};
var _getAllClientsClippedToElement = function (element) {
var elementMetaId, clientIds, i, len, client, clients = [];
if (element && element.nodeType === 1 && (elementMetaId = element.zcClippingId) && _elementMeta.hasOwnProperty(elementMetaId)) {
clientIds = _elementMeta[elementMetaId];
if (clientIds && clientIds.length) {
for (i = 0, len = clientIds.length; i < len; i++) {
client = _clientMeta[clientIds[i]].instance;
if (client && client instanceof ZeroClipboard) {
clients.push(client);
}
}
}
}
return clients;
};
_globalConfig.hoverClass = "zeroclipboard-is-hover";
_globalConfig.activeClass = "zeroclipboard-is-active";
_globalConfig.trustedOrigins = null;
_globalConfig.allowScriptAccess = null;
_globalConfig.useNoCache = true;
_globalConfig.moviePath = "ZeroClipboard.swf";
ZeroClipboard.detectFlashSupport = function () {
_deprecationWarning("ZeroClipboard.detectFlashSupport", _globalConfig.debug);
return _detectFlashSupport();
};
ZeroClipboard.dispatch = function (eventName, args) {
if (typeof eventName === "string" && eventName) {
var cleanEventName = eventName.toLowerCase().replace(/^on/, "");
if (cleanEventName) {
var clients = currentElement && _globalConfig.autoActivate === true ? _getAllClientsClippedToElement(currentElement) : _getAllClients();
for (var i = 0, len = clients.length; i < len; i++) {
_receiveEvent.call(clients[i], cleanEventName, args);
}
}
}
};
ZeroClipboard.prototype.setHandCursor = function (enabled) {
_deprecationWarning("ZeroClipboard.prototype.setHandCursor", _globalConfig.debug);
enabled = typeof enabled === "boolean" ? enabled : !!enabled;
_setHandCursor(enabled);
_globalConfig.forceHandCursor = enabled;
return this;
};
ZeroClipboard.prototype.reposition = function () {
_deprecationWarning("ZeroClipboard.prototype.reposition", _globalConfig.debug);
return _reposition();
};
ZeroClipboard.prototype.receiveEvent = function (eventName, args) {
_deprecationWarning("ZeroClipboard.prototype.receiveEvent", _globalConfig.debug);
if (typeof eventName === "string" && eventName) {
var cleanEventName = eventName.toLowerCase().replace(/^on/, "");
if (cleanEventName) {
_receiveEvent.call(this, cleanEventName, args);
}
}
};
ZeroClipboard.prototype.setCurrent = function (element) {
_deprecationWarning("ZeroClipboard.prototype.setCurrent", _globalConfig.debug);
ZeroClipboard.activate(element);
return this;
};
ZeroClipboard.prototype.resetBridge = function () {
_deprecationWarning("ZeroClipboard.prototype.resetBridge", _globalConfig.debug);
ZeroClipboard.deactivate();
return this;
};
ZeroClipboard.prototype.setTitle = function (newTitle) {
_deprecationWarning("ZeroClipboard.prototype.setTitle", _globalConfig.debug);
newTitle = newTitle || _globalConfig.title || currentElement && currentElement.getAttribute("title");
if (newTitle) {
var htmlBridge = _getHtmlBridge(flashState.bridge);
if (htmlBridge) {
htmlBridge.setAttribute("title", newTitle);
}
}
return this;
};
ZeroClipboard.setDefaults = function (options) {
_deprecationWarning("ZeroClipboard.setDefaults", _globalConfig.debug);
ZeroClipboard.config(options);
};
ZeroClipboard.prototype.addEventListener = function (eventName, func) {
_deprecationWarning("ZeroClipboard.prototype.addEventListener", _globalConfig.debug);
return this.on(eventName, func);
};
ZeroClipboard.prototype.removeEventListener = function (eventName, func) {
_deprecationWarning("ZeroClipboard.prototype.removeEventListener", _globalConfig.debug);
return this.off(eventName, func);
};
ZeroClipboard.prototype.ready = function () {
_deprecationWarning("ZeroClipboard.prototype.ready", _globalConfig.debug);
return flashState.ready === true;
};
var _receiveEvent = function (eventName, args) {
eventName = eventName.toLowerCase().replace(/^on/, "");
var cleanVersion = args && args.flashVersion && _parseFlashVersion(args.flashVersion) || null;
var element = currentElement;
var performCallbackAsync = true;
switch (eventName) {
case "load":
if (cleanVersion) {
if (!_isFlashVersionSupported(cleanVersion)) {
_receiveEvent.call(this, "onWrongFlash", {
flashVersion: cleanVersion
});
return;
}
flashState.outdated = false;
flashState.ready = true;
flashState.version = cleanVersion;
}
break;
case "wrongflash":
if (cleanVersion && !_isFlashVersionSupported(cleanVersion)) {
flashState.outdated = true;
flashState.ready = false;
flashState.version = cleanVersion;
}
break;
case "mouseover":
_addClass(element, _globalConfig.hoverClass);
break;
case "mouseout":
if (_globalConfig.autoActivate === true) {
ZeroClipboard.deactivate();
}
break;
case "mousedown":
_addClass(element, _globalConfig.activeClass);
break;
case "mouseup":
_removeClass(element, _globalConfig.activeClass);
break;
case "datarequested":
if (element) {
var targetId = element.getAttribute("data-clipboard-target"), targetEl = !targetId ? null : document.getElementById(targetId);
if (targetEl) {
var textContent = targetEl.value || targetEl.textContent || targetEl.innerText;
if (textContent) {
this.setText(textContent);
}
} else {
var defaultText = element.getAttribute("data-clipboard-text");
if (defaultText) {
this.setText(defaultText);
}
}
}
performCallbackAsync = false;
break;
case "complete":
_deleteOwnProperties(_clipData);
if (element && element !== _safeActiveElement() && element.focus) {
element.focus();
}
break;
}
var context = element;
var eventArgs = [this, args];
return _dispatchClientCallbacks.call(this, eventName, context, eventArgs, performCallbackAsync);
};
if (typeof define === "function" && define.amd) {
define(["require", "exports", "module"], function (require, exports, module) {
_amdModuleId = module && module.id || null;
return ZeroClipboard;
});
} else if (typeof module === "object" && module && typeof module.exports === "object" && module.exports && typeof window.require === "function") {
_cjsModuleId = module.id || null;
module.exports = ZeroClipboard;
} else {
window.ZeroClipboard = ZeroClipboard;
}
})(function () {
return this;
}());
/*!
* JSizes - JQuery plugin v0.33
*
* Licensed under the revised BSD License.
* Copyright 2008-2010 Bram Stein
* All rights reserved.
*/
/*global jQuery*/
(function ($) {
var num = function (value) {
return parseInt(value, 10) || 0;
};
/**
* Sets or gets the values for min-width, min-height, max-width
* and max-height.
*/
$.each(['min', 'max'], function (i, name) {
$.fn[name + 'Size'] = function (value) {
var width, height;
if (value) {
if (value.width !== undefined) {
this.css(name + '-width', value.width);
}
if (value.height !== undefined) {
this.css(name + '-height', value.height);
}
return this;
}
else {
width = this.css(name + '-width');
height = this.css(name + '-height');
// Apparently:
// * Opera returns -1px instead of none
// * IE6 returns undefined instead of none
return {'width': (name === 'max' && (width === undefined || width === 'none' || num(width) === -1) && Number.MAX_VALUE) || num(width),
'height': (name === 'max' && (height === undefined || height === 'none' || num(height) === -1) && Number.MAX_VALUE) || num(height)};
}
};
});
/**
* Returns whether or not an element is visible.
*/
$.fn.isVisible = function () {
return this.is(':visible');
};
/**
* Sets or gets the values for border, margin and padding.
*/
$.each(['border', 'margin', 'padding'], function (i, name) {
$.fn[name] = function (value) {
if (value) {
if (value.top !== undefined) {
this.css(name + '-top' + (name === 'border' ? '-width' : ''), value.top);
}
if (value.bottom !== undefined) {
this.css(name + '-bottom' + (name === 'border' ? '-width' : ''), value.bottom);
}
if (value.left !== undefined) {
this.css(name + '-left' + (name === 'border' ? '-width' : ''), value.left);
}
if (value.right !== undefined) {
this.css(name + '-right' + (name === 'border' ? '-width' : ''), value.right);
}
return this;
}
else {
return {top: num(this.css(name + '-top' + (name === 'border' ? '-width' : ''))),
bottom: num(this.css(name + '-bottom' + (name === 'border' ? '-width' : ''))),
left: num(this.css(name + '-left' + (name === 'border' ? '-width' : ''))),
right: num(this.css(name + '-right' + (name === 'border' ? '-width' : '')))};
}
};
});
})(jQuery);
/*!
* jQuery UI 1.8.18
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI
*/
(function( $, undefined ) {
// prevent duplicate loading
// this is only a problem because we proxy existing functions
// and we don't want to double proxy them
$.ui = $.ui || {};
if ( $.ui.version ) {
return;
}
$.extend( $.ui, {
version: "1.8.18",
keyCode: {
ALT: 18,
BACKSPACE: 8,
CAPS_LOCK: 20,
COMMA: 188,
COMMAND: 91,
COMMAND_LEFT: 91, // COMMAND
COMMAND_RIGHT: 93,
CONTROL: 17,
DELETE: 46,
DOWN: 40,
END: 35,
ENTER: 13,
ESCAPE: 27,
HOME: 36,
INSERT: 45,
LEFT: 37,
MENU: 93, // COMMAND_RIGHT
NUMPAD_ADD: 107,
NUMPAD_DECIMAL: 110,
NUMPAD_DIVIDE: 111,
NUMPAD_ENTER: 108,
NUMPAD_MULTIPLY: 106,
NUMPAD_SUBTRACT: 109,
PAGE_DOWN: 34,
PAGE_UP: 33,
PERIOD: 190,
RIGHT: 39,
SHIFT: 16,
SPACE: 32,
TAB: 9,
UP: 38,
WINDOWS: 91 // COMMAND
}
});
// plugins
$.fn.extend({
propAttr: $.fn.prop || $.fn.attr,
_focus: $.fn.focus,
focus: function( delay, fn ) {
return typeof delay === "number" ?
this.each(function() {
var elem = this;
setTimeout(function() {
$( elem ).focus();
if ( fn ) {
fn.call( elem );
}
}, delay );
}) :
this._focus.apply( this, arguments );
},
scrollParent: function() {
var scrollParent;
if (($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {
scrollParent = this.parents().filter(function() {
return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
}).eq(0);
} else {
scrollParent = this.parents().filter(function() {
return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
}).eq(0);
}
return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent;
},
zIndex: function( zIndex ) {
if ( zIndex !== undefined ) {
return this.css( "zIndex", zIndex );
}
if ( this.length ) {
var elem = $( this[ 0 ] ), position, value;
while ( elem.length && elem[ 0 ] !== document ) {
// Ignore z-index if position is set to a value where z-index is ignored by the browser
// This makes behavior of this function consistent across browsers
// WebKit always returns auto if the element is positioned
position = elem.css( "position" );
if ( position === "absolute" || position === "relative" || position === "fixed" ) {
// IE returns 0 when zIndex is not specified
// other browsers return a string
// we ignore the case of nested elements with an explicit value of 0
//
value = parseInt( elem.css( "zIndex" ), 10 );
if ( !isNaN( value ) && value !== 0 ) {
return value;
}
}
elem = elem.parent();
}
}
return 0;
},
disableSelection: function() {
return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
".ui-disableSelection", function( event ) {
event.preventDefault();
});
},
enableSelection: function() {
return this.unbind( ".ui-disableSelection" );
}
});
$.each( [ "Width", "Height" ], function( i, name ) {
var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
type = name.toLowerCase(),
orig = {
innerWidth: $.fn.innerWidth,
innerHeight: $.fn.innerHeight,
outerWidth: $.fn.outerWidth,
outerHeight: $.fn.outerHeight
};
function reduce( elem, size, border, margin ) {
$.each( side, function() {
size -= parseFloat( $.curCSS( elem, "padding" + this, true) ) || 0;
if ( border ) {
size -= parseFloat( $.curCSS( elem, "border" + this + "Width", true) ) || 0;
}
if ( margin ) {
size -= parseFloat( $.curCSS( elem, "margin" + this, true) ) || 0;
}
});
return size;
}
$.fn[ "inner" + name ] = function( size ) {
if ( size === undefined ) {
return orig[ "inner" + name ].call( this );
}
return this.each(function() {
$( this ).css( type, reduce( this, size ) + "px" );
});
};
$.fn[ "outer" + name] = function( size, margin ) {
if ( typeof size !== "number" ) {
return orig[ "outer" + name ].call( this, size );
}
return this.each(function() {
$( this).css( type, reduce( this, size, true, margin ) + "px" );
});
};
});
// selectors
function focusable( element, isTabIndexNotNaN ) {
var nodeName = element.nodeName.toLowerCase();
if ( "area" === nodeName ) {
var map = element.parentNode,
mapName = map.name,
img;
if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
return false;
}
img = $( "img[usemap=#" + mapName + "]" )[0];
return !!img && visible( img );
}
return ( /input|select|textarea|button|object/.test( nodeName )
? !element.disabled
: "a" == nodeName
? element.href || isTabIndexNotNaN
: isTabIndexNotNaN)
// the element and all of its ancestors must be visible
&& visible( element );
}
function visible( element ) {
return !$( element ).parents().andSelf().filter(function() {
return $.curCSS( this, "visibility" ) === "hidden" ||
$.expr.filters.hidden( this );
}).length;
}
$.extend( $.expr[ ":" ], {
data: function( elem, i, match ) {
return !!$.data( elem, match[ 3 ] );
},
focusable: function( element ) {
return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
},
tabbable: function( element ) {
var tabIndex = $.attr( element, "tabindex" ),
isTabIndexNaN = isNaN( tabIndex );
return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
}
});
// support
$(function() {
var body = document.body,
div = body.appendChild( div = document.createElement( "div" ) );
// access offsetHeight before setting the style to prevent a layout bug
// in IE 9 which causes the elemnt to continue to take up space even
// after it is removed from the DOM (#8026)
div.offsetHeight;
$.extend( div.style, {
minHeight: "100px",
height: "auto",
padding: 0,
borderWidth: 0
});
$.support.minHeight = div.offsetHeight === 100;
$.support.selectstart = "onselectstart" in div;
// set display to none to avoid a layout bug in IE
// http://dev.jquery.com/ticket/4014
body.removeChild( div ).style.display = "none";
});
// deprecated
$.extend( $.ui, {
// $.ui.plugin is deprecated. Use the proxy pattern instead.
plugin: {
add: function( module, option, set ) {
var proto = $.ui[ module ].prototype;
for ( var i in set ) {
proto.plugins[ i ] = proto.plugins[ i ] || [];
proto.plugins[ i ].push( [ option, set[ i ] ] );
}
},
call: function( instance, name, args ) {
var set = instance.plugins[ name ];
if ( !set || !instance.element[ 0 ].parentNode ) {
return;
}
for ( var i = 0; i < set.length; i++ ) {
if ( instance.options[ set[ i ][ 0 ] ] ) {
set[ i ][ 1 ].apply( instance.element, args );
}
}
}
},
// will be deprecated when we switch to jQuery 1.4 - use jQuery.contains()
contains: function( a, b ) {
return document.compareDocumentPosition ?
a.compareDocumentPosition( b ) & 16 :
a !== b && a.contains( b );
},
// only used by resizable
hasScroll: function( el, a ) {
//If overflow is hidden, the element might have extra content, but the user wants to hide it
if ( $( el ).css( "overflow" ) === "hidden") {
return false;
}
var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
has = false;
if ( el[ scroll ] > 0 ) {
return true;
}
// TODO: determine which cases actually cause this to happen
// if the element doesn't have the scroll set, see if it's possible to
// set the scroll
el[ scroll ] = 1;
has = ( el[ scroll ] > 0 );
el[ scroll ] = 0;
return has;
},
// these are odd functions, fix the API or move into individual plugins
isOverAxis: function( x, reference, size ) {
//Determines when x coordinate is over "b" element axis
return ( x > reference ) && ( x < ( reference + size ) );
},
isOver: function( y, x, top, left, height, width ) {
//Determines when x, y coordinates is over "b" element
return $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width );
}
});
})( jQuery );
/*!
* jQuery UI Widget 1.8.18
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Widget
*/
(function( $, undefined ) {
// jQuery 1.4+
if ( $.cleanData ) {
var _cleanData = $.cleanData;
$.cleanData = function( elems ) {
for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
try {
$( elem ).triggerHandler( "remove" );
// http://bugs.jquery.com/ticket/8235
} catch( e ) {}
}
_cleanData( elems );
};
} else {
var _remove = $.fn.remove;
$.fn.remove = function( selector, keepData ) {
return this.each(function() {
if ( !keepData ) {
if ( !selector || $.filter( selector, [ this ] ).length ) {
$( "*", this ).add( [ this ] ).each(function() {
try {
$( this ).triggerHandler( "remove" );
// http://bugs.jquery.com/ticket/8235
} catch( e ) {}
});
}
}
return _remove.call( $(this), selector, keepData );
});
};
}
$.widget = function( name, base, prototype ) {
var namespace = name.split( "." )[ 0 ],
fullName;
name = name.split( "." )[ 1 ];
fullName = namespace + "-" + name;
if ( !prototype ) {
prototype = base;
base = $.Widget;
}
// create selector for plugin
$.expr[ ":" ][ fullName ] = function( elem ) {
return !!$.data( elem, name );
};
$[ namespace ] = $[ namespace ] || {};
$[ namespace ][ name ] = function( options, element ) {
// allow instantiation without initializing for simple inheritance
if ( arguments.length ) {
this._createWidget( options, element );
}
};
var basePrototype = new base();
// we need to make the options hash a property directly on the new instance
// otherwise we'll modify the options hash on the prototype that we're
// inheriting from
// $.each( basePrototype, function( key, val ) {
// if ( $.isPlainObject(val) ) {
// basePrototype[ key ] = $.extend( {}, val );
// }
// });
basePrototype.options = $.extend( true, {}, basePrototype.options );
$[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
namespace: namespace,
widgetName: name,
widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,
widgetBaseClass: fullName
}, prototype );
$.widget.bridge( name, $[ namespace ][ name ] );
};
$.widget.bridge = function( name, object ) {
$.fn[ name ] = function( options ) {
var isMethodCall = typeof options === "string",
args = Array.prototype.slice.call( arguments, 1 ),
returnValue = this;
// allow multiple hashes to be passed on init
options = !isMethodCall && args.length ?
$.extend.apply( null, [ true, options ].concat(args) ) :
options;
// prevent calls to internal methods
if ( isMethodCall && options.charAt( 0 ) === "_" ) {
return returnValue;
}
if ( isMethodCall ) {
this.each(function() {
var instance = $.data( this, name ),
methodValue = instance && $.isFunction( instance[options] ) ?
instance[ options ].apply( instance, args ) :
instance;
// TODO: add this back in 1.9 and use $.error() (see #5972)
// if ( !instance ) {
// throw "cannot call methods on " + name + " prior to initialization; " +
// "attempted to call method '" + options + "'";
// }
// if ( !$.isFunction( instance[options] ) ) {
// throw "no such method '" + options + "' for " + name + " widget instance";
// }
// var methodValue = instance[ options ].apply( instance, args );
if ( methodValue !== instance && methodValue !== undefined ) {
returnValue = methodValue;
return false;
}
});
} else {
this.each(function() {
var instance = $.data( this, name );
if ( instance ) {
instance.option( options || {} )._init();
} else {
$.data( this, name, new object( options, this ) );
}
});
}
return returnValue;
};
};
$.Widget = function( options, element ) {
// allow instantiation without initializing for simple inheritance
if ( arguments.length ) {
this._createWidget( options, element );
}
};
$.Widget.prototype = {
widgetName: "widget",
widgetEventPrefix: "",
options: {
disabled: false
},
_createWidget: function( options, element ) {
// $.widget.bridge stores the plugin instance, but we do it anyway
// so that it's stored even before the _create function runs
$.data( element, this.widgetName, this );
this.element = $( element );
this.options = $.extend( true, {},
this.options,
this._getCreateOptions(),
options );
var self = this;
this.element.bind( "remove." + this.widgetName, function() {
self.destroy();
});
this._create();
this._trigger( "create" );
this._init();
},
_getCreateOptions: function() {
return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ];
},
_create: function() {},
_init: function() {},
destroy: function() {
this.element
.unbind( "." + this.widgetName )
.removeData( this.widgetName );
this.widget()
.unbind( "." + this.widgetName )
.removeAttr( "aria-disabled" )
.removeClass(
this.widgetBaseClass + "-disabled " +
"ui-state-disabled" );
},
widget: function() {
return this.element;
},
option: function( key, value ) {
var options = key;
if ( arguments.length === 0 ) {
// don't return a reference to the internal hash
return $.extend( {}, this.options );
}
if (typeof key === "string" ) {
if ( value === undefined ) {
return this.options[ key ];
}
options = {};
options[ key ] = value;
}
this._setOptions( options );
return this;
},
_setOptions: function( options ) {
var self = this;
$.each( options, function( key, value ) {
self._setOption( key, value );
});
return this;
},
_setOption: function( key, value ) {
this.options[ key ] = value;
if ( key === "disabled" ) {
this.widget()
[ value ? "addClass" : "removeClass"](
this.widgetBaseClass + "-disabled" + " " +
"ui-state-disabled" )
.attr( "aria-disabled", value );
}
return this;
},
enable: function() {
return this._setOption( "disabled", false );
},
disable: function() {
return this._setOption( "disabled", true );
},
_trigger: function( type, event, data ) {
var prop, orig,
callback = this.options[ type ];
data = data || {};
event = $.Event( event );
event.type = ( type === this.widgetEventPrefix ?
type :
this.widgetEventPrefix + type ).toLowerCase();
// the original event may come from any element
// so we need to reset the target on the new event
event.target = this.element[ 0 ];
// copy original event properties over to the new event
orig = event.originalEvent;
if ( orig ) {
for ( prop in orig ) {
if ( !( prop in event ) ) {
event[ prop ] = orig[ prop ];
}
}
}
this.element.trigger( event, data );
return !( $.isFunction(callback) &&
callback.call( this.element[0], event, data ) === false ||
event.isDefaultPrevented() );
}
};
})( jQuery );
/*!
* jQuery UI Mouse 1.8.18
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Mouse
*
* Depends:
* jquery.ui.widget.js
*/
(function( $, undefined ) {
var mouseHandled = false;
$( document ).mouseup( function( e ) {
mouseHandled = false;
});
$.widget("ui.mouse", {
options: {
cancel: ':input,option',
distance: 1,
delay: 0
},
_mouseInit: function() {
var self = this;
this.element
.bind('mousedown.'+this.widgetName, function(event) {
return self._mouseDown(event);
})
.bind('click.'+this.widgetName, function(event) {
if (true === $.data(event.target, self.widgetName + '.preventClickEvent')) {
$.removeData(event.target, self.widgetName + '.preventClickEvent');
event.stopImmediatePropagation();
return false;
}
});
this.started = false;
},
// TODO: make sure destroying one instance of mouse doesn't mess with
// other instances of mouse
_mouseDestroy: function() {
this.element.unbind('.'+this.widgetName);
},
_mouseDown: function(event) {
// don't let more than one widget handle mouseStart
if( mouseHandled ) { return };
// we may have missed mouseup (out of window)
(this._mouseStarted && this._mouseUp(event));
this._mouseDownEvent = event;
var self = this,
btnIsLeft = (event.which == 1),
// event.target.nodeName works around a bug in IE 8 with
// disabled inputs (#7620)
elIsCancel = (typeof this.options.cancel == "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
return true;
}
this.mouseDelayMet = !this.options.delay;
if (!this.mouseDelayMet) {
this._mouseDelayTimer = setTimeout(function() {
self.mouseDelayMet = true;
}, this.options.delay);
}
if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
this._mouseStarted = (this._mouseStart(event) !== false);
if (!this._mouseStarted) {
event.preventDefault();
return true;
}
}
// Click event may never have fired (Gecko & Opera)
if (true === $.data(event.target, this.widgetName + '.preventClickEvent')) {
$.removeData(event.target, this.widgetName + '.preventClickEvent');
}
// these delegates are required to keep context
this._mouseMoveDelegate = function(event) {
return self._mouseMove(event);
};
this._mouseUpDelegate = function(event) {
return self._mouseUp(event);
};
$(document)
.bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
.bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
event.preventDefault();
mouseHandled = true;
return true;
},
_mouseMove: function(event) {
// IE mouseup check - mouseup happened when mouse was out of window
if ($.browser.msie && !(document.documentMode >= 9) && !event.button) {
return this._mouseUp(event);
}
if (this._mouseStarted) {
this._mouseDrag(event);
return event.preventDefault();
}
if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
this._mouseStarted =
(this._mouseStart(this._mouseDownEvent, event) !== false);
(this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
}
return !this._mouseStarted;
},
_mouseUp: function(event) {
$(document)
.unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
.unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
if (this._mouseStarted) {
this._mouseStarted = false;
if (event.target == this._mouseDownEvent.target) {
$.data(event.target, this.widgetName + '.preventClickEvent', true);
}
this._mouseStop(event);
}
return false;
},
_mouseDistanceMet: function(event) {
return (Math.max(
Math.abs(this._mouseDownEvent.pageX - event.pageX),
Math.abs(this._mouseDownEvent.pageY - event.pageY)
) >= this.options.distance
);
},
_mouseDelayMet: function(event) {
return this.mouseDelayMet;
},
// These are placeholder methods, to be overriden by extending plugin
_mouseStart: function(event) {},
_mouseDrag: function(event) {},
_mouseStop: function(event) {},
_mouseCapture: function(event) { return true; }
});
})(jQuery);
/*
* jQuery UI Position 1.8.18
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Position
*/
(function( $, undefined ) {
$.ui = $.ui || {};
var horizontalPositions = /left|center|right/,
verticalPositions = /top|center|bottom/,
center = "center",
support = {},
_position = $.fn.position,
_offset = $.fn.offset;
$.fn.position = function( options ) {
if ( !options || !options.of ) {
return _position.apply( this, arguments );
}
// make a copy, we don't want to modify arguments
options = $.extend( {}, options );
var target = $( options.of ),
targetElem = target[0],
collision = ( options.collision || "flip" ).split( " " ),
offset = options.offset ? options.offset.split( " " ) : [ 0, 0 ],
targetWidth,
targetHeight,
basePosition;
if ( targetElem.nodeType === 9 ) {
targetWidth = target.width();
targetHeight = target.height();
basePosition = { top: 0, left: 0 };
// TODO: use $.isWindow() in 1.9
} else if ( targetElem.setTimeout ) {
targetWidth = target.width();
targetHeight = target.height();
basePosition = { top: target.scrollTop(), left: target.scrollLeft() };
} else if ( targetElem.preventDefault ) {
// force left top to allow flipping
options.at = "left top";
targetWidth = targetHeight = 0;
basePosition = { top: options.of.pageY, left: options.of.pageX };
} else {
targetWidth = target.outerWidth();
targetHeight = target.outerHeight();
basePosition = target.offset();
}
// force my and at to have valid horizontal and veritcal positions
// if a value is missing or invalid, it will be converted to center
$.each( [ "my", "at" ], function() {
var pos = ( options[this] || "" ).split( " " );
if ( pos.length === 1) {
pos = horizontalPositions.test( pos[0] ) ?
pos.concat( [center] ) :
verticalPositions.test( pos[0] ) ?
[ center ].concat( pos ) :
[ center, center ];
}
pos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : center;
pos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : center;
options[ this ] = pos;
});
// normalize collision option
if ( collision.length === 1 ) {
collision[ 1 ] = collision[ 0 ];
}
// normalize offset option
offset[ 0 ] = parseInt( offset[0], 10 ) || 0;
if ( offset.length === 1 ) {
offset[ 1 ] = offset[ 0 ];
}
offset[ 1 ] = parseInt( offset[1], 10 ) || 0;
if ( options.at[0] === "right" ) {
basePosition.left += targetWidth;
} else if ( options.at[0] === center ) {
basePosition.left += targetWidth / 2;
}
if ( options.at[1] === "bottom" ) {
basePosition.top += targetHeight;
} else if ( options.at[1] === center ) {
basePosition.top += targetHeight / 2;
}
basePosition.left += offset[ 0 ];
basePosition.top += offset[ 1 ];
return this.each(function() {
var elem = $( this ),
elemWidth = elem.outerWidth(),
elemHeight = elem.outerHeight(),
marginLeft = parseInt( $.curCSS( this, "marginLeft", true ) ) || 0,
marginTop = parseInt( $.curCSS( this, "marginTop", true ) ) || 0,
collisionWidth = elemWidth + marginLeft +
( parseInt( $.curCSS( this, "marginRight", true ) ) || 0 ),
collisionHeight = elemHeight + marginTop +
( parseInt( $.curCSS( this, "marginBottom", true ) ) || 0 ),
position = $.extend( {}, basePosition ),
collisionPosition;
if ( options.my[0] === "right" ) {
position.left -= elemWidth;
} else if ( options.my[0] === center ) {
position.left -= elemWidth / 2;
}
if ( options.my[1] === "bottom" ) {
position.top -= elemHeight;
} else if ( options.my[1] === center ) {
position.top -= elemHeight / 2;
}
// prevent fractions if jQuery version doesn't support them (see #5280)
if ( !support.fractions ) {
position.left = Math.round( position.left );
position.top = Math.round( position.top );
}
collisionPosition = {
left: position.left - marginLeft,
top: position.top - marginTop
};
$.each( [ "left", "top" ], function( i, dir ) {
if ( $.ui.position[ collision[i] ] ) {
$.ui.position[ collision[i] ][ dir ]( position, {
targetWidth: targetWidth,
targetHeight: targetHeight,
elemWidth: elemWidth,
elemHeight: elemHeight,
collisionPosition: collisionPosition,
collisionWidth: collisionWidth,
collisionHeight: collisionHeight,
offset: offset,
my: options.my,
at: options.at
});
}
});
if ( $.fn.bgiframe ) {
elem.bgiframe();
}
elem.offset( $.extend( position, { using: options.using } ) );
});
};
$.ui.position = {
fit: {
left: function( position, data ) {
var win = $( window ),
over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft();
position.left = over > 0 ? position.left - over : Math.max( position.left - data.collisionPosition.left, position.left );
},
top: function( position, data ) {
var win = $( window ),
over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop();
position.top = over > 0 ? position.top - over : Math.max( position.top - data.collisionPosition.top, position.top );
}
},
flip: {
left: function( position, data ) {
if ( data.at[0] === center ) {
return;
}
var win = $( window ),
over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(),
myOffset = data.my[ 0 ] === "left" ?
-data.elemWidth :
data.my[ 0 ] === "right" ?
data.elemWidth :
0,
atOffset = data.at[ 0 ] === "left" ?
data.targetWidth :
-data.targetWidth,
offset = -2 * data.offset[ 0 ];
position.left += data.collisionPosition.left < 0 ?
myOffset + atOffset + offset :
over > 0 ?
myOffset + atOffset + offset :
0;
},
top: function( position, data ) {
if ( data.at[1] === center ) {
return;
}
var win = $( window ),
over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(),
myOffset = data.my[ 1 ] === "top" ?
-data.elemHeight :
data.my[ 1 ] === "bottom" ?
data.elemHeight :
0,
atOffset = data.at[ 1 ] === "top" ?
data.targetHeight :
-data.targetHeight,
offset = -2 * data.offset[ 1 ];
position.top += data.collisionPosition.top < 0 ?
myOffset + atOffset + offset :
over > 0 ?
myOffset + atOffset + offset :
0;
}
}
};
// offset setter from jQuery 1.4
if ( !$.offset.setOffset ) {
$.offset.setOffset = function( elem, options ) {
// set position first, in-case top/left are set even on static elem
if ( /static/.test( $.curCSS( elem, "position" ) ) ) {
elem.style.position = "relative";
}
var curElem = $( elem ),
curOffset = curElem.offset(),
curTop = parseInt( $.curCSS( elem, "top", true ), 10 ) || 0,
curLeft = parseInt( $.curCSS( elem, "left", true ), 10) || 0,
props = {
top: (options.top - curOffset.top) + curTop,
left: (options.left - curOffset.left) + curLeft
};
if ( 'using' in options ) {
options.using.call( elem, props );
} else {
curElem.css( props );
}
};
$.fn.offset = function( options ) {
var elem = this[ 0 ];
if ( !elem || !elem.ownerDocument ) { return null; }
if ( options ) {
return this.each(function() {
$.offset.setOffset( this, options );
});
}
return _offset.call( this );
};
}
// fraction support test (older versions of jQuery don't support fractions)
(function () {
var body = document.getElementsByTagName( "body" )[ 0 ],
div = document.createElement( "div" ),
testElement, testElementParent, testElementStyle, offset, offsetTotal;
//Create a "fake body" for testing based on method used in jQuery.support
testElement = document.createElement( body ? "div" : "body" );
testElementStyle = {
visibility: "hidden",
width: 0,
height: 0,
border: 0,
margin: 0,
background: "none"
};
if ( body ) {
$.extend( testElementStyle, {
position: "absolute",
left: "-1000px",
top: "-1000px"
});
}
for ( var i in testElementStyle ) {
testElement.style[ i ] = testElementStyle[ i ];
}
testElement.appendChild( div );
testElementParent = body || document.documentElement;
testElementParent.insertBefore( testElement, testElementParent.firstChild );
div.style.cssText = "position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;";
offset = $( div ).offset( function( _, offset ) {
return offset;
}).offset();
testElement.innerHTML = "";
testElementParent.removeChild( testElement );
offsetTotal = offset.top + offset.left + ( body ? 2000 : 0 );
support.fractions = offsetTotal > 21 && offsetTotal < 22;
})();
}( jQuery ));
/*
* jQuery UI Selectable 1.8.18
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Selectables
*
* Depends:
* jquery.ui.core.js
* jquery.ui.mouse.js
* jquery.ui.widget.js
*/
(function( $, undefined ) {
$.widget("ui.selectable", $.ui.mouse, {
options: {
appendTo: 'body',
autoRefresh: true,
distance: 0,
filter: '*',
tolerance: 'touch'
},
_create: function() {
var self = this;
this.element.addClass("ui-selectable");
this.dragged = false;
// cache selectee children based on filter
var selectees;
this.refresh = function() {
selectees = $(self.options.filter, self.element[0]);
selectees.addClass("ui-selectee");
selectees.each(function() {
var $this = $(this);
var pos = $this.offset();
$.data(this, "selectable-item", {
element: this,
$element: $this,
left: pos.left,
top: pos.top,
right: pos.left + $this.outerWidth(),
bottom: pos.top + $this.outerHeight(),
startselected: false,
selected: $this.hasClass('ui-selected'),
selecting: $this.hasClass('ui-selecting'),
unselecting: $this.hasClass('ui-unselecting')
});
});
};
this.refresh();
this.selectees = selectees.addClass("ui-selectee");
this._mouseInit();
this.helper = $("");
},
destroy: function() {
this.selectees
.removeClass("ui-selectee")
.removeData("selectable-item");
this.element
.removeClass("ui-selectable ui-selectable-disabled")
.removeData("selectable")
.unbind(".selectable");
this._mouseDestroy();
return this;
},
_mouseStart: function(event) {
var self = this;
this.opos = [event.pageX, event.pageY];
if (this.options.disabled)
return;
var options = this.options;
this.selectees = $(options.filter, this.element[0]);
this._trigger("start", event);
$(options.appendTo).append(this.helper);
// position helper (lasso)
this.helper.css({
"left": event.clientX,
"top": event.clientY,
"width": 0,
"height": 0
});
if (options.autoRefresh) {
this.refresh();
}
this.selectees.filter('.ui-selected').each(function() {
var selectee = $.data(this, "selectable-item");
selectee.startselected = true;
if (!event.metaKey && !event.ctrlKey) {
selectee.$element.removeClass('ui-selected');
selectee.selected = false;
selectee.$element.addClass('ui-unselecting');
selectee.unselecting = true;
// selectable UNSELECTING callback
self._trigger("unselecting", event, {
unselecting: selectee.element
});
}
});
$(event.target).parents().andSelf().each(function() {
var selectee = $.data(this, "selectable-item");
if (selectee) {
var doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass('ui-selected');
selectee.$element
.removeClass(doSelect ? "ui-unselecting" : "ui-selected")
.addClass(doSelect ? "ui-selecting" : "ui-unselecting");
selectee.unselecting = !doSelect;
selectee.selecting = doSelect;
selectee.selected = doSelect;
// selectable (UN)SELECTING callback
if (doSelect) {
self._trigger("selecting", event, {
selecting: selectee.element
});
} else {
self._trigger("unselecting", event, {
unselecting: selectee.element
});
}
return false;
}
});
},
_mouseDrag: function(event) {
var self = this;
this.dragged = true;
if (this.options.disabled)
return;
var options = this.options;
var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY;
if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; }
if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; }
this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
this.selectees.each(function() {
var selectee = $.data(this, "selectable-item");
//prevent helper from being selected if appendTo: selectable
if (!selectee || selectee.element == self.element[0])
return;
var hit = false;
if (options.tolerance == 'touch') {
hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
} else if (options.tolerance == 'fit') {
hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
}
if (hit) {
// SELECT
if (selectee.selected) {
selectee.$element.removeClass('ui-selected');
selectee.selected = false;
}
if (selectee.unselecting) {
selectee.$element.removeClass('ui-unselecting');
selectee.unselecting = false;
}
if (!selectee.selecting) {
selectee.$element.addClass('ui-selecting');
selectee.selecting = true;
// selectable SELECTING callback
self._trigger("selecting", event, {
selecting: selectee.element
});
}
} else {
// UNSELECT
if (selectee.selecting) {
if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
selectee.$element.removeClass('ui-selecting');
selectee.selecting = false;
selectee.$element.addClass('ui-selected');
selectee.selected = true;
} else {
selectee.$element.removeClass('ui-selecting');
selectee.selecting = false;
if (selectee.startselected) {
selectee.$element.addClass('ui-unselecting');
selectee.unselecting = true;
}
// selectable UNSELECTING callback
self._trigger("unselecting", event, {
unselecting: selectee.element
});
}
}
if (selectee.selected) {
if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
selectee.$element.removeClass('ui-selected');
selectee.selected = false;
selectee.$element.addClass('ui-unselecting');
selectee.unselecting = true;
// selectable UNSELECTING callback
self._trigger("unselecting", event, {
unselecting: selectee.element
});
}
}
}
});
return false;
},
_mouseStop: function(event) {
var self = this;
this.dragged = false;
var options = this.options;
$('.ui-unselecting', this.element[0]).each(function() {
var selectee = $.data(this, "selectable-item");
selectee.$element.removeClass('ui-unselecting');
selectee.unselecting = false;
selectee.startselected = false;
self._trigger("unselected", event, {
unselected: selectee.element
});
});
$('.ui-selecting', this.element[0]).each(function() {
var selectee = $.data(this, "selectable-item");
selectee.$element.removeClass('ui-selecting').addClass('ui-selected');
selectee.selecting = false;
selectee.selected = true;
selectee.startselected = true;
self._trigger("selected", event, {
selected: selectee.element
});
});
this._trigger("stop", event);
this.helper.remove();
return false;
}
});
$.extend($.ui.selectable, {
version: "1.8.18"
});
})(jQuery);
/*
* jQuery UI Accordion 1.8.18
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Accordion
*
* Depends:
* jquery.ui.core.js
* jquery.ui.widget.js
*/
(function( $, undefined ) {
$.widget( "ui.accordion", {
options: {
active: 0,
animated: "slide",
autoHeight: true,
clearStyle: false,
collapsible: false,
event: "click",
fillSpace: false,
header: "> li > :first-child,> :not(li):even",
icons: {
header: "ui-icon-triangle-1-e",
headerSelected: "ui-icon-triangle-1-s"
},
navigation: false,
navigationFilter: function() {
return this.href.toLowerCase() === location.href.toLowerCase();
}
},
_create: function() {
var self = this,
options = self.options;
self.running = 0;
self.element
.addClass( "ui-accordion ui-widget ui-helper-reset" )
// in lack of child-selectors in CSS
// we need to mark top-LIs in a UL-accordion for some IE-fix
.children( "li" )
.addClass( "ui-accordion-li-fix" );
self.headers = self.element.find( options.header )
.addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" )
.bind( "mouseenter.accordion", function() {
if ( options.disabled ) {
return;
}
$( this ).addClass( "ui-state-hover" );
})
.bind( "mouseleave.accordion", function() {
if ( options.disabled ) {
return;
}
$( this ).removeClass( "ui-state-hover" );
})
.bind( "focus.accordion", function() {
if ( options.disabled ) {
return;
}
$( this ).addClass( "ui-state-focus" );
})
.bind( "blur.accordion", function() {
if ( options.disabled ) {
return;
}
$( this ).removeClass( "ui-state-focus" );
});
self.headers.next()
.addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" );
if ( options.navigation ) {
var current = self.element.find( "a" ).filter( options.navigationFilter ).eq( 0 );
if ( current.length ) {
var header = current.closest( ".ui-accordion-header" );
if ( header.length ) {
// anchor within header
self.active = header;
} else {
// anchor within content
self.active = current.closest( ".ui-accordion-content" ).prev();
}
}
}
self.active = self._findActive( self.active || options.active )
.addClass( "ui-state-default ui-state-active" )
.toggleClass( "ui-corner-all" )
.toggleClass( "ui-corner-top" );
self.active.next().addClass( "ui-accordion-content-active" );
self._createIcons();
self.resize();
// ARIA
self.element.attr( "role", "tablist" );
self.headers
.attr( "role", "tab" )
.bind( "keydown.accordion", function( event ) {
return self._keydown( event );
})
.next()
.attr( "role", "tabpanel" );
self.headers
.not( self.active || "" )
.attr({
"aria-expanded": "false",
"aria-selected": "false",
tabIndex: -1
})
.next()
.hide();
// make sure at least one header is in the tab order
if ( !self.active.length ) {
self.headers.eq( 0 ).attr( "tabIndex", 0 );
} else {
self.active
.attr({
"aria-expanded": "true",
"aria-selected": "true",
tabIndex: 0
});
}
// only need links in tab order for Safari
if ( !$.browser.safari ) {
self.headers.find( "a" ).attr( "tabIndex", -1 );
}
if ( options.event ) {
self.headers.bind( options.event.split(" ").join(".accordion ") + ".accordion", function(event) {
self._clickHandler.call( self, event, this );
event.preventDefault();
});
}
},
_createIcons: function() {
var options = this.options;
if ( options.icons ) {
$( "" )
.addClass( "ui-icon " + options.icons.header )
.prependTo( this.headers );
this.active.children( ".ui-icon" )
.toggleClass(options.icons.header)
.toggleClass(options.icons.headerSelected);
this.element.addClass( "ui-accordion-icons" );
}
},
_destroyIcons: function() {
this.headers.children( ".ui-icon" ).remove();
this.element.removeClass( "ui-accordion-icons" );
},
destroy: function() {
var options = this.options;
this.element
.removeClass( "ui-accordion ui-widget ui-helper-reset" )
.removeAttr( "role" );
this.headers
.unbind( ".accordion" )
.removeClass( "ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
.removeAttr( "role" )
.removeAttr( "aria-expanded" )
.removeAttr( "aria-selected" )
.removeAttr( "tabIndex" );
this.headers.find( "a" ).removeAttr( "tabIndex" );
this._destroyIcons();
var contents = this.headers.next()
.css( "display", "" )
.removeAttr( "role" )
.removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled" );
if ( options.autoHeight || options.fillHeight ) {
contents.css( "height", "" );
}
return $.Widget.prototype.destroy.call( this );
},
_setOption: function( key, value ) {
$.Widget.prototype._setOption.apply( this, arguments );
if ( key == "active" ) {
this.activate( value );
}
if ( key == "icons" ) {
this._destroyIcons();
if ( value ) {
this._createIcons();
}
}
// #5332 - opacity doesn't cascade to positioned elements in IE
// so we need to add the disabled class to the headers and panels
if ( key == "disabled" ) {
this.headers.add(this.headers.next())
[ value ? "addClass" : "removeClass" ](
"ui-accordion-disabled ui-state-disabled" );
}
},
_keydown: function( event ) {
if ( this.options.disabled || event.altKey || event.ctrlKey ) {
return;
}
var keyCode = $.ui.keyCode,
length = this.headers.length,
currentIndex = this.headers.index( event.target ),
toFocus = false;
switch ( event.keyCode ) {
case keyCode.RIGHT:
case keyCode.DOWN:
toFocus = this.headers[ ( currentIndex + 1 ) % length ];
break;
case keyCode.LEFT:
case keyCode.UP:
toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
break;
case keyCode.SPACE:
case keyCode.ENTER:
this._clickHandler( { target: event.target }, event.target );
event.preventDefault();
}
if ( toFocus ) {
$( event.target ).attr( "tabIndex", -1 );
$( toFocus ).attr( "tabIndex", 0 );
toFocus.focus();
return false;
}
return true;
},
resize: function() {
var options = this.options,
maxHeight;
if ( options.fillSpace ) {
if ( $.browser.msie ) {
var defOverflow = this.element.parent().css( "overflow" );
this.element.parent().css( "overflow", "hidden");
}
maxHeight = this.element.parent().height();
if ($.browser.msie) {
this.element.parent().css( "overflow", defOverflow );
}
this.headers.each(function() {
maxHeight -= $( this ).outerHeight( true );
});
this.headers.next()
.each(function() {
$( this ).height( Math.max( 0, maxHeight -
$( this ).innerHeight() + $( this ).height() ) );
})
.css( "overflow", "auto" );
} else if ( options.autoHeight ) {
maxHeight = 0;
this.headers.next()
.each(function() {
maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
})
.height( maxHeight );
}
return this;
},
activate: function( index ) {
// TODO this gets called on init, changing the option without an explicit call for that
this.options.active = index;
// call clickHandler with custom event
var active = this._findActive( index )[ 0 ];
this._clickHandler( { target: active }, active );
return this;
},
_findActive: function( selector ) {
return selector
? typeof selector === "number"
? this.headers.filter( ":eq(" + selector + ")" )
: this.headers.not( this.headers.not( selector ) )
: selector === false
? $( [] )
: this.headers.filter( ":eq(0)" );
},
// TODO isn't event.target enough? why the separate target argument?
_clickHandler: function( event, target ) {
var options = this.options;
if ( options.disabled ) {
return;
}
// called only when using activate(false) to close all parts programmatically
if ( !event.target ) {
if ( !options.collapsible ) {
return;
}
this.active
.removeClass( "ui-state-active ui-corner-top" )
.addClass( "ui-state-default ui-corner-all" )
.children( ".ui-icon" )
.removeClass( options.icons.headerSelected )
.addClass( options.icons.header );
this.active.next().addClass( "ui-accordion-content-active" );
var toHide = this.active.next(),
data = {
options: options,
newHeader: $( [] ),
oldHeader: options.active,
newContent: $( [] ),
oldContent: toHide
},
toShow = ( this.active = $( [] ) );
this._toggle( toShow, toHide, data );
return;
}
// get the click target
var clicked = $( event.currentTarget || target ),
clickedIsActive = clicked[0] === this.active[0];
// TODO the option is changed, is that correct?
// TODO if it is correct, shouldn't that happen after determining that the click is valid?
options.active = options.collapsible && clickedIsActive ?
false :
this.headers.index( clicked );
// if animations are still active, or the active header is the target, ignore click
if ( this.running || ( !options.collapsible && clickedIsActive ) ) {
return;
}
// find elements to show and hide
var active = this.active,
toShow = clicked.next(),
toHide = this.active.next(),
data = {
options: options,
newHeader: clickedIsActive && options.collapsible ? $([]) : clicked,
oldHeader: this.active,
newContent: clickedIsActive && options.collapsible ? $([]) : toShow,
oldContent: toHide
},
down = this.headers.index( this.active[0] ) > this.headers.index( clicked[0] );
// when the call to ._toggle() comes after the class changes
// it causes a very odd bug in IE 8 (see #6720)
this.active = clickedIsActive ? $([]) : clicked;
this._toggle( toShow, toHide, data, clickedIsActive, down );
// switch classes
active
.removeClass( "ui-state-active ui-corner-top" )
.addClass( "ui-state-default ui-corner-all" )
.children( ".ui-icon" )
.removeClass( options.icons.headerSelected )
.addClass( options.icons.header );
if ( !clickedIsActive ) {
clicked
.removeClass( "ui-state-default ui-corner-all" )
.addClass( "ui-state-active ui-corner-top" )
.children( ".ui-icon" )
.removeClass( options.icons.header )
.addClass( options.icons.headerSelected );
clicked
.next()
.addClass( "ui-accordion-content-active" );
}
return;
},
_toggle: function( toShow, toHide, data, clickedIsActive, down ) {
var self = this,
options = self.options;
self.toShow = toShow;
self.toHide = toHide;
self.data = data;
var complete = function() {
if ( !self ) {
return;
}
return self._completed.apply( self, arguments );
};
// trigger changestart event
self._trigger( "changestart", null, self.data );
// count elements to animate
self.running = toHide.size() === 0 ? toShow.size() : toHide.size();
if ( options.animated ) {
var animOptions = {};
if ( options.collapsible && clickedIsActive ) {
animOptions = {
toShow: $( [] ),
toHide: toHide,
complete: complete,
down: down,
autoHeight: options.autoHeight || options.fillSpace
};
} else {
animOptions = {
toShow: toShow,
toHide: toHide,
complete: complete,
down: down,
autoHeight: options.autoHeight || options.fillSpace
};
}
if ( !options.proxied ) {
options.proxied = options.animated;
}
if ( !options.proxiedDuration ) {
options.proxiedDuration = options.duration;
}
options.animated = $.isFunction( options.proxied ) ?
options.proxied( animOptions ) :
options.proxied;
options.duration = $.isFunction( options.proxiedDuration ) ?
options.proxiedDuration( animOptions ) :
options.proxiedDuration;
var animations = $.ui.accordion.animations,
duration = options.duration,
easing = options.animated;
if ( easing && !animations[ easing ] && !$.easing[ easing ] ) {
easing = "slide";
}
if ( !animations[ easing ] ) {
animations[ easing ] = function( options ) {
this.slide( options, {
easing: easing,
duration: duration || 700
});
};
}
animations[ easing ]( animOptions );
} else {
if ( options.collapsible && clickedIsActive ) {
toShow.toggle();
} else {
toHide.hide();
toShow.show();
}
complete( true );
}
// TODO assert that the blur and focus triggers are really necessary, remove otherwise
toHide.prev()
.attr({
"aria-expanded": "false",
"aria-selected": "false",
tabIndex: -1
})
.blur();
toShow.prev()
.attr({
"aria-expanded": "true",
"aria-selected": "true",
tabIndex: 0
})
.focus();
},
_completed: function( cancel ) {
this.running = cancel ? 0 : --this.running;
if ( this.running ) {
return;
}
if ( this.options.clearStyle ) {
this.toShow.add( this.toHide ).css({
height: "",
overflow: ""
});
}
// other classes are removed before the animation; this one needs to stay until completed
this.toHide.removeClass( "ui-accordion-content-active" );
// Work around for rendering bug in IE (#5421)
if ( this.toHide.length ) {
this.toHide.parent()[0].className = this.toHide.parent()[0].className;
}
this._trigger( "change", null, this.data );
}
});
$.extend( $.ui.accordion, {
version: "1.8.18",
animations: {
slide: function( options, additions ) {
options = $.extend({
easing: "swing",
duration: 300
}, options, additions );
if ( !options.toHide.size() ) {
options.toShow.animate({
height: "show",
paddingTop: "show",
paddingBottom: "show"
}, options );
return;
}
if ( !options.toShow.size() ) {
options.toHide.animate({
height: "hide",
paddingTop: "hide",
paddingBottom: "hide"
}, options );
return;
}
var overflow = options.toShow.css( "overflow" ),
percentDone = 0,
showProps = {},
hideProps = {},
fxAttrs = [ "height", "paddingTop", "paddingBottom" ],
originalWidth;
// fix width before calculating height of hidden element
var s = options.toShow;
originalWidth = s[0].style.width;
s.width( s.parent().width()
- parseFloat( s.css( "paddingLeft" ) )
- parseFloat( s.css( "paddingRight" ) )
- ( parseFloat( s.css( "borderLeftWidth" ) ) || 0 )
- ( parseFloat( s.css( "borderRightWidth" ) ) || 0 ) );
$.each( fxAttrs, function( i, prop ) {
hideProps[ prop ] = "hide";
var parts = ( "" + $.css( options.toShow[0], prop ) ).match( /^([\d+-.]+)(.*)$/ );
showProps[ prop ] = {
value: parts[ 1 ],
unit: parts[ 2 ] || "px"
};
});
options.toShow.css({ height: 0, overflow: "hidden" }).show();
options.toHide
.filter( ":hidden" )
.each( options.complete )
.end()
.filter( ":visible" )
.animate( hideProps, {
step: function( now, settings ) {
// only calculate the percent when animating height
// IE gets very inconsistent results when animating elements
// with small values, which is common for padding
if ( settings.prop == "height" ) {
percentDone = ( settings.end - settings.start === 0 ) ? 0 :
( settings.now - settings.start ) / ( settings.end - settings.start );
}
options.toShow[ 0 ].style[ settings.prop ] =
( percentDone * showProps[ settings.prop ].value )
+ showProps[ settings.prop ].unit;
},
duration: options.duration,
easing: options.easing,
complete: function() {
if ( !options.autoHeight ) {
options.toShow.css( "height", "" );
}
options.toShow.css({
width: originalWidth,
overflow: overflow
});
options.complete();
}
});
},
bounceslide: function( options ) {
this.slide( options, {
easing: options.down ? "easeOutBounce" : "swing",
duration: options.down ? 1000 : 200
});
}
}
});
})( jQuery );
/*
* jQuery UI Tabs 1.8.18
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Tabs
*
* Depends:
* jquery.ui.core.js
* jquery.ui.widget.js
*/
(function( $, undefined ) {
var tabId = 0,
listId = 0;
function getNextTabId() {
return ++tabId;
}
function getNextListId() {
return ++listId;
}
$.widget( "ui.tabs", {
options: {
add: null,
ajaxOptions: null,
cache: false,
cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
collapsible: false,
disable: null,
disabled: [],
enable: null,
event: "click",
fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
idPrefix: "ui-tabs-",
load: null,
panelTemplate: "",
remove: null,
select: null,
show: null,
spinner: "Loading…",
tabTemplate: "