Index: in-commerce/checkout/one_step_checkout.tpl =================================================================== --- in-commerce/checkout/one_step_checkout.tpl (revision 0) +++ in-commerce/checkout/one_step_checkout.tpl (revision 0) @@ -0,0 +1,279 @@ + + + + + + + + + + + + + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ + + + +
+
+ +
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ +

+ + Continue as Guest or + + + +
+
+ B +
+ + + checked"/> + + + +
+ + + + + + + + + +
+
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ . +
+ + +
+
+ + + + + + () + View Order Details +
+ img/credit_cards/visa.gif" /> + img/credit_cards/american_express.gif" /> + img/credit_cards/master_card.gif" /> + img/credit_cards/novus.gif" /> + + + +
+ + + + + + + + + + + + + "> + + + + + + + + "> + + + + +
+ +
+
+ + / + +
+ +
+
+ " value="" tabindex="" style="width: 50px;"> +    +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
:
():
:
:
:
%:
:
:
+ + +
+
+ +
+
+
+ + + + + Property changes on: in-commerce\checkout\one_step_checkout.tpl ___________________________________________________________________ Added: svn:eol-style + LF Index: in-commerce/checkout/shop_cart.tpl =================================================================== --- in-commerce/checkout/shop_cart.tpl (revision 14590) +++ in-commerce/checkout/shop_cart.tpl (working copy) @@ -41,9 +41,13 @@ () -
+ - +
+ +
+ + - +
+ - @@ -90,88 +94,100 @@ - + - - + + - + @@ -186,61 +202,82 @@ @@ -252,7 +289,47 @@ in-commerce/checkout/shippingin-commerce/checkout/billing" /> @@ -317,6 +394,57 @@ + + + + Index: in-commerce/elements/content_boxes/checkout/shipping_options.elm.tpl =================================================================== --- in-commerce/elements/content_boxes/checkout/shipping_options.elm.tpl (revision 14590) +++ in-commerce/elements/content_boxes/checkout/shipping_options.elm.tpl (working copy) @@ -2,197 +2,22 @@ - -
@@ -75,8 +79,8 @@
. .  
- img/shopping_cart_item.gif" width="16" height="14" alt="" /> + +
+ [ProductId: ; OptionsSalt: ; BackOrderFlag: ] +
+ "> -   + +   - + + + +
- - - - - - - "> - + + + + + + + + "> +
- + +
- -
- :
- : + +
style="display: none;"> + :
+ : + - - +
-
- - + - " style="width:20px" class="input-text" name="" /> + " style="width:20px" class="input-text product-qty" name="" id="" /> - " style="width:20px" class="input-text" name="" /> + " style="width:20px" class="input-text product-qty" name="" id="" /> - 1 + + + + +   - img/delete.gif" title="Delete" alt="Delete" width="8" height="10" border="0" /> + img/delete.gif" title="Delete" alt="Delete" width="8" height="10" border="0" /> - img/delete.gif" title="Delete" alt="Delete" width="8" height="10" border="0" /> + img/delete.gif" title="Delete" alt="Delete" width="8" height="10" border="0" />
img/s.gif" width="1" height="1" alt="" />
- - + style="display: none;"> - + + style="display: none;"> - - - + + - + - - + - - - - - - - + + + - - - - - -
:  - +
img/s.gif" width="1" height="5" alt="" />
- :  +
style="display: none;"> + :  +
+ +
style="display: none;"> + :  +
-    +
style="display: none;"> +    + <inp2:m_Phrase label='lu_comm_RemoveCoupon' no_editing='1'/> +
- ">img/delete.gif" title="" alt="" width="8" height="10" border="0" /> +
style="display: none;"> + + +
+ +
+
+ img/s.gif" width="1" height="3" alt="" /> +
- img/s.gif" width="1" height="3" alt="" /> -
-    - ">img/delete.gif" title="" alt="" width="8" height="10" border="0" /> +
style="display: none;"> + :  +
+ +
style="display: none;"> + :  +
+ + +
style="display: none;"> + + +
+ +
+
+
- : + :
- " /> + + + " />   ')" value="" />
- - - - - - - - - - - - - - - : - - -
- - - name="" - id="_" value=""> -  
-
- -
-
- - - : - -
- " id="" value="" /> - ').value = this.checked ? 1:0; document.getElementById('events[ord][OnUpdate]').click();" type="checkbox" - - name="cb_" - id="cb_" value="1" /> -  
- -
- " value="1" /> -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
img/s.gif" width="1" height="1" alt="" />
-
-
img/s.gif" width="1" height="1" alt="" />
-
- "/>
-
  - : - - -
   - : - - -
   - : - - -
   - : - - -
   - : - - -
   - %: - - -
   - : - - -
   - : - - -
    - - " class="button"> -
- - -
+
+
- - - - - - - ">
-
+ + + + + + + ">
+
@@ -201,13 +26,13 @@
:
- + @@ -223,14 +48,185 @@ (">). - - . - - - + + + + + + + + + + + + + + + + + : + + +
+ + + name="" + id="_" value=""> +  
+
+ +
+
+ + + : + +
+ " id="" value="" /> + ').value = this.checked ? 1:0; document.getElementById('events[ord][OnUpdate]').click();" type="checkbox" + + name="cb_" + id="cb_" value="1" /> +  
+ +
+ " value="1" /> +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
img/s.gif" width="1" height="1" alt="" />
+
+
img/s.gif" width="1" height="1" alt="" />
+
+ "/>
+
  + : + + +
   + : + + +
   + : + + +
   + : + + +
   + : + + +
   + %: + + +
   + : + + +
   + : + + +
    + + " class="button"> +
+ + . +
\ No newline at end of file Index: in-commerce/elements/html_head.elm.tpl =================================================================== --- in-commerce/elements/html_head.elm.tpl (revision 14590) +++ in-commerce/elements/html_head.elm.tpl (working copy) @@ -3,4 +3,8 @@ + + + + Index: in-commerce/elements/side_boxes/checkout_steps.elm.tpl =================================================================== --- in-commerce/elements/side_boxes/checkout_steps.elm.tpl (revision 14590) +++ in-commerce/elements/side_boxes/checkout_steps.elm.tpl (working copy) @@ -39,6 +39,9 @@ in-commerce/checkout/confirmation" />
+ +
+ One Step Checkout \ No newline at end of file Index: in-commerce/inc/cart_manager.js =================================================================== --- in-commerce/inc/cart_manager.js (revision 0) +++ in-commerce/inc/cart_manager.js (revision 0) @@ -0,0 +1,538 @@ +function ShopCartManager( $settings ) { + this.updateUrl = ''; + this.orderInfo = {}; + this.constants = {}; + this.currencyMask = '%s'; + + $.extend(this, $settings); + + this.tooltips = []; + this.rowTimers = {}; + + var $me = this; + + $(document).ready( + function () { + $me.init(); + } + ); +} + +ShopCartManager.prototype.init = function () { + var $me = this; + + this.process(this.orderInfo); + + $('.delete-cart-link').click( + function ($e) { + var $order_item_id = $(this).parents('tr:first').attr('order_item_id'); + + $me.apply( [{name: 'delete_id', value: $order_item_id}] ); + + return false; + } + ); + + $('.product-qty:input', '#shopping-cart-form') + .blur( + function ($e) { + var $row_index = $(this).parents('tr[row_index]:first').attr('row_index'); + + console.log('blur on ', $row_index, ' row'); + + $me.clearRowTimers($row_index); + + console.log('doing apply (from blur) on ', $row_index, ' row'); + $me.apply(); + + return false; + } + ) + .keyup( + function ($e) { + var $row_index = $(this).parents('tr[row_index]:first').attr('row_index'); + + console.log('keyup on ', $row_index, ' row'); + + $me.clearRowTimers($row_index); + + $me.rowTimers[$row_index] = setTimeout( + function() { + console.log('doing apply (from keyup) on ', $row_index, ' row'); + $me.apply(); + } + , 2000 + ); + } + ); + + + $('#remove-coupon').click( + function ($e) { + $me.apply( [{name: 'remove', value: 'coupon'}] ); + + return false; + } + ); + + $('#remove-gift-certificate').click( + function ($e) { + $me.apply( [{name: 'remove', value: 'gift_certificate'}] ); + + return false; + } + ); + + $('#update-cart, #apply-coupon, #apply-gift-certificate').click( + function ($e) { + $me.apply(); + + return false; + } + ); +} + +ShopCartManager.prototype.clearRowTimers = function ($row_index) { + if ( this.rowTimers[$row_index] !== undefined ) { + console.log('cleartimers on ', $row_index, ' row -> found = delete'); + + clearTimeout(this.rowTimers[$row_index]); + delete this.rowTimers[$row_index]; + } + else { + console.log('cleartimers on ', $row_index, ' row -> not found = skip'); + } +} + +ShopCartManager.prototype.destroyTooltips = function () { + while ( this.tooltips.length ) { + var $input = this.tooltips.shift(); + + $input.qtip('destroy'); + } +} + +ShopCartManager.prototype.apply = function ($params) { + var $me = this; + + $.post( + this.updateUrl, + this.getFormData($params), + function ($data) { + $data = eval('(' + $data + ')'); + + $me.process($data); + } + ) +} + +ShopCartManager.prototype.getFormData = function ($params) { + var $ret = $('#shopping-cart-form').serializeArray(); + + if ( $params !== undefined ) { + while( $params.length > 0 ) { + $ret.push( $params.shift() ); + } + } + + return $ret; +} + +ShopCartManager.prototype.process = function ($data) { + // 1. row missing ajax response -> was deleted in db + // 2. row missing in HTML -> was added in db + var $me = this, + $old_rows = this.getOldRows(), + $new_rows = this.getNewRows($data), + $add_rows = $new_rows.diff($old_rows), + $delete_rows = $old_rows.diff($new_rows); + + console.log('proessing data: ', $data); + + // add rows + $($add_rows).each( + function () { + $me.addRow( this, $data.items[this] ); + } + ); + + // delete rows + $($delete_rows).each( + function () { + var $row = $me.getRowByIndex(this); + + $row.next('tr.separator').remove(); + $row.remove(); + } + ); + + this.updateExistingRows($data); + + + this.showErrors($data); + this.showFooter($data); + + console.log('old: ', $old_rows, '; new: ', $new_rows, '; add: ', $add_rows, '; delete: ', $delete_rows); +} + +ShopCartManager.prototype.addRow = function ($row_index, $row_data) { + console.log('adding row: ', $row_data); + + var $html = $('#product-row-mask').val(), + $value = ''; + + + /*f: OrderItemId ; v: 101 + f: ProductName ; v: Product With Stock Limit = 5; with backorder + f: BackOrderFlag ; v: 1 + f: FlatPrice ; v: 2 + f: Price ; v: 1.2308 + f: Quantity ; v: 2 + f: Virtual ; v: 0 + f: cust_Availability ; v:*/ + + + for (var $field in $row_data.fields) { + $value = $row_data.fields[$field]; + + if ( $field == 'Price' || $field == 'FlatPrice' ) { + $value = this.formatPrice($value); + } + + $html = $html.replace(new RegExp('{field:' + $field + '}', 'g'), $value); + + console.log('f: ', $field, '; v: ', $value); + } + + $html = $html.replace(/{ROW_INDEX}/g, $row_index); +// $html = $html.replace(/{DISCOUNT}/g, $row_index); +// $html = $html.replace(/{EXTENDED_PRICE}/g, $row_index); + + var $separator = $( $('#product-row-separator-mask').val() ); + + $('.shop-cart-row:last').after($separator); + $separator.after($html); +} + +ShopCartManager.prototype.updateExistingRows = function ($data) { + for (var $row_index in $data.items) { + var $fields = $data.items[$row_index].fields, + $discount = $fields['FlatPrice'] - $fields['Price'], + $product_row = this.getRowByIndex($row_index), + $discount_container = $('.product-discount', $product_row); + + // update product title + var $product_with_link = $('.product-with-link', $product_row); + + $('a:first', $product_with_link) + .attr('href', $data.items[$row_index].product_url) + .html($fields['ProductName']); + $product_with_link.toggle( $fields['Virtual'] == 0 ); + + $('.product-without-link', $product_row) + .toggle( $fields['Virtual'] == 1 ) + .html($fields['ProductName']); + + $('.free-shipping', $product_row).toggle( $data.items[$row_index].free_promo_shipping ); + $('.back-order-mark', $product_row).toggle( $fields['BackOrderFlag'] > 0 ); + + $('.product-availability', $product_row) + .toggle( $fields['cust_Availability'] != '' ) + .html('
' + $fields['cust_Availability']); + + $('.product-qty.read-only', $product_row).toggle( $fields['Type'] != this.constants['PRODUCT_TYPE_TANGIBLE'] ); + $('.product-qty:not(.read-only)', $product_row).toggle( $fields['Type'] == this.constants['PRODUCT_TYPE_TANGIBLE'] ); + + + // update product specific disocunt + $('.item-price', $discount_container).html( this.formatPrice($fields['FlatPrice']) ); + $('.item-discount', $discount_container).html( '- ' + this.formatPrice($discount) ); + $discount_container.toggle( $discount > 0 ); + + // update product prices + $('.price-cell', $product_row).html( this.formatPrice($fields['Price']) ); + $('.extended-price-cell', $product_row).html( this.formatPrice($fields['Quantity'] * $fields['Price']) ); + } +} + +ShopCartManager.prototype.showErrors = function ($data) { + var $error_code = 0, $error_info = [], + $row_index = '', $field = '', + $tooltip_options = '', + $coupon_error_code = this.getErrorByType('OrderCheckoutErrorType::COUPON', $data), + $gift_certificate_error_code = this.getErrorByType('OrderCheckoutErrorType::GIFT_CERTIFICATE', $data), + $discount_error_code = this.getErrorByType('OrderCheckoutErrorType::DISCOUNT', $data); + + this.destroyTooltips(); + + if ( $.isArray($data.errors) ) { + // when no error, then it's array + return ; + } + + if ( $coupon_error_code ) { + if ( $coupon_error_code == this.constants['OrderCheckoutError::COUPON_APPLIED'] ) { + var $input = $('.coupon-name', '#coupon-row'); + } + else { + var $input = $('.coupon-code:input', '#coupon-row'); + } + + $tooltip_options = this.getCouponErrorOptions($coupon_error_code); + + if ( $tooltip_options ) { + this.tooltips.push( $input.qtip($tooltip_options) ); + } + } + + if ( $gift_certificate_error_code ) { + if ( $gift_certificate_error_code == this.constants['OrderCheckoutError::GC_APPLIED'] ) { + var $input = $('.gift-certificate-discount', '#gift-certificate-row'); + } + else { + var $input = $('.gift-certificate-code:input', '#gift-certificate-row'); + } + + $tooltip_options = this.getGiftCertificateErrorOptions($gift_certificate_error_code); + + if ( $tooltip_options ) { + this.tooltips.push( $input.qtip($tooltip_options) ); + } + } + + if ( $discount_error_code ) { + $input = $('#sub-total'); + + $tooltip_options = this.getDiscountErrorOptions($discount_error_code); + + if ( $tooltip_options ) { + this.tooltips.push( $input.qtip($tooltip_options) ); + } + } + + for (var $error_type in $data.errors) { + $tooltip_options = ''; + $error_info = $error_type.split(':'); + $error_code = parseInt( $data.errors[$error_type] ); + + if ( $error_info[0] == this.constants['OrderCheckoutErrorType::PRODUCT'] ) { + this.processProductError($error_info, $error_code, $data); + } + + console.log('error_type: ', $error_type, '; error_code: ', $error_code, '; row_index: ', $row_index, '; field: ', $field); + } +} + +ShopCartManager.prototype.showFooter = function ($data) { + var $discount_total = $data.order['DiscountTotal']; + + // update "Total Savings" + $('#discount-row, #discount-row-separator').toggle( $discount_total > 0 ); + $('.price1', '#discount-row').html( this.formatPrice($discount_total) ); + + // update Coupon Info + if ( $data.order['CouponId'] == 0 ) { + $('.coupon-code', '#coupon-row').val(''); + } + + $('.used', '#coupon-row').toggle( $data.order['CouponId'] > 0 ); + $('.not-used', '#coupon-row').toggle( $data.order['CouponId'] == 0 ); + $('.coupon-name', '#coupon-row').html( $data.order['CouponName'] ); + + // update Gift Certificate Info + if ( $data.order['GiftCertificateId'] == 0 ) { + $('.gift-certificate-code', '#gift-certificate-row').val(''); + } + + $('.used', '#gift-certificate-row').toggle( $data.order['GiftCertificateId'] > 0 ); + $('.not-used', '#gift-certificate-row').toggle( $data.order['GiftCertificateId'] == 0 ); + $('.gift-certificate-discount', '#gift-certificate-row').html( this.formatPrice($data.order['GiftCertificateDiscount']) ); + + // update "subtotal" + $('#sub-total').html( this.formatPrice($data.order['SubTotal']) ); +} + +ShopCartManager.prototype.processProductError = function ($error_info, $error_code, $data) { + var $error_type = $error_info.shift(), + $field = $error_info.pop(), + $row_index = $error_info.join(':'); + + if ( this.getRowByIndex($row_index).length == 0 ) { + // row was deleted + return ; + } + + if ( $field == 'Quantity' ) { + var $input = $('.product-qty:input', this.getRowByIndex($row_index)), + $allow_qty_replace = [ + this.constants['OrderCheckoutError::FIELD_UPDATE_SUCCESS'], + this.constants['OrderCheckoutError::QTY_CHANGED_TO_MINIMAL'] + ]; + + if ( in_array($error_code, $allow_qty_replace) && $input.val() != $data.items[$row_index]['fields']['Quantity'] ) { + // qty changed during ord:OnRecalculateItems + $input.val( $data.items[$row_index]['fields']['Quantity'] ); + } + + $tooltip_options = this.getQtyErrorOptions($error_code); + + if ( $tooltip_options ) { + this.tooltips.push( $input.qtip($tooltip_options) ); + } + } +} + +ShopCartManager.prototype.getErrorByType = function ($contant_name, $data) { + var $error_type = this.constants[$contant_name]; + + return $data.errors[$error_type] !== undefined ? $data.errors[$error_type] : false; +} + +ShopCartManager.prototype.getRowByIndex = function ($row_index) { + return $("tr.shop-cart-row[row_index='" + $row_index + "']", '#shop-cart-table'); +} + +ShopCartManager.prototype.getOldRows = function () { + var $ret = []; + + $('tr.shop-cart-row', '#shop-cart-table').each( + function () { + $ret.push( $(this).attr('row_index') ); + } + ); + + return $ret; +} + +ShopCartManager.prototype.getNewRows = function ($data) { + var $ret = []; + + if ( $.isArray($data.items) ) { + return $data.items; + } + + for (var $row_index in $data.items) { + $ret.push( $row_index ); + } + + return $ret; +} + +ShopCartManager.prototype.formatPrice = function ($price) { + // TODO: format currency + return this.currencyMask.replace('%s', $price.toFixed(2)); +} + +ShopCartManager.prototype.getQtyErrorOptions = function ($error_code) { + var $ret = false; + + switch ($error_code) { + case this.constants['OrderCheckoutError::FIELD_UPDATE_SUCCESS']: + $ret = this.getTooltipOptions('FIELD_UPDATE_SUCCESS', 'ui-tooltip-green'); + break; + + case this.constants['OrderCheckoutError::FIELD_UPDATE_ERROR']: + $ret = this.getTooltipOptions('FIELD_UPDATE_ERROR', 'ui-tooltip-red'); + break; + + case this.constants['OrderCheckoutError::QTY_UNAVAILABLE']: + $ret = this.getTooltipOptions('QTY_UNAVAILABLE', 'ui-tooltip-red'); + break; + + case this.constants['OrderCheckoutError::QTY_OUT_OF_STOCK']: + $ret = this.getTooltipOptions('QTY_OUT_OF_STOCK', 'ui-tooltip-red'); + break; + + case this.constants['OrderCheckoutError::QTY_CHANGED_TO_MINIMAL']: + $ret = this.getTooltipOptions('QTY_CHANGED_TO_MINIMAL', 'ui-tooltip-green'); + break; + } + + return $ret; +} + +ShopCartManager.prototype.getCouponErrorOptions = function ($error_code) { + var $ret = false; + + switch ($error_code) { + case this.constants['OrderCheckoutError::COUPON_APPLIED']: // for label + $ret = this.getTooltipOptions('COUPON_APPLIED', 'ui-tooltip-green'); + break; + + // all next error for input + case this.constants['OrderCheckoutError::COUPON_REMOVED']: + $ret = this.getTooltipOptions('COUPON_REMOVED', 'ui-tooltip-green'); + break; + + case this.constants['OrderCheckoutError::COUPON_REMOVED_AUTOMATICALLY']: + $ret = this.getTooltipOptions('COUPON_REMOVED_AUTOMATICALLY', 'ui-tooltip-green'); + break; + + case this.constants['OrderCheckoutError::COUPON_CODE_INVALID']: + $ret = this.getTooltipOptions('COUPON_CODE_INVALID', 'ui-tooltip-red'); + break; + + case this.constants['OrderCheckoutError::COUPON_CODE_EXPIRED']: + $ret = this.getTooltipOptions('COUPON_CODE_EXPIRED', 'ui-tooltip-red'); + break; + } + + return $ret; +} + +ShopCartManager.prototype.getGiftCertificateErrorOptions = function ($error_code) { + var $ret = false; + + switch ($error_code) { + case this.constants['OrderCheckoutError::GC_APPLIED']: // for label + $ret = this.getTooltipOptions('GC_APPLIED', 'ui-tooltip-green'); + break; + + // all next error for input + case this.constants['OrderCheckoutError::GC_REMOVED']: + $ret = this.getTooltipOptions('GC_REMOVED', 'ui-tooltip-green'); + break; + + case this.constants['OrderCheckoutError::GC_REMOVED_AUTOMATICALLY']: + $ret = this.getTooltipOptions('GC_REMOVED_AUTOMATICALLY', 'ui-tooltip-green'); + break; + + case this.constants['OrderCheckoutError::GC_CODE_INVALID']: + $ret = this.getTooltipOptions('GC_CODE_INVALID', 'ui-tooltip-red'); + break; + + case this.constants['OrderCheckoutError::GC_CODE_EXPIRED']: + $ret = this.getTooltipOptions('GC_CODE_EXPIRED', 'ui-tooltip-red'); + break; + } + + return $ret; +} + +ShopCartManager.prototype.getDiscountErrorOptions = function ($error_code) { + var $ret = false; + + switch ($error_code) { + case this.constants['OrderCheckoutError::DISCOUNT_APPLIED']: + $ret = this.getTooltipOptions('DISCOUNT_APPLIED', 'ui-tooltip-green'); + $ret.position.my = 'top right'; + break; + + case this.constants['OrderCheckoutError::DISCOUNT_REMOVED']: + $ret = this.getTooltipOptions('DISCOUNT_REMOVED', 'ui-tooltip-green'); + $ret.position.my = 'top right'; + break; + } + + return $ret; +} + +ShopCartManager.prototype.getTooltipOptions = function ($text, $css_classes) { + return { + content: {text: $text}, + position: {my: 'top left', at: 'bottom center'}, + show: {when: false, ready: true}, + hide: {event: 'focus', inactive: 2500}, + style: {classes: $css_classes} + }; +} Property changes on: in-commerce\inc\cart_manager.js ___________________________________________________________________ Added: svn:eol-style + LF Index: platform/elements/html_head.elm.tpl =================================================================== --- platform/elements/html_head.elm.tpl (revision 14590) +++ platform/elements/html_head.elm.tpl (working copy) @@ -13,9 +13,9 @@ - + - + Index: platform/inc/jquery/qtip/jquery.qtip.css =================================================================== --- platform/inc/jquery/qtip/jquery.qtip.css (revision 0) +++ platform/inc/jquery/qtip/jquery.qtip.css (revision 0) @@ -0,0 +1,539 @@ +/* +* 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: Sun Aug 14 05:10:00 PDT 2011 +*/ + +/* Core qTip styles */ +.ui-tooltip, .qtip{ + position: absolute; + left: -28000px; + top: -28000px; + display: none; + + max-width: 280px; + min-width: 50px; + + font-size: 10.5px; + line-height: 12px; + + z-index: 15000; +} + + /* Fluid class for determining actual width in IE */ + .ui-tooltip-fluid{ + display: block; + visibility: hidden; + position: static !important; + float: left !important; + } + + .ui-tooltip-content{ + position: relative; + padding: 5px 9px; + overflow: hidden; + + border-width: 1px; + border-style: solid; + + text-align: left; + word-wrap: break-word; + overflow: hidden; + } + + .ui-tooltip-titlebar{ + position: relative; + min-height: 14px; + padding: 5px 35px 5px 10px; + overflow: hidden; + + border-width: 1px 1px 0; + border-style: solid; + + font-weight: bold; + } + + .ui-tooltip-titlebar + .ui-tooltip-content{ border-top-width: 0px !important; } + + /*! Default close button class */ + .ui-tooltip-titlebar .ui-state-default{ + position: absolute; + right: 4px; + top: 50%; + margin-top: -9px; + + cursor: pointer; + outline: medium none; + + border-width: 1px; + border-style: solid; + } + + * html .ui-tooltip-titlebar .ui-state-default{ top: 16px; } /* IE fix */ + + .ui-tooltip-titlebar .ui-icon, + .ui-tooltip-icon .ui-icon{ + display: block; + text-indent: -1000em; + } + + .ui-tooltip-icon, .ui-tooltip-icon .ui-icon{ + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; + } + + .ui-tooltip-icon .ui-icon{ + width: 18px; + height: 14px; + + text-align: center; + text-indent: 0; + font: normal bold 10px/13px Tahoma,sans-serif; + + color: inherit; + background: transparent none no-repeat -100em -100em; + } + + +/* Applied to 'focused' tooltips e.g. most recently displayed/interacted with */ +.ui-tooltip-focus{ + +} + +/* Applied on hover of tooltips i.e. added/removed on mouseenter/mouseleave respectively */ +.ui-tooltip-hover{ + +} + + +/*! Default tooltip style */ +.ui-tooltip-default .ui-tooltip-titlebar, +.ui-tooltip-default .ui-tooltip-content{ + border-color: #F1D031; + background-color: #FFFFA3; + color: #555; +} + + .ui-tooltip-default .ui-tooltip-titlebar{ + background-color: #FFEF93; + } + + .ui-tooltip-default .ui-tooltip-icon{ + border-color: #CCC; + background: #F1F1F1; + color: #777; + } + + .ui-tooltip-default .ui-tooltip-titlebar .ui-state-hover{ + border-color: #AAA; + color: #111; + } + +/* Tips plugin */ +.ui-tooltip .ui-tooltip-tip{ + margin: 0 auto; + overflow: hidden; + + background: transparent !important; + border: 0px dashed transparent !important; + z-index: 10; +} + + .ui-tooltip .ui-tooltip-tip, + .ui-tooltip .ui-tooltip-tip *{ + position: absolute; + + line-height: 0.1px !important; + font-size: 0.1px !important; + color: #123456; + + background: transparent; + border: 0px dashed transparent; + } + + .ui-tooltip .ui-tooltip-tip canvas{ top: 0; left: 0; } + + +/*! Light tooltip style */ +.ui-tooltip-light .ui-tooltip-titlebar, +.ui-tooltip-light .ui-tooltip-content{ + border-color: #E2E2E2; + color: #454545; +} + + .ui-tooltip-light .ui-tooltip-content{ + background-color: white; + } + + .ui-tooltip-light .ui-tooltip-titlebar{ + background-color: #f1f1f1; + } + + +/*! Dark tooltip style */ +.ui-tooltip-dark .ui-tooltip-titlebar, +.ui-tooltip-dark .ui-tooltip-content{ + border-color: #303030; + color: #f3f3f3; +} + + .ui-tooltip-dark .ui-tooltip-content{ + background-color: #505050; + } + + .ui-tooltip-dark .ui-tooltip-titlebar{ + background-color: #404040; + } + + .ui-tooltip-dark .ui-tooltip-icon{ + border-color: #444; + } + + .ui-tooltip-dark .ui-tooltip-titlebar .ui-state-hover{ + border-color: #303030; + } + + +/*! Cream tooltip style */ +.ui-tooltip-cream .ui-tooltip-titlebar, +.ui-tooltip-cream .ui-tooltip-content{ + border-color: #F9E98E; + color: #A27D35; +} + + .ui-tooltip-cream .ui-tooltip-content{ + background-color: #FBF7AA; + } + + .ui-tooltip-cream .ui-tooltip-titlebar{ + background-color: #F0DE7D; + } + + .ui-tooltip-cream .ui-state-default .ui-tooltip-icon{ + background-position: -82px 0; + } + + +/*! Red tooltip style */ +.ui-tooltip-red .ui-tooltip-titlebar, +.ui-tooltip-red .ui-tooltip-content{ + border-color: #D95252; + color: #912323; +} + + .ui-tooltip-red .ui-tooltip-content{ + background-color: #F78B83; + } + + .ui-tooltip-red .ui-tooltip-titlebar{ + background-color: #F06D65; + } + + .ui-tooltip-red .ui-state-default .ui-tooltip-icon{ + background-position: -102px 0; + } + + .ui-tooltip-red .ui-tooltip-icon{ + border-color: #D95252; + } + + .ui-tooltip-red .ui-tooltip-titlebar .ui-state-hover{ + border-color: #D95252; + } + + +/*! Green tooltip style */ +.ui-tooltip-green .ui-tooltip-titlebar, +.ui-tooltip-green .ui-tooltip-content{ + border-color: #90D93F; + color: #3F6219; +} + + .ui-tooltip-green .ui-tooltip-content{ + background-color: #CAED9E; + } + + .ui-tooltip-green .ui-tooltip-titlebar{ + background-color: #B0DE78; + } + + .ui-tooltip-green .ui-state-default .ui-tooltip-icon{ + background-position: -42px 0; + } + + +/*! Blue tooltip style */ +.ui-tooltip-blue .ui-tooltip-titlebar, +.ui-tooltip-blue .ui-tooltip-content{ + border-color: #ADD9ED; + color: #5E99BD; +} + + .ui-tooltip-blue .ui-tooltip-content{ + background-color: #E5F6FE; + } + + .ui-tooltip-blue .ui-tooltip-titlebar{ + background-color: #D0E9F5; + } + + .ui-tooltip-blue .ui-state-default .ui-tooltip-icon{ + background-position: -2px 0; + } + +/*! Add shadows to your tooltips in: FF3+, Chrome 2+, Opera 10.6+, IE6+, Safari 2+ */ +.ui-tooltip-shadow{ + -webkit-box-shadow: 1px 1px 3px 1px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 1px 1px 3px 1px rgba(0, 0, 0, 0.15); + box-shadow: 1px 1px 3px 1px rgba(0, 0, 0, 0.15); +} + + .ui-tooltip-shadow .ui-tooltip-titlebar, + .ui-tooltip-shadow .ui-tooltip-content{ + filter: progid:DXImageTransform.Microsoft.Shadow(Color='gray', Direction=135, Strength=3); + -ms-filter:"progid:DXImageTransform.Microsoft.Shadow(Color='gray', Direction=135, Strength=3)"; + + _margin-bottom: -3px; /* IE6 */ + .margin-bottom: -3px; /* IE7 */ + } + + +/*! Add rounded corners to your tooltips in: FF3+, Chrome 2+, Opera 10.6+, IE9+, Safari 2+ */ +.ui-tooltip-rounded, +.ui-tooltip-rounded .ui-tooltip-content, +.ui-tooltip-tipsy, +.ui-tooltip-tipsy .ui-tooltip-content, +.ui-tooltip-youtube, +.ui-tooltip-youtube .ui-tooltip-content{ + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; +} + +.ui-tooltip-rounded .ui-tooltip-titlebar, +.ui-tooltip-tipsy .ui-tooltip-titlebar, +.ui-tooltip-youtube .ui-tooltip-titlebar{ + -moz-border-radius: 5px 5px 0 0; + -webkit-border-radius: 5px 5px 0 0; + border-radius: 5px 5px 0 0; +} + +.ui-tooltip-rounded .ui-tooltip-titlebar + .ui-tooltip-content, +.ui-tooltip-tipsy .ui-tooltip-titlebar + .ui-tooltip-content, +.ui-tooltip-youtube .ui-tooltip-titlebar + .ui-tooltip-content{ + -moz-border-radius: 0 0 5px 5px; + -webkit-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; +} + + +/*! Youtube tooltip style */ +.ui-tooltip-youtube{ + -webkit-box-shadow: 0 0 3px #333; + -moz-box-shadow: 0 0 3px #333; + box-shadow: 0 0 3px #333; +} + + .ui-tooltip-youtube .ui-tooltip-titlebar, + .ui-tooltip-youtube .ui-tooltip-content{ + _margin-bottom: 0; /* IE6 */ + .margin-bottom: 0; /* IE7 */ + + background: transparent; + background: rgba(0, 0, 0, 0.85); + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000)"; + + color: white; + border-color: #CCCCCC; + } + + .ui-tooltip-youtube .ui-tooltip-icon{ + border-color: #222; + } + + .ui-tooltip-youtube .ui-tooltip-titlebar .ui-state-hover{ + border-color: #303030; + } + + +/* jQuery TOOLS Tooltip style */ +.ui-tooltip-jtools{ + background: #232323; + background: rgba(0, 0, 0, 0.7); + background-image: -moz-linear-gradient(top, #717171, #232323); + background-image: -webkit-gradient(linear, left top, left bottom, from(#717171), to(#232323)); + + border: 2px solid #ddd; + border: 2px solid rgba(241,241,241,1); + + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + border-radius: 2px; + + -webkit-box-shadow: 0 0 12px #333; + -moz-box-shadow: 0 0 12px #333; + box-shadow: 0 0 12px #333; +} + + /* IE Specific */ + .ui-tooltip-jtools .ui-tooltip-titlebar{ + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171,endColorstr=#4A4A4A); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171,endColorstr=#4A4A4A)"; + } + .ui-tooltip-jtools .ui-tooltip-content{ + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A,endColorstr=#232323); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A,endColorstr=#232323)"; + } + + .ui-tooltip-jtools .ui-tooltip-titlebar, + .ui-tooltip-jtools .ui-tooltip-content{ + background: transparent; + color: white; + border: 0 dashed transparent; + } + + .ui-tooltip-jtools .ui-tooltip-icon{ + border-color: #555; + } + + .ui-tooltip-jtools .ui-tooltip-titlebar .ui-state-hover{ + border-color: #333; + } + + +/* Cluetip style */ +.ui-tooltip-cluetip{ + -webkit-box-shadow: 4px 4px 5px rgba(0, 0, 0, 0.4); + -moz-box-shadow: 4px 4px 5px rgba(0, 0, 0, 0.4); + box-shadow: 4px 4px 5px rgba(0, 0, 0, 0.4); +} + + .ui-tooltip-cluetip .ui-tooltip-titlebar{ + background-color: #87876A; + color: white; + border: 0 dashed transparent; + } + + .ui-tooltip-cluetip .ui-tooltip-content{ + background-color: #D9D9C2; + color: #111; + border: 0 dashed transparent; + } + + .ui-tooltip-cluetip .ui-tooltip-icon{ + border-color: #808064; + } + + .ui-tooltip-cluetip .ui-tooltip-titlebar .ui-state-hover{ + border-color: #696952; + color: #696952; + } + + +/* Tipsy style */ +.ui-tooltip-tipsy{ + border: 0; +} + + .ui-tooltip-tipsy .ui-tooltip-titlebar, + .ui-tooltip-tipsy .ui-tooltip-content{ + _margin-bottom: 0; /* IE6 */ + .margin-bottom: 0; /* IE7 */ + + background: transparent; + background: rgba(0, 0, 0, .87); + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000)"; + + color: white; + border: 0px transparent; + + font-size: 11px; + font-family: 'Lucida Grande', sans-serif; + font-weight: bold; + line-height: 16px; + text-shadow: 0 1px black; + } + + .ui-tooltip-tipsy .ui-tooltip-titlebar{ + padding: 6px 35px 0 10; + } + + .ui-tooltip-tipsy .ui-tooltip-content{ + padding: 6px 10; + } + + .ui-tooltip-tipsy .ui-tooltip-icon{ + border-color: #222; + text-shadow: none; + } + + .ui-tooltip-tipsy .ui-tooltip-titlebar .ui-state-hover{ + border-color: #303030; + } + + +/* Tipped style */ +.ui-tooltip-tipped{ + +} + + .ui-tooltip-tipped .ui-tooltip-titlebar, + .ui-tooltip-tipped .ui-tooltip-content{ + border: 3px solid #959FA9; + + filter: none; -ms-filter: none; + } + + .ui-tooltip-tipped .ui-tooltip-titlebar{ + background: #3A79B8; + background-image: -moz-linear-gradient(top, #3A79B8, #2E629D); + background-image: -webkit-gradient(linear, left top, left bottom, from(#3A79B8), to(#2E629D)); + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8,endColorstr=#2E629D); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8,endColorstr=#2E629D)"; + + color: white; + font-weight: normal; + font-family: serif; + + border-bottom-width: 0; + -moz-border-radius: 3px 3px 0 0; + -webkit-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; + } + + .ui-tooltip-tipped .ui-tooltip-content{ + background-color: #F9F9F9; + color: #454545; + + -moz-border-radius: 0 0 3px 3px; + -webkit-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + } + + .ui-tooltip-tipped .ui-tooltip-icon{ + border: 2px solid #285589; + background: #285589; + } + + .ui-tooltip-tipped .ui-tooltip-icon .ui-icon{ + background-color: #FBFBFB; + color: #555; + } + +/* IE9 fix - removes all filters */ +.ui-tooltip:not(.ie9haxors) div.ui-tooltip-content, +.ui-tooltip:not(.ie9haxors) div.ui-tooltip-titlebar{ + filter: none; + -ms-filter: none; +} Property changes on: platform\inc\jquery\qtip\jquery.qtip.css ___________________________________________________________________ Added: svn:eol-style + LF Index: platform/inc/jquery/qtip/jquery.qtip.js =================================================================== --- platform/inc/jquery/qtip/jquery.qtip.js (revision 0) +++ platform/inc/jquery/qtip/jquery.qtip.js (revision 0) @@ -0,0 +1,2712 @@ +/* +* 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: Sun Aug 14 05:10:00 PDT 2011 +*/ + +/*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 */ + + +(function($, window, undefined) { + + "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, + + // 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('object' !== typeof opts.metadata) { + opts.metadata = { + type: opts.metadata + }; + } + + if('content' in opts) { + if('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('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('object' !== typeof opts.position) { + opts.position = { + my: opts.position, + at: opts.position + }; + } + } + + if('show' in opts) { + if('object' !== typeof opts.show) { + if(opts.show.jquery) { + opts.show = { target: opts.show }; + } + else { + opts.show = { event: opts.show }; + } + } + } + + if('hide' in opts) { + if('object' !== typeof opts.hide) { + if(opts.hide.jquery) { + opts.hide = { target: opts.hide }; + } + else { + opts.hide = { event: opts.hide }; + } + } + } + + if('style' in opts) { + if('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 + }; + + /* + * 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, !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 ' + (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') + .hover(function(event){ $(this).toggleClass('ui-state-hover', event.type === 'mouseenter'); }) + .click(function(event) { + if(!tooltip.hasClass(disabled)) { self.hide(event); } + return FALSE; + }) + .bind('mousedown keydown mouseup keyup mouseout', function(event) { + $(this).toggleClass('ui-state-active ui-state-focus', event.type.substr(-4) === 'down'); + }); + + // 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); + + // 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 + if(content === FALSE) { 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.is(':visible')) { + 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: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; } + + (function timer(){ + // When the dimensions are found, remove the image from the queue + if(elem.height || elem.width) { return imageLoad(elem); } + + // Restart timer + 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), + 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; } + + // If set, hide tooltip when inactive for delay period + targets.show.trigger('qtip-'+id+'-inactive'); + + // 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)))) { + event.preventDefault(); event.stopImmediatePropagation(); 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(tooltip.is(':visible')) { 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, 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) { + targets.document.bind('mousedown'+namespace, function(event) { + var $target = $(event.target), + enabled = !tooltip.hasClass(disabled) && tooltip.is(':visible'); + + if($target[0] !== tooltip[0] && $target.parents(selector).length === 0 && $target.add(target).length > 1) { + 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.is(':visible')) { 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) { + tooltip.bind('mouseleave'+namespace, function(event) { + if((event.relatedTarget || event.target) !== targets.show[0]) { self.hide(event); } + }); + } + + // 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(!tooltip.hasClass(disabled) && tooltip.is(':visible')) { + 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 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, + '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; + + // Update title + if(title) { + createTitle(); + updateTitle(title, FALSE); + } + + // Set proper rendered flag and update content + updateContent(options.content.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); + } + + 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(tooltip.is(':visible') && self.rendered) { + if(reposition) { + self.reposition( options.position.target === 'mouse' ? NULL : cache.event ); + } + if(redraw) { self.redraw(); } + } + + return self; + }, + + toggle: function(state, event) + { + // Make sure tooltip is rendered + if(!self.rendered) { + if(state) { self.render(1); } // Render the tooltip if showing and it isn't already + else { return self; } + } + + var type = state ? 'show' : 'hide', + opts = options[type], + visible = tooltip.is(':visible'), + sameTarget = !event || options[type].target.length < 2 || cache.target[0] === event.target, + posOptions = options.position, + contentOptions = options.content, + 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) && + event.target === options.show.target[0] && 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); + + // Hide other tooltips if tooltip is solo, using it as the context + if(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(); + } + + // Call API method + callback = $.Event('tooltipvisible'); + callback.originalEvent = event ? cache.event : NULL; + tooltip.trigger(callback, [self]); + } + else { + // Reset CSS states + tooltip.css({ + display: '', + visibility: '', + opacity: '', + left: '', + top: '' + }); + } + } + + // Clear animation queue if same target + if(sameTarget) { tooltip.stop(0, 1); } + + // If no effect type is supplied, use a simple toggle + if(opts.effect === FALSE) { + tooltip[ type ](); + after.call(tooltip); + } + + // Use custom function if provided + else if($.isFunction(opts.effect)) { + 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 }, + tip = self.plugins.tip, + readjust = { + // Repositioning method and axis detection + horizontal: method[0], + vertical: method[1] || method[0], + + // Reposition methods + left: function(posLeft) { + var isShift = readjust.horizontal === 'shift', + viewportScroll = 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), + 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( + viewport.offset.left + (tipAdjust && tip.corner.x === 'center' ? tip.offset : 0), + posLeft - offset, + Math.min( + Math.max(viewport.offset.left + viewport.width, posLeft + offset), + position.left + ) + ); + } + + // Default 'flip' repositioning + else { + if(overflowLeft > 0 && (my.x !== 'left' || overflowRight > 0)) { + position.left -= offset + (isCenter ? 0 : 2 * adjust.x); + } + else if(overflowRight > 0 && (my.x !== 'right' || overflowLeft > 0) ) { + position.left -= isCenter ? -offset : offset + (2 * adjust.x); + } + 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 = 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), + 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( + viewport.offset.top + (tipAdjust && tip.corner.x === 'center' ? tip.offset : 0), + posTop - offset, + Math.min( + Math.max(viewport.offset.top + viewport.height, posTop + offset), + position.top + ) + ); + } + + // Default 'flip' repositioning + else { + if(overflowTop > 0 && (my.y !== 'top' || overflowBottom > 0)) { + position.top -= offset + (isCenter ? 0 : 2 * adjust.y); + } + else if(overflowBottom > 0 && (my.y !== 'bottom' || overflowTop > 0) ) { + position.top -= isCenter ? -offset : offset + (2 * adjust.y); + } + 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; + } + }; + + // 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 ? 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 { cache.target = $(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: !fixed || PLUGINS.iOS ? (viewport || target).scrollTop() : 0, + left: !fixed || PLUGINS.iOS ? (viewport || target).scrollLeft() : 0 + }; + } + } + + // Use Imagemap/SVG plugins if needed + else if(target.is('area') && PLUGINS.imagemap) { + position = PLUGINS.imagemap(target, at); + } + 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, posOptions.container, fixed); + } + + // Parse returned plugin values into proper variables + if(position.offset) { + targetWidth = position.width; + targetHeight = position.height; + position = position.offset; + } + + // 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(viewport.jquery && target[0] !== window && target[0] !== docBody && + readjust.vertical+readjust.horizontal !== 'nonenone') + { + // 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 } + }; + + // 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 + }; + } + + //Viewport adjustment is disabled, set values to zero + else { position.adjusted = { left: 0, top: 0 }; } + + // Set tooltip position class + tooltip.attr('class', function(i, val) { + return $.attr(this, 'class').replace(/ui-tooltip-pos-\w+/i, ''); + }) + .addClass(uitooltip + '-pos-' + my.abbreviation()); + + // 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 || 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); + + // Destroy tooltip and any associated plugins if rendered + if(self.rendered) { + tooltip.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(); + + // 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 and bound qtip events + target.removeAttr('aria-describedby').unbind('.qtip'); + + // 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 === FALSE) { 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 = docBody; } + if(config.hide.target === FALSE) { config.hide.target = newTarget; } + if(config.position.viewport === TRUE) { config.position.viewport = posOptions.container; } + + // 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 events on target element to destroy redundant tooltip + elem.bind('remove.qtip', 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 = command === 'disable' ? [TRUE] : $.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. + */ + targets.show.bind('mousemove'+namespace, function(event) { + MOUSE = { pageX: event.pageX, pageY: event.pageY, type: 'mousemove' }; + }); + + // 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(); + + this.precedance = (corner.charAt(0).search(/^(t|b)/) > -1) ? 'y' : 'x'; + this.string = function() { return this.precedance === 'y' ? this.y+this.x : this.x+this.y; }; + this.abbreviation = 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; + }; + }, + + // Custom (more correct for qTip!) offset calculator + offset: function(elem, container, fixed) { + var pos = elem.offset(), + parent = container, + deep = 0, + docBody = document.body, + coffset; + + 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[0] === docBody ? + { left: parseInt(parent.css('left'), 10) || 0, top: parseInt(parent.css('top'), 10) || 0 } : + parent.position(); + + 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); + + deep++; + } + if(parent[0] === docBody) { break; } + } + while(parent = parent.offsetParent()); + + // Compensate for containers scroll if it also has an offsetParent + if(container[0] !== docBody && deep > 1) { scroll( container, 1 ); } + + // 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 && fixed)) { scroll( $(window), -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 && '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; + }, + + /* + * Taken directly from jQuery 1.8.2 widget source code + * Trigger 'remove' event on all elements on removal if jQuery UI isn't present + */ + remove: $.ui ? NULL : function( selector, keepData ) { + $(this).each(function() { + if (!keepData) { + if (!selector || $.filter( selector, [ this ] ).length) { + $('*', this).add(this).each(function() { + $(this).triggerHandler('remove'); + }); + } + } + }); + } + } +}; + +// Apply the fn overrides above +$.each(PLUGINS.fn, function(name, func) { + if(!func) { return TRUE; } + + var old = $.fn[name+replaceSuffix] = $.fn[name]; + $.fn[name] = function() { + return func.apply(this, arguments) || old.apply(this, arguments); + }; +}); + +// 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 + }, + events: { + render: NULL, + move: NULL, + show: NULL, + hide: NULL, + toggle: NULL, + visible: NULL, + focus: NULL, + blur: NULL + } +}; + +function Ajax(api) +{ + var self = this, + tooltip = api.elements.tooltip, + opts = api.options.content.ajax, + namespace = '.qtip-ajax', + rscript = /)<[^<]*)*<\/script>/gi, + first = TRUE; + + api.checks.ajax = { + '^content.ajax': function(obj, name, v) { + // If content.ajax object was reset, set our local var + if(name === 'ajax') { opts = v; } + + if(name === 'once') { + self.init(); + } + else if(opts && opts.url) { + self.load(); + } + else { + tooltip.unbind(namespace); + } + } + }; + + $.extend(self, { + init: function() + { + // Make sure ajax options are enabled and bind event + if(opts && opts.url) { + tooltip.unbind(namespace)[ opts.once ? 'one' : 'bind' ]('tooltipshow'+namespace, self.load); + } + + return self; + }, + + load: function(event, first) + { + // Make sure default event hasn't been prevented + if(event && event.isDefaultPrevented()) { return self; } + + var hasSelector = opts.url.indexOf(' '), + url = opts.url, + selector, + hideFirst = opts.once && !opts.loading && first; + + // If loading option is disabled, hide the tooltip until content is retrieved (first time only) + if(hideFirst) { tooltip.css('visibility', 'hidden'); } + + // Check if user delcared a content selector like in .load() + if(hasSelector > -1) { + selector = url.substr(hasSelector); + url = url.substr(0, hasSelector); + } + + // Define common after callback for both success/error handlers + function after() { + // Re-display tip if loading and first time, and reset first flag + if(hideFirst) { tooltip.css('visibility', ''); first = FALSE; } + + // Call users complete if it was defined + if($.isFunction(opts.complete)) { opts.complete.apply(this, arguments); } + } + + // Define success handler + function successHandler(content) { + if(selector) { + // Create a dummy div to hold the results and grab the selector element + content = $('
') + // inject the contents of the document in, removing the scripts + // to avoid any 'Permission Denied' errors in IE + .append(content.replace(rscript, "")) + + // Locate the specified elements + .find(selector); + } + + // Set the content + api.set('content.text', content); + } + + // Error handler + function errorHandler(xh, status, error){ api.set('content.text', status + ': ' + error); } + + // Setup $.ajax option object and process the request + $.ajax( $.extend({ success: successHandler, error: errorHandler, context: api }, opts, { url: url, complete: after }) ); + + return self; + } + }); + + self.init(); +} + + +PLUGINS.ajax = function(api) +{ + var self = api.plugins.ajax; + + return 'object' === typeof self ? self : (api.plugins.ajax = new Ajax(api)); +}; + +PLUGINS.ajax.initialize = 'render'; + +// Setup plugin sanitization +PLUGINS.ajax.sanitize = function(options) +{ + var content = options.content, opts; + if(content && 'ajax' in content) { + opts = content.ajax; + if(typeof opts !== 'object') { opts = options.content.ajax = { url: opts }; } + if('boolean' !== typeof opts.once && opts.once) { opts.once = !!opts.once; } + } +}; + +// Extend original api defaults +$.extend(TRUE, QTIP.defaults, { + content: { + ajax: { + loading: TRUE, + once: TRUE + } + } +}); + +// 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, + corner: '' + }, + size = { + width: opts.width, + height: opts.height + }, + color = { }, + border = opts.border || 0, + namespace = '.qtip-tip', + hasCanvas = !!($('')[0] || {}).getContext; + + 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 = $.extend({}, self.corner), + 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 && (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.string(); + } + + /* 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; + } + } + + return self.corner.string() !== 'centercenter'; + }, + + detectColours: function() { + var i, fill, border, + tip = elems.tip.css({ backgroundColor: '', border: '' }), + corner = 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/i, + backgroundColor = 'background-color', + transparent = 'transparent', + + 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 === contentColour) { + color.border = border; + } + } + + // Reset background and border colours + $('*', tip).add(tip).css(backgroundColor, transparent).css('border', ''); + + // 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); + } + }, + + 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 = 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(); + + // 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 + } + } +}); + +/* + * BGIFrame adaption (http://plugins.jquery.com/project/bgiframe) + * Special thanks to Brandon Aaron + */ +function BGIFrame(api) +{ + var self = this, + elems = api.elements, + tooltip = elems.tooltip, + namespace = '.bgiframe-' + api.id; + + $.extend(self, { + init: function() + { + // Create the BGIFrame element + elems.bgiframe = $(''); + + // Append the new element to the tooltip + elems.bgiframe.appendTo(tooltip); + + // Update BGIFrame on tooltip move + tooltip.bind('tooltipmove'+namespace, self.adjust); + }, + + adjust: function() + { + var dimensions = api.get('dimensions'), // Determine current tooltip dimensions + plugin = api.plugins.tip, + tip = elems.tip, + tipAdjust, offset; + + // Adjust border offset + offset = parseInt(tooltip.css('border-left-width'), 10) || 0; + offset = { left: -offset, top: -offset }; + + // Adjust for tips plugin + if(plugin && tip) { + tipAdjust = (plugin.corner.precedance === 'x') ? ['width', 'left'] : ['height', 'top']; + offset[ tipAdjust[1] ] -= tip[ tipAdjust[0] ](); + } + + // Update bgiframe + elems.bgiframe.css(offset).css(dimensions); + }, + + destroy: function() + { + // Remove iframe + elems.bgiframe.remove(); + + // Remove bound events + tooltip.unbind(namespace); + } + }); + + self.init(); +} + +PLUGINS.bgiframe = function(api) +{ + var browser = $.browser, + self = api.plugins.bgiframe; + + // Proceed only if the browser is IE6 and offending elements are present + if($('select, object').length < 1 || !(browser.msie && browser.version.charAt(0) === '6')) { + return FALSE; + } + + return 'object' === typeof self ? self : (api.plugins.bgiframe = new BGIFrame(api)); +}; + +// Plugin needs to be initialized on render +PLUGINS.bgiframe.initialize = 'render'; + + +}(jQuery, window)); Property changes on: platform\inc\jquery\qtip\jquery.qtip.js ___________________________________________________________________ Added: svn:eol-style + LF Index: platform/inc/jquery/qtip/jquery.qtip.min.js =================================================================== --- platform/inc/jquery/qtip/jquery.qtip.min.js (revision 0) +++ platform/inc/jquery/qtip/jquery.qtip.min.js (revision 0) @@ -0,0 +1,13 @@ +/* +* 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: Sun Aug 14 05:10:00 PDT 2011 +*//*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 */(function(a,b,c){function D(b){var c=this,d=b.elements,e=d.tooltip,f=".bgiframe-"+b.id;a.extend(c,{init:function(){d.bgiframe=a(''),d.bgiframe.appendTo(e),e.bind("tooltipmove"+f,c.adjust)},adjust:function(){var a=b.get("dimensions"),c=b.plugins.tip,f=d.tip,g,h;h=parseInt(e.css("border-left-width"),10)||0,h={left:-h,top:-h},c&&f&&(g=c.corner.precedance==="x"?["width","left"]:["height","top"],h[g[1]]-=f[g[0]]()),d.bgiframe.css(h).css(a)},destroy:function(){d.bgiframe.remove(),e.unbind(f)}}),c.init()}function C(b,g){function w(a){var b=a.precedance==="y",c=n[b?"width":"height"],d=n[b?"height":"width"],e=a.string().indexOf("center")>-1,f=c*(e?.5:1),g=Math.pow,h=Math.round,i,j,k,l=Math.sqrt(g(f,2)+g(d,2)),m=[p/f*l,p/d*l];m[2]=Math.sqrt(g(m[0],2)-g(p,2)),m[3]=Math.sqrt(g(m[1],2)-g(p,2)),i=l+m[2]+m[3]+(e?0:m[0]),j=i/l,k=[h(j*d),h(j*c)];return{height:k[b?0:1],width:k[b?1:0]}}function v(b){var c=k.titlebar&&b.y==="top",d=c?k.titlebar:k.content,e=a.browser.mozilla,f=e?"-moz-":a.browser.webkit?"-webkit-":"",g=b.y+(e?"":"-")+b.x,h=f+(e?"border-radius-"+g:"border-"+g+"-radius");return parseInt(d.css(h),10)||parseInt(l.css(h),10)||0}function u(a,b,c){b=b?b:a[a.precedance];var d=l.hasClass(r),e=k.titlebar&&a.y==="top",f=e?k.titlebar:k.content,g="border-"+b+"-width",h;l.addClass(r),h=parseInt(f.css(g),10),h=(c?h||parseInt(l.css(g),10):h)||0,l.toggleClass(r,d);return h}function t(f,g,h,l){if(k.tip){var n=a.extend({},i.corner),o=h.adjusted,p=b.options.position.adjust.method.split(" "),q=p[0],r=p[1]||p[0],s={left:e,top:e,x:0,y:0},t,u={},v;i.corner.fixed!==d&&(q==="shift"&&n.precedance==="x"&&o.left&&n.y!=="center"?n.precedance=n.precedance==="x"?"y":"x":q==="flip"&&o.left&&(n.x=n.x==="center"?o.left>0?"left":"right":n.x==="left"?"right":"left"),r==="shift"&&n.precedance==="y"&&o.top&&n.x!=="center"?n.precedance=n.precedance==="y"?"x":"y":r==="flip"&&o.top&&(n.y=n.y==="center"?o.top>0?"top":"bottom":n.y==="top"?"bottom":"top"),n.string()!==m.corner&&(m.top!==o.top||m.left!==o.left)&&i.update(n,e)),t=i.position(n,o),t.right!==c&&(t.left=-t.right),t.bottom!==c&&(t.top=-t.bottom),t.user=Math.max(0,j.offset);if(s.left=q==="shift"&&!!o.left)n.x==="center"?u["margin-left"]=s.x=t["margin-left"]-o.left:(v=t.right!==c?[o.left,-t.left]:[-o.left,t.left],(s.x=Math.max(v[0],v[1]))>v[0]&&(h.left-=o.left,s.left=e),u[t.right!==c?"right":"left"]=s.x);if(s.top=r==="shift"&&!!o.top)n.y==="center"?u["margin-top"]=s.y=t["margin-top"]-o.top:(v=t.bottom!==c?[o.top,-t.top]:[-o.top,t.top],(s.y=Math.max(v[0],v[1]))>v[0]&&(h.top-=o.top,s.top=e),u[t.bottom!==c?"bottom":"top"]=s.y);k.tip.css(u).toggle(!(s.x&&s.y||n.x==="center"&&s.y||n.y==="center"&&s.x)),h.left-=t.left.charAt?t.user:q!=="shift"||s.top||!s.left&&!s.top?t.left:0,h.top-=t.top.charAt?t.user:r!=="shift"||s.left||!s.left&&!s.top?t.top:0,m.left=o.left,m.top=o.top,m.corner=n.string()}}var i=this,j=b.options.style.tip,k=b.elements,l=k.tooltip,m={top:0,left:0,corner:""},n={width:j.width,height:j.height},o={},p=j.border||0,q=".qtip-tip",s=!!(a("")[0]||{}).getContext;i.corner=f,i.mimic=f,i.border=p,i.offset=j.offset,i.size=n,b.checks.tip={"^position.my|style.tip.(corner|mimic|border)$":function(){i.init()||i.destroy(),b.reposition()},"^style.tip.(height|width)$":function(){n={width:j.width,height:j.height},i.create(),i.update(),b.reposition()},"^content.title.text|style.(classes|widget)$":function(){k.tip&&i.update()}},a.extend(i,{init:function(){var b=i.detectCorner()&&(s||a.browser.msie);b&&(i.create(),i.update(),l.unbind(q).bind("tooltipmove"+q,t));return b},detectCorner:function(){var a=j.corner,c=b.options.position,f=c.at,g=c.my.string?c.my.string():c.my;if(a===e||g===e&&f===e)return e;a===d?i.corner=new h.Corner(g):a.string||(i.corner=new h.Corner(a),i.corner.fixed=d);return i.corner.string()!=="centercenter"},detectColours:function(){var c,d,e,f=k.tip.css({backgroundColor:"",border:""}),g=i.corner,h=g[g.precedance],m="border-"+h+"-color",p="border"+h.charAt(0)+h.substr(1)+"Color",q=/rgba?\(0, 0, 0(, 0)?\)|transparent/i,s="background-color",t="transparent",u=a(document.body).css("color"),v=b.elements.content.css("color"),w=k.titlebar&&(g.y==="top"||g.y==="center"&&f.position().top+n.height/2+j.offset",{"class":"ui-tooltip-tip"}).css({width:b,height:c}).prependTo(l),s?a("").appendTo(k.tip)[0].getContext("2d").save():(d='',k.tip.html(d+d))},update:function(b,c){var g=k.tip,l=g.children(),m=n.width,q=n.height,r="px solid ",t="px dashed transparent",v=j.mimic,x=Math.round,y,z,A,C,D;b||(b=i.corner),v===e?v=b:(v=new h.Corner(v),v.precedance=b.precedance,v.x==="inherit"?v.x=b.x:v.y==="inherit"?v.y=b.y:v.x===v.y&&(v[b.precedance]=b[b.precedance])),y=v.precedance,i.detectColours(),o.border!=="transparent"&&o.border!=="#123456"?(p=u(b,f,d),j.border===0&&p>0&&(o.fill=o.border),i.border=p=j.border!==d?j.border:p):i.border=p=0,A=B(v,m,q),i.size=D=w(b),g.css(D),b.precedance==="y"?C=[x(v.x==="left"?p:v.x==="right"?D.width-m-p:(D.width-m)/2),x(v.y==="top"?D.height-q:0)]:C=[x(v.x==="left"?D.width-m:0),x(v.y==="top"?p:v.y==="bottom"?D.height-q-p:(D.height-q)/2)],s?(l.attr(D),z=l[0].getContext("2d"),z.restore(),z.save(),z.clearRect(0,0,3e3,3e3),z.translate(C[0],C[1]),z.beginPath(),z.moveTo(A[0][0],A[0][1]),z.lineTo(A[1][0],A[1][1]),z.lineTo(A[2][0],A[2][1]),z.closePath(),z.fillStyle=o.fill,z.strokeStyle=o.border,z.lineWidth=p*2,z.lineJoin="miter",z.miterLimit=100,p&&z.stroke(),z.fill()):(A="m"+A[0][0]+","+A[0][1]+" l"+A[1][0]+","+A[1][1]+" "+A[2][0]+","+A[2][1]+" xe",C[2]=p&&/^(r|b)/i.test(b.string())?parseFloat(a.browser.version,10)===8?2:1:0,l.css({antialias:""+(v.string().indexOf("center")>-1),left:C[0]-C[2]*Number(y==="x"),top:C[1]-C[2]*Number(y==="y"),width:m+p,height:q+p}).each(function(b){var c=a(this);c[c.prop?"prop":"attr"]({coordsize:m+p+" "+(q+p),path:A,fillcolor:o.fill,filled:!!b,stroked:!b}).css({display:p||b?"block":"none"}),!b&&c.html()===""&&c.html('')})),c!==e&&i.position(b)},position:function(b){var c=k.tip,f={},g=Math.max(0,j.offset),h,l,m;if(j.corner===e||!c)return e;b=b||i.corner,h=b.precedance,l=w(b),m=[b.x,b.y],h==="x"&&m.reverse(),a.each(m,function(a,c){var e,i;c==="center"?(e=h==="y"?"left":"top",f[e]="50%",f["margin-"+e]=-Math.round(l[h==="y"?"width":"height"]/2)+g):(e=u(b,c,d),i=v(b),f[c]=a?p?u(b,c):0:g+(i>e?i:0))}),f[b[h]]-=l[h==="x"?"width":"height"],c.css({top:"",bottom:"",left:"",right:"",margin:""}).css(f);return f},destroy:function(){k.tip&&k.tip.remove(),l.unbind(q)}}),i.init()}function B(a,b,c){var d=Math.ceil(b/2),e=Math.ceil(c/2),f={bottomright:[[0,0],[b,c],[b,0]],bottomleft:[[0,0],[b,0],[0,c]],topright:[[0,c],[b,0],[b,c]],topleft:[[0,0],[0,c],[b,c]],topcenter:[[0,c],[d,0],[b,c]],bottomcenter:[[0,0],[b,0],[d,c]],rightcenter:[[0,0],[b,e],[0,c]],leftcenter:[[b,0],[b,c],[0,e]]};f.lefttop=f.bottomright,f.righttop=f.bottomleft,f.leftbottom=f.topright,f.rightbottom=f.topleft;return f[a.string()]}function A(b){var c=this,f=b.elements.tooltip,g=b.options.content.ajax,h=".qtip-ajax",i=/)<[^<]*)*<\/script>/gi,j=d;b.checks.ajax={"^content.ajax":function(a,b,d){b==="ajax"&&(g=d),b==="once"?c.init():g&&g.url?c.load():f.unbind(h)}},a.extend(c,{init:function(){g&&g.url&&f.unbind(h)[g.once?"one":"bind"]("tooltipshow"+h,c.load);return c},load:function(d,h){function p(a,c,d){b.set("content.text",c+": "+d)}function o(c){l&&(c=a("
").append(c.replace(i,"")).find(l)),b.set("content.text",c)}function n(){m&&(f.css("visibility",""),h=e),a.isFunction(g.complete)&&g.complete.apply(this,arguments)}if(d&&d.isDefaultPrevented())return c;var j=g.url.indexOf(" "),k=g.url,l,m=g.once&&!g.loading&&h;m&&f.css("visibility","hidden"),j>-1&&(l=k.substr(j),k=k.substr(0,j)),a.ajax(a.extend({success:o,error:p,context:b},g,{url:k,complete:n}));return c}}),c.init()}function z(b,c){var i,j,k,l,m,n=a(this),o=a(document.body),p=this===document?o:n,q=n.metadata?n.metadata(c.metadata):f,r=c.metadata.type==="html5"&&q?q[c.metadata.name]:f,s=n.data(c.metadata.name||"qtipopts");try{s=typeof s==="string"?(new Function("return "+s))():s}catch(t){w("Unable to parse HTML5 attribute data: "+s)}l=a.extend(d,{},g.defaults,c,typeof s==="object"?x(s):f,x(r||q)),j=l.position,l.id=b;if("boolean"===typeof l.content.text){k=n.attr(l.content.attr);if(l.content.attr!==e&&k)l.content.text=k;else{w("Unable to locate content for tooltip! Aborting render of tooltip on element: ",n);return e}}j.container===e&&(j.container=o),j.target===e&&(j.target=p),l.show.target===e&&(l.show.target=p),l.show.solo===d&&(l.show.solo=o),l.hide.target===e&&(l.hide.target=p),l.position.viewport===d&&(l.position.viewport=j.container),j.at=new h.Corner(j.at),j.my=new h.Corner(j.my);if(a.data(this,"qtip"))if(l.overwrite)n.qtip("destroy");else if(l.overwrite===e)return e;l.suppress&&(m=a.attr(this,"title"))&&a(this).removeAttr("title").attr(u,m),i=new y(n,l,b,!!k),a.data(this,"qtip",i),n.bind("remove.qtip",function(){i.destroy()});return i}function y(s,t,w,y){function R(){var c=[t.show.target[0],t.hide.target[0],z.rendered&&G.tooltip[0],t.position.container[0],t.position.viewport[0],b,document];z.rendered?a([]).pushStack(a.grep(c,function(a){return typeof a==="object"})).unbind(F):t.show.target.unbind(F+"-create")}function Q(){function p(a){E.is(":visible")&&z.reposition(a)}function o(a){if(E.hasClass(m))return e;clearTimeout(z.timers.inactive),z.timers.inactive=setTimeout(function(){z.hide(a)},t.hide.inactive)}function l(b){if(E.hasClass(m)||C||D)return e;var d=a(b.relatedTarget||b.target),g=d.closest(n)[0]===E[0],h=d[0]===f.show[0];clearTimeout(z.timers.show),clearTimeout(z.timers.hide);c.target==="mouse"&&g||t.hide.fixed&&(/mouse(out|leave|move)/.test(b.type)&&(g||h))?(b.preventDefault(),b.stopImmediatePropagation()):t.hide.delay>0?z.timers.hide=setTimeout(function(){z.hide(b)},t.hide.delay):z.hide(b)}function k(a){if(E.hasClass(m))return e;f.show.trigger("qtip-"+w+"-inactive"),clearTimeout(z.timers.show),clearTimeout(z.timers.hide);var b=function(){z.toggle(d,a)};t.show.delay>0?z.timers.show=setTimeout(b,t.show.delay):b()}var c=t.position,f={show:t.show.target,hide:t.hide.target,viewport:a(c.viewport),document:a(document),window:a(b)},h={show:a.trim(""+t.show.event).split(" "),hide:a.trim(""+t.hide.event).split(" ")},j=a.browser.msie&&parseInt(a.browser.version,10)===6;E.bind("mouseenter"+F+" mouseleave"+F,function(a){var b=a.type==="mouseenter";b&&z.focus(a),E.toggleClass(q,b)}),t.hide.fixed&&(f.hide=f.hide.add(E),E.bind("mouseover"+F,function(){E.hasClass(m)||clearTimeout(z.timers.hide)})),/mouse(out|leave)/i.test(t.hide.event)?t.hide.leave==="window"&&f.window.bind("mouseout"+F,function(a){/select|option/.test(a.target)&&!a.relatedTarget&&z.hide(a)}):/mouse(over|enter)/i.test(t.show.event)&&f.hide.bind("mouseleave"+F,function(a){clearTimeout(z.timers.show)}),(""+t.hide.event).indexOf("unfocus")>-1&&f.document.bind("mousedown"+F,function(b){var c=a(b.target),d=!E.hasClass(m)&&E.is(":visible");c[0]!==E[0]&&c.parents(n).length===0&&c.add(s).length>1&&z.hide(b)}),"number"===typeof t.hide.inactive&&(f.show.bind("qtip-"+w+"-inactive",o),a.each(g.inactiveEvents,function(a,b){f.hide.add(G.tooltip).bind(b+F+"-inactive",o)})),a.each(h.hide,function(b,c){var d=a.inArray(c,h.show),e=a(f.hide);d>-1&&e.add(f.show).length===e.length||c==="unfocus"?(f.show.bind(c+F,function(a){E.is(":visible")?l(a):k(a)}),delete h.show[d]):f.hide.bind(c+F,l)}),a.each(h.show,function(a,b){f.show.bind(b+F,k)}),"number"===typeof t.hide.distance&&f.show.add(E).bind("mousemove"+F,function(a){var b=H.origin||{},c=t.hide.distance,d=Math.abs;(d(a.pageX-b.pageX)>=c||d(a.pageY-b.pageY)>=c)&&z.hide(a)}),c.target==="mouse"&&(f.show.bind("mousemove"+F,function(a){i={pageX:a.pageX,pageY:a.pageY,type:"mousemove"}}),c.adjust.mouse&&(t.hide.event&&E.bind("mouseleave"+F,function(a){(a.relatedTarget||a.target)!==f.show[0]&&z.hide(a)}),f.document.bind("mousemove"+F,function(a){!E.hasClass(m)&&E.is(":visible")&&z.reposition(a||i)}))),(c.adjust.resize||f.viewport.length)&&(a.event.special.resize?f.viewport:f.window).bind("resize"+F,p),(f.viewport.length||j&&E.css("position")==="fixed")&&f.viewport.bind("scroll"+F,p)}function P(b,d){function g(b){function i(c){c&&(delete h[c.src],clearTimeout(z.timers.img[c.src]),a(c).unbind(F)),a.isEmptyObject(h)&&(z.redraw(),d!==e&&z.reposition(H.event),b())}var g,h={};if((g=f.find("img:not([height]):not([width])")).length===0)return i();g.each(function(b,d){h[d.src]===c&&(function e(){if(d.height||d.width)return i(d);z.timers.img[d.src]=setTimeout(e,700)}(),a(d).bind("error"+F+" load"+F,function(){i(this)}),h[d.src]=d)})}var f=G.content;if(!z.rendered||!b)return e;a.isFunction(b)&&(b=b.call(s,H.event,z)||""),b.jquery&&b.length>0?f.empty().append(b.css({display:"block"})):f.html(b),z.rendered<0?E.queue("fx",g):(D=0,g(a.noop));return z}function O(b,c){var d=G.title;if(!z.rendered||!b)return e;a.isFunction(b)&&(b=b.call(s,H.event,z));if(b===e)return K(e);b.jquery&&b.length>0?d.empty().append(b.css({display:"block"})):d.html(b),z.redraw(),c!==e&&z.rendered&&E.is(":visible")&&z.reposition(H.event)}function N(a){var b=G.button,c=G.title;if(!z.rendered)return e;a?(c||M(),L()):b.remove()}function M(){var b=B+"-title";G.titlebar&&K(),G.titlebar=a("
",{"class":k+"-titlebar "+(t.style.widget?"ui-widget-header":"")}).append(G.title=a("
",{id:b,"class":k+"-title","aria-atomic":d})).insertBefore(G.content),t.content.title.button?L():z.rendered&&z.redraw()}function L(){var b=t.content.title.button,c=typeof b==="string",d=c?b:"Close tooltip";G.button&&G.button.remove(),b.jquery?G.button=b:G.button=a("",{"class":"ui-state-default "+(t.style.widget?"":k+"-icon"),title:d,"aria-label":d}).prepend(a("",{"class":"ui-icon ui-icon-close",html:"×"})),G.button.appendTo(G.titlebar).attr("role","button").hover(function(b){a(this).toggleClass("ui-state-hover",b.type==="mouseenter")}).click(function(a){E.hasClass(m)||z.hide(a);return e}).bind("mousedown keydown mouseup keyup mouseout",function(b){a(this).toggleClass("ui-state-active ui-state-focus",b.type.substr(-4)==="down")}),z.redraw()}function K(a){G.title&&(G.titlebar.remove(),G.titlebar=G.title=G.button=f,a!==e&&z.reposition())}function J(){var a=t.style.widget;E.toggleClass(l,a).toggleClass(o,!a),G.content.toggleClass(l+"-content",a),G.titlebar&&G.titlebar.toggleClass(l+"-header",a),G.button&&G.button.toggleClass(k+"-icon",!a)}function I(a){var b=0,c,d=t,e=a.split(".");while(d=d[e[b++]])b0&&!a("#"+i).length&&(E[0].id=i,G.content[0].id=i+"-content",G.title[0].id=i+"-title")},"^content.text$":function(a,b,c){P(c)},"^content.title.text$":function(a,b,c){if(!c)return K();!G.title&&c&&M(),O(c)},"^content.title.button$":function(a,b,c){N(c)},"^position.(my|at)$":function(a,b,c){"string"===typeof c&&(a[b]=new h.Corner(c))},"^position.container$":function(a,b,c){z.rendered&&E.appendTo(c)},"^show.ready$":function(){z.rendered?z.toggle(d):z.render(1)},"^style.classes$":function(a,b,c){E.attr("class",k+" qtip ui-helper-reset "+c)},"^style.widget|content.title":J,"^events.(render|show|move|hide|focus|blur)$":function(b,c,d){E[(a.isFunction(d)?"":"un")+"bind"]("tooltip"+c,d)},"^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)":function(){var a=t.position;E.attr("tracking",a.target==="mouse"&&a.adjust.mouse),R(),Q()}},a.extend(z,{render:function(b){if(z.rendered)return z;var c=t.content.title.text,f=t.position,g=a.Event("tooltiprender");a.attr(s[0],"aria-describedby",B),E=G.tooltip=a("
",{id:B,"class":k+" qtip ui-helper-reset "+o+" "+t.style.classes,width:t.style.width||"",height:t.style.height||"",tracking:f.target==="mouse"&&f.adjust.mouse,role:"alert","aria-live":"polite","aria-atomic":e,"aria-describedby":B+"-content","aria-hidden":d}).toggleClass(m,H.disabled).data("qtip",z).appendTo(t.position.container).append(G.content=a("
",{"class":k+"-content",id:B+"-content","aria-atomic":d})),z.rendered=-1,D=1,C=1,c&&(M(),O(c,e)),P(t.content.text,e),z.rendered=d,J(),a.each(t.events,function(b,c){a.isFunction(c)&&E.bind(b==="toggle"?"tooltipshow tooltiphide":"tooltip"+b,c)}),a.each(h,function(){this.initialize==="render"&&this(z)}),Q(),E.queue("fx",function(a){g.originalEvent=H.event,E.trigger(g,[z]),D=0,C=0,z.redraw(),(t.show.ready||b)&&z.toggle(d,H.event),a()});return z},get:function(a){var b,c;switch(a.toLowerCase()){case"dimensions":b={height:E.outerHeight(),width:E.outerWidth()};break;case"offset":b=h.offset(E,t.position.container);break;default:c=I(a.toLowerCase()),b=c[0][c[1]],b=b.precedance?b.string():b}return b},set:function(b,c){function m(a,b){var c,d,e;for(c in k)for(d in k[c])if(e=(new RegExp(d,"i")).exec(a))b.push(e),k[c][d].apply(z,b)}var g=/^position\.(my|at|adjust|target|container)|style|content|show\.ready/i,h=/^content\.(title|attr)|style/i,i=e,j=e,k=z.checks,l;"string"===typeof b?(l=b,b={},b[l]=c):b=a.extend(d,{},b),a.each(b,function(c,d){var e=I(c.toLowerCase()),f;f=e[0][e[1]],e[0][e[1]]="object"===typeof d&&d.nodeType?a(d):d,b[c]=[e[0],e[1],d,f],i=g.test(c)||i,j=h.test(c)||j}),x(t),C=D=1,a.each(b,m),C=D=0,E.is(":visible")&&z.rendered&&(i&&z.reposition(t.position.target==="mouse"?f:H.event),j&&z.redraw());return z},toggle:function(b,c){function q(){b?(a.browser.msie&&E[0].style.removeAttribute("filter"),E.css("overflow",""),"string"===typeof h.autofocus&&a(h.autofocus,E).focus(),p=a.Event("tooltipvisible"),p.originalEvent=c?H.event:f,E.trigger(p,[z])):E.css({display:"",visibility:"",opacity:"",left:"",top:""})}if(!z.rendered)if(b)z.render(1);else return z;var g=b?"show":"hide",h=t[g],j=E.is(":visible"),k=!c||t[g].target.length<2||H.target[0]===c.target,l=t.position,m=t.content,o,p;(typeof b).search("boolean|number")&&(b=!j);if(!E.is(":animated")&&j===b&&k)return z;if(c){if(/over|enter/.test(c.type)&&/out|leave/.test(H.event.type)&&c.target===t.show.target[0]&&E.has(c.relatedTarget).length)return z;H.event=a.extend({},c)}p=a.Event("tooltip"+g),p.originalEvent=c?H.event:f,E.trigger(p,[z,90]);if(p.isDefaultPrevented())return z;a.attr(E[0],"aria-hidden",!b),b?(H.origin=a.extend({},i),z.focus(c),a.isFunction(m.text)&&P(m.text,e),a.isFunction(m.title.text)&&O(m.title.text,e),!v&&l.target==="mouse"&&l.adjust.mouse&&(a(document).bind("mousemove.qtip",function(a){i={pageX:a.pageX,pageY:a.pageY,type:"mousemove"}}),v=d),z.reposition(c),h.solo&&a(n,h.solo).not(E).qtip("hide",p)):(clearTimeout(z.timers.show),delete H.origin,v&&!a(n+'[tracking="true"]:visible',h.solo).not(E).length&&(a(document).unbind("mousemove.qtip"),v=e),z.blur(c)),k&&E.stop(0,1),h.effect===e?(E[g](),q.call(E)):a.isFunction(h.effect)?(h.effect.call(E,z),E.queue("fx",function(a){q(),a()})):E.fadeTo(90,b?1:0,q),b&&h.target.trigger("qtip-"+w+"-inactive");return z},show:function(a){return z.toggle(d,a)},hide:function(a){return z.toggle(e,a)},focus:function(b){if(!z.rendered)return z;var c=a(n),d=parseInt(E[0].style.zIndex,10),e=g.zindex+c.length,f=a.extend({},b),h,i;E.hasClass(p)||(i=a.Event("tooltipfocus"),i.originalEvent=f,E.trigger(i,[z,e]),i.isDefaultPrevented()||(d!==e&&(c.each(function(){this.style.zIndex>d&&(this.style.zIndex=this.style.zIndex-1)}),c.filter("."+p).qtip("blur",f)),E.addClass(p)[0].style.zIndex=e));return z},blur:function(b){var c=a.extend({},b),d;E.removeClass(p),d=a.Event("tooltipblur"),d.originalEvent=c,E.trigger(d,[z]);return z},reposition:function(c,d){if(!z.rendered||C)return z;C=1;var f=t.position.target,g=t.position,j=g.my,l=g.at,m=g.adjust,n=m.method.split(" "),o=E.outerWidth(),p=E.outerHeight(),q=0,r=0,s=a.Event("tooltipmove"),u=E.css("position")==="fixed",v=g.viewport,w={left:0,top:0},x=z.plugins.tip,y={horizontal:n[0],vertical:n[1]||n[0],left:function(a){var b=y.horizontal==="shift",c=v.offset.left+v.scrollLeft,d=j.x==="left"?o:j.x==="right"?-o:-o/2,e=l.x==="left"?q:l.x==="right"?-q:-q/2,f=x&&x.size?x.size.width||0:0,g=x&&x.corner&&x.corner.precedance==="x"&&!b?f:0,h=c-a+g,i=a+o-v.width-c+g,k=d-(j.precedance==="x"||j.x===j.y?e:0),n=j.x==="center";b?(g=x&&x.corner&&x.corner.precedance==="y"?f:0,k=(j.x==="left"?1:-1)*d-g,w.left+=h>0?h:i>0?-i:0,w.left=Math.max(v.offset.left+(g&&x.corner.x==="center"?x.offset:0),a-k,Math.min(Math.max(v.offset.left+v.width,a+k),w.left))):(h>0&&(j.x!=="left"||i>0)?w.left-=k+(n?0:2*m.x):i>0&&(j.x!=="right"||h>0)&&(w.left-=n?-k:k+2*m.x),w.left!==a&&n&&(w.left-=m.x),w.lefti&&(w.left=a));return w.left-a},top:function(a){var b=y.vertical==="shift",c=v.offset.top+v.scrollTop,d=j.y==="top"?p:j.y==="bottom"?-p:-p/2,e=l.y==="top"?r:l.y==="bottom"?-r:-r/2,f=x&&x.size?x.size.height||0:0,g=x&&x.corner&&x.corner.precedance==="y"&&!b?f:0,h=c-a+g,i=a+p-v.height-c+g,k=d-(j.precedance==="y"||j.x===j.y?e:0),n=j.y==="center";b?(g=x&&x.corner&&x.corner.precedance==="x"?f:0,k=(j.y==="top"?1:-1)*d-g,w.top+=h>0?h:i>0?-i:0,w.top=Math.max(v.offset.top+(g&&x.corner.x==="center"?x.offset:0),a-k,Math.min(Math.max(v.offset.top+v.height,a+k),w.top))):(h>0&&(j.y!=="top"||i>0)?w.top-=k+(n?0:2*m.y):i>0&&(j.y!=="bottom"||h>0)&&(w.top-=n?-k:k+2*m.y),w.top!==a&&n&&(w.top-=m.y),w.top<0&&-w.top>i&&(w.top=a));return w.top-a}};if(a.isArray(f)&&f.length===2)l={x:"left",y:"top"},w={left:f[0],top:f[1]};else if(f==="mouse"&&(c&&c.pageX||H.event.pageX))l={x:"left",y:"top"},c=(c&&(c.type==="resize"||c.type==="scroll")?H.event:c&&c.pageX&&c.type==="mousemove"?c:i&&i.pageX&&(m.mouse||!c||!c.pageX)?{pageX:i.pageX,pageY:i.pageY}:!m.mouse&&H.origin&&H.origin.pageX?H.origin:c)||c||H.event||i||{},w={top:c.pageY,left:c.pageX};else{f==="event"?c&&c.target&&c.type!=="scroll"&&c.type!=="resize"?f=H.target=a(c.target):f=H.target:H.target=a(f),f=a(f).eq(0);if(f.length===0)return z;f[0]===document||f[0]===b?(q=h.iOS?b.innerWidth:f.width(),r=h.iOS?b.innerHeight:f.height(),f[0]===b&&(w={top:!u||h.iOS?(v||f).scrollTop():0,left:!u||h.iOS?(v||f).scrollLeft():0})):f.is("area")&&h.imagemap?w=h.imagemap(f,l):f[0].namespaceURI==="http://www.w3.org/2000/svg"&&h.svg?w=h.svg(f,l):(q=f.outerWidth(),r=f.outerHeight(),w=h.offset(f,g.container,u)),w.offset&&(q=w.width,r=w.height,w=w.offset),w.left+=l.x==="right"?q:l.x==="center"?q/2:0,w.top+=l.y==="bottom"?r:l.y==="center"?r/2:0}w.left+=m.x+(j.x==="right"?-o:j.x==="center"?-o/2:0),w.top+=m.y+(j.y==="bottom"?-p:j.y==="center"?-p/2:0),v.jquery&&f[0]!==b&&f[0]!==A&&y.vertical+y.horizontal!=="nonenone"?(v={elem:v,height:v[(v[0]===b?"h":"outerH")+"eight"](),width:v[(v[0]===b?"w":"outerW")+"idth"](),scrollLeft:u?0:v.scrollLeft(),scrollTop:u?0:v.scrollTop(),offset:v.offset()||{left:0,top:0}},w.adjusted={left:y.horizontal!=="none"?y.left(w.left):0,top:y.vertical!=="none"?y.top(w.top):0}):w.adjusted={left:0,top:0},E.attr("class",function(b,c){return a.attr(this,"class").replace(/ui-tooltip-pos-\w+/i,"")}).addClass(k+"-pos-"+j.abbreviation()),s.originalEvent=a.extend({},c),E.trigger(s,[z,w,v.elem||v]);if(s.isDefaultPrevented())return z;delete w.adjusted,d===e||isNaN(w.left)||isNaN(w.top)||f==="mouse"||!a.isFunction(g.effect)?E.css(w):a.isFunction(g.effect)&&(g.effect.call(E,z,a.extend({},w)),E.queue(function(b){a(this).css({opacity:"",height:""}),a.browser.msie&&this.style.removeAttribute("filter"),b()})),C=0;return z},redraw:function(){if(z.rendered<1||D)return z;var a=t.position.container,b,c,d,e;D=1,t.style.height&&E.css("height",t.style.height),t.style.width?E.css("width",t.style.width):(E.css("width","").addClass(r),c=E.width()+1,d=E.css("max-width")||"",e=E.css("min-width")||"",b=(d+e).indexOf("%")>-1?a.width()/100:0,d=(d.indexOf("%")>-1?b:1)*parseInt(d,10)||c,e=(e.indexOf("%")>-1?b:1)*parseInt(e,10)||0,c=d+e?Math.min(Math.max(c,e),d):c,E.css("width",Math.round(c)).removeClass(r)),D=0;return z},disable:function(b){"boolean"!==typeof b&&(b=!E.hasClass(m)&&!H.disabled),z.rendered?(E.toggleClass(m,b),a.attr(E[0],"aria-disabled",b)):H.disabled=!!b;return z},enable:function(){return z.disable(e)},destroy:function(){var b=s[0],c=a.attr(b,u);z.rendered&&(E.remove(),a.each(z.plugins,function(){this.destroy&&this.destroy()})),clearTimeout(z.timers.show),clearTimeout(z.timers.hide),R(),a.removeData(b,"qtip"),t.suppress&&c&&(a.attr(b,"title",c),s.removeAttr(u)),s.removeAttr("aria-describedby").unbind(".qtip"),delete j[z.id];return s}})}function x(b){var c;if(!b||"object"!==typeof b)return e;"object"!==typeof b.metadata&&(b.metadata={type:b.metadata});if("content"in b){if("object"!==typeof b.content||b.content.jquery)b.content={text:b.content};c=b.content.text||e,!a.isFunction(c)&&(!c&&!c.attr||c.length<1||"object"===typeof c&&!c.jquery)&&(b.content.text=e),"title"in b.content&&("object"!==typeof b.content.title&&(b.content.title={text:b.content.title}),c=b.content.title.text||e,!a.isFunction(c)&&(!c&&!c.attr||c.length<1||"object"===typeof c&&!c.jquery)&&(b.content.title.text=e))}"position"in b&&("object"!==typeof b.position&&(b.position={my:b.position,at:b.position})),"show"in b&&("object"!==typeof b.show&&(b.show.jquery?b.show={target:b.show}:b.show={event:b.show})),"hide"in b&&("object"!==typeof b.hide&&(b.hide.jquery?b.hide={target:b.hide}:b.hide={event:b.hide})),"style"in b&&("object"!==typeof b.style&&(b.style={classes:b.style})),a.each(h,function(){this.sanitize&&this.sanitize(b)});return b}function w(){w.history=w.history||[],w.history.push(arguments);if("object"===typeof console){var a=console[console.warn?"warn":"log"],b=Array.prototype.slice.call(arguments),c;typeof arguments[0]==="string"&&(b[0]="qTip2: "+b[0]),c=a.apply?a.apply(console,b):a(b)}}"use strict";var d=!0,e=!1,f=null,g,h,i,j={},k="ui-tooltip",l="ui-widget",m="ui-state-disabled",n="div.qtip."+k,o=k+"-default",p=k+"-focus",q=k+"-hover",r=k+"-fluid",s="-31000px",t="_replacedByqTip",u="oldtitle",v;g=a.fn.qtip=function(b,h,i){var j=(""+b).toLowerCase(),k=f,l=j==="disable"?[d]:a.makeArray(arguments).slice(1),m=l[l.length-1],n=this[0]?a.data(this[0],"qtip"):f;if(!arguments.length&&n||j==="api")return n;if("string"===typeof b){this.each(function(){var b=a.data(this,"qtip");if(!b)return d;m&&m.timeStamp&&(b.cache.event=m);if(j!=="option"&&j!=="options"||!h)b[j]&&b[j].apply(b[j],l);else if(a.isPlainObject(h)||i!==c)b.set(h,i);else{k=b.get(h);return e}});return k!==f?k:this}if("object"===typeof b||!arguments.length){n=x(a.extend(d,{},b));return g.bind.call(this,n,m)}},g.bind=function(b,f){return this.each(function(k){function r(b){function d(){p.render(typeof b==="object"||l.show.ready),m.show.add(m.hide).unbind(o)}if(p.cache.disabled)return e;p.cache.event=a.extend({},b),p.cache.target=b?a(b.target):[c],l.show.delay>0?(clearTimeout(p.timers.show),p.timers.show=setTimeout(d,l.show.delay),n.show!==n.hide&&m.hide.bind(n.hide,function(){clearTimeout(p.timers.show)})):d()}var l,m,n,o,p,q;q=a.isArray(b.id)?b.id[k]:b.id,q=!q||q===e||q.length<1||j[q]?g.nextid++:j[q]=q,o=".qtip-"+q+"-create",p=z.call(this,q,b);if(p===e)return d;l=p.options,a.each(h,function(){this.initialize==="initialize"&&this(p)}),m={show:l.show.target,hide:l.hide.target},n={show:a.trim(""+l.show.event).replace(/ /g,o+" ")+o,hide:a.trim(""+l.hide.event).replace(/ /g,o+" ")+o},/mouse(over|enter)/i.test(n.show)&&!/mouse(out|leave)/i.test(n.hide)&&(n.hide+=" mouseleave"+o),m.show.bind("mousemove"+o,function(a){i={pageX:a.pageX,pageY:a.pageY,type:"mousemove"}}),m.show.bind(n.show,r),(l.show.ready||l.prerender)&&r(f)})},h=g.plugins={Corner:function(a){a=(""+a).replace(/([A-Z])/," $1").replace(/middle/gi,"center").toLowerCase(),this.x=(a.match(/left|right/i)||a.match(/center/)||["inherit"])[0].toLowerCase(),this.y=(a.match(/top|bottom|center/i)||["inherit"])[0].toLowerCase(),this.precedance=a.charAt(0).search(/^(t|b)/)>-1?"y":"x",this.string=function(){return this.precedance==="y"?this.y+this.x:this.x+this.y},this.abbreviation=function(){var a=this.x.substr(0,1),b=this.y.substr(0,1);return a===b?a:a==="c"||a!=="c"&&b!=="c"?b+a:a+b}},offset:function(c,d,e){function l(a,b){f.left+=b*a.scrollLeft(),f.top+=b*a.scrollTop()}var f=c.offset(),g=d,i=0,j=document.body,k;if(g){do{g.css("position")!=="static"&&(k=g[0]===j?{left:parseInt(g.css("left"),10)||0,top:parseInt(g.css("top"),10)||0}:g.position(),f.left-=k.left+(parseInt(g.css("borderLeftWidth"),10)||0)+(parseInt(g.css("marginLeft"),10)||0),f.top-=k.top+(parseInt(g.css("borderTopWidth"),10)||0),i++);if(g[0]===j)break}while(g=g.offsetParent());d[0]!==j&&i>1&&l(d,1),(h.iOS<4.1&&h.iOS>3.1||!h.iOS&&e)&&l(a(b),-1)}return f},iOS:parseFloat((""+(/CPU.*OS ([0-9_]{1,3})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_","."))||e,fn:{attr:function(b,c){if(this.length){var d=this[0],e="title",f=a.data(d,"qtip");if(b===e&&"object"===typeof f&&f.options.suppress){if(arguments.length<2)return a.attr(d,u);f&&f.options.content.attr===e&&f.cache.attr&&f.set("content.text",c);return this.attr(u,c)}}return a.fn["attr"+t].apply(this,arguments)},clone:function(b){var c=a([]),d="title",e=a.fn["clone"+t].apply(this,arguments);b||e.filter("["+u+"]").attr("title",function(){return a.attr(this,u)}).removeAttr(u);return e},remove:a.ui?f:function(b,c){a(this).each(function(){c||(!b||a.filter(b,[this]).length)&&a("*",this).add(this).each(function(){a(this).triggerHandler("remove")})})}}},a.each(h.fn,function(b,c){if(!c)return d;var e=a.fn[b+t]=a.fn[b];a.fn[b]=function(){return c.apply(this,arguments)||e.apply(this,arguments)}}),g.version="nightly",g.nextid=0,g.inactiveEvents="click dblclick mousedown mouseup mousemove mouseleave mouseenter".split(" "),g.zindex=15e3,g.defaults={prerender:e,id:e,overwrite:d,suppress:d,content:{text:d,attr:"title",title:{text:e,button:e}},position:{my:"top left",at:"bottom right",target:e,container:e,viewport:e,adjust:{x:0,y:0,mouse:d,resize:d,method:"flip flip"},effect:function(b,c,d){a(this).animate(c,{duration:200,queue:e})}},show:{target:e,event:"mouseenter",effect:d,delay:90,solo:e,ready:e,autofocus:e},hide:{target:e,event:"mouseleave",effect:d,delay:0,fixed:e,inactive:e,leave:"window",distance:e},style:{classes:"",widget:e,width:e,height:e},events:{render:f,move:f,show:f,hide:f,toggle:f,visible:f,focus:f,blur:f}},h.ajax=function(a){var b=a.plugins.ajax;return"object"===typeof b?b:a.plugins.ajax=new A(a)},h.ajax.initialize="render",h.ajax.sanitize=function(a){var b=a.content,c;b&&"ajax"in b&&(c=b.ajax,typeof c!=="object"&&(c=a.content.ajax={url:c}),"boolean"!==typeof c.once&&c.once&&(c.once=!!c.once))},a.extend(d,g.defaults,{content:{ajax:{loading:d,once:d}}}),h.tip=function(a){var b=a.plugins.tip;return"object"===typeof b?b:a.plugins.tip=new C(a)},h.tip.initialize="render",h.tip.sanitize=function(a){var b=a.style,c;b&&"tip"in b&&(c=a.style.tip,typeof c!=="object"&&(a.style.tip={corner:c}),/string|boolean/i.test(typeof c.corner)||(c.corner=d),typeof c.width!=="number"&&delete c.width,typeof c.height!=="number"&&delete c.height,typeof c.border!=="number"&&c.border!==d&&delete c.border,typeof c.offset!=="number"&&delete c.offset)},a.extend(d,g.defaults,{style:{tip:{corner:d,mimic:e,width:6,height:6,border:d,offset:0}}}),h.bgiframe=function(b){var c=a.browser,d=b.plugins.bgiframe;if(a("select, object").length<1||(!c.msie||c.version.charAt(0)!=="6"))return e;return"object"===typeof d?d:b.plugins.bgiframe=new D(b)},h.bgiframe.initialize="render"})(jQuery,window) Property changes on: platform\inc\jquery\qtip\jquery.qtip.min.js ___________________________________________________________________ Added: svn:eol-style + LF Index: platform/inc/script.js =================================================================== --- platform/inc/script.js (revision 14590) +++ platform/inc/script.js (working copy) @@ -214,3 +214,24 @@ this._controls.push($id); } +function in_array(needle, haystack) +{ + return array_search(needle, haystack) != -1; +} + +function array_search(needle, haystack) +{ + for (var i=0; i