Skip to content
This repository has been archived by the owner on Jun 14, 2020. It is now read-only.

Commit

Permalink
Optimize initial rendering methods and related code. Fixes #566
Browse files Browse the repository at this point in the history
  • Loading branch information
Craga89 committed Jul 28, 2013
1 parent 7cdf72f commit a0ea0ad
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 119 deletions.
3 changes: 2 additions & 1 deletion src/core/class.js
Expand Up @@ -110,7 +110,8 @@ PROTOTYPE.render = function(show) {
}
});

// Assign events
// Unassign initial events and assign proper events
this._unassignEvents();
this._assignEvents();

// When deferreds have completed
Expand Down
2 changes: 2 additions & 0 deletions src/core/constants.js
Expand Up @@ -40,6 +40,8 @@ replaceSuffix = '_replacedByqTip',
oldtitle = 'oldtitle',
trackingBound,

docBody, // set in jquery_methods.init

// Browser detection
BROWSER = {
/*
Expand Down
102 changes: 80 additions & 22 deletions src/core/events.js
@@ -1,3 +1,13 @@
function delay(callback, duration) {
// If tooltip has displayed, start hide timer
if(duration > 0) {
return setTimeout(
$.proxy(callback, this), duration
);
}
else{ callback.call(this); }
}

function showMethod(event) {
if(this.tooltip.hasClass(CLASS_DISABLED)) { return FALSE; }

Expand All @@ -6,11 +16,10 @@ function showMethod(event) {
clearTimeout(this.timers.hide);

// Start show timer
var callback = $.proxy(function(){ this.toggle(TRUE, event); }, this);
if(this.options.show.delay > 0) {
this.timers.show = setTimeout(callback, this.options.show.delay);
}
else{ callback(); }
this.timers.show = delay.call(this,
function() { this.toggle(TRUE, event); },
this.options.show.delay
);
}

function hideMethod(event) {
Expand Down Expand Up @@ -42,20 +51,22 @@ function hideMethod(event) {
}

// If tooltip has displayed, start hide timer
var callback = $.proxy(function(){ this.toggle(FALSE, event); }, this);
if(this.options.hide.delay > 0) {
this.timers.hide = setTimeout(callback, this.options.hide.delay);
}
else{ callback(); }
this.timers.hide = delay.call(this,
function() { this.toggle(FALSE, event); },
this.options.hide.delay,
this
);
}

function inactiveMethod(event) {
if(this.tooltip.hasClass(CLASS_DISABLED) || !this.options.hide.inactive) { return FALSE; }

// Clear timer
clearTimeout(this.timers.inactive);
this.timers.inactive = setTimeout(
$.proxy(function(){ this.hide(event); }, this), this.options.hide.inactive

this.timers.inactive = delay.call(this,
function(){ this.hide(event); },
this.options.hide.inactive
);
}

Expand Down Expand Up @@ -89,7 +100,7 @@ PROTOTYPE._unbind = function(targets, suffix) {
// Apply common event handlers using delegate (avoids excessive .bind calls!)
var ns = '.'+NAMESPACE;
function delegate(selector, events, method) {
$(document.body).delegate(selector,
docBody.delegate(selector,
(events.split ? events : events.join(ns + ' ')) + ns,
function() {
var api = QTIP.api[ $.attr(this, ATTR_ID) ];
Expand Down Expand Up @@ -143,6 +154,59 @@ PROTOTYPE._trigger = function(type, args, event) {
return !callback.isDefaultPrevented();
};

PROTOTYPE._assignInitialEvents = function(event) {
var options = this.options,
showTarget = options.show.target,
hideTarget = options.hide.target,
showEvents = options.show.event ? $.trim('' + options.show.event).split(' ') : [],
hideEvents = options.hide.event ? $.trim('' + options.hide.event).split(' ') : [];

/*
* 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(options.show.event) && !/mouse(out|leave)/i.test(options.hide.event)) {
hideEvents.push('mouseleave');
}

/*
* Also make sure initial mouse targetting works correctly by caching mousemove coords
* on show targets before the tooltip has rendered. Also set onTarget when triggered to
* keep mouse tracking working.
*/
this._bind(showTarget, 'mousemove', function(event) {
this._storeMouse(event);
this.cache.onTarget = TRUE;
});

// Define hoverIntent function
function hoverIntent(event) {
// Only continue if tooltip isn't disabled
if(this.disabled) { return FALSE; }

// Cache the event data
this.cache.event = $.extend({}, event);
this.cache.target = event ? $(event.target) : [undefined];

// Start the event sequence
clearTimeout(this.timers.show);
this.timers.show = delay.call(this,
function() { this.render(typeof event === 'object' || options.show.ready); },
options.show.delay
);
}

// Bind events to target
this._bind(showTarget, showEvents, hoverIntent);
if(options.show.event !== options.hide.event) {
this._bind(hideTarget, hideEvents, function() { clearTimeout(this.timers.show); });
}

// Prerendering is enabled, create tooltip now
if(options.show.ready || options.prerender) { hoverIntent.call(this, event); }
};


// Event assignment method
PROTOTYPE._assignEvents = function() {
var self = this,
Expand Down Expand Up @@ -299,14 +363,8 @@ PROTOTYPE._unassignEvents = function() {
document
];

// Check if tooltip is rendered
if(this.rendered) {
this._unbind($([]).pushStack( $.grep(targets, function(i) {
return typeof i === 'object';
})));
}

// Tooltip isn't yet rendered, remove render event
else { $(targets[0]).unbind('.'+this._id+'-create'); }
this._unbind($([]).pushStack( $.grep(targets, function(i) {
return typeof i === 'object';
})));
};

123 changes: 31 additions & 92 deletions src/core/jquery_methods.js
@@ -1,10 +1,9 @@
// Initialization method
function init(elem, id, opts)
{
var obj, posOptions, attr, config, title,

function init(elem, id, opts) {
// Setup element references
docBody = $(document.body),
docBody = docBody || $(document.body);

var obj, posOptions, attr, config, title,

// Use document body instead of document element if needed
newTarget = elem[0] === document ? docBody : elem,
Expand Down Expand Up @@ -102,10 +101,8 @@ QTIP = $.fn.qtip = function(options, notation, newValue)
}

// Execute API command if present
else if('string' === typeof options)
{
this.each(function()
{
else if('string' === typeof options) {
this.each(function() {
var api = $.data(this, NAMESPACE);
if(!api) { return TRUE; }

Expand Down Expand Up @@ -133,99 +130,41 @@ QTIP = $.fn.qtip = function(options, notation, newValue)
}

// No API commands. validate provided options and setup qTips
else if('object' === typeof options || !arguments.length)
{
else if('object' === typeof options || !arguments.length) {
// Sanitize options first
opts = sanitizeOptions($.extend(TRUE, {}, options));

// Bind the qTips
return QTIP.bind.call(this, opts, event);
}
};
return this.each(function(i) {
var options, targets, events, namespace, api, id;

// $.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 || QTIP.api[id] ? QTIP.nextid++ : 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 || QTIP.api[id] ? QTIP.nextid++ : id;
// Setup events namespace
namespace = '.qtip-'+id+'-create';

// Setup events namespace
namespace = '.qtip-'+id+'-create';
// Initialize the qTip and re-grab newly sanitized options
api = init($(this), id, opts);
if(api === FALSE) { return TRUE; }
else { QTIP.api[id] = api; }
options = api.options;

// Initialize the qTip and re-grab newly sanitized options
api = init($(this), id, opts);
if(api === FALSE) { return TRUE; }
else { QTIP.api[id] = api; }
options = api.options;
// Initialize plugins
$.each(PLUGINS, function() {
if(this.initialize === 'initialize') { this(api); }
});

// Initialize plugins
$.each(PLUGINS, function() {
if(this.initialize === 'initialize') { this(api); }
// Assign initial pre-render events
api._assignInitialEvents(event);
});
}
};

// Determine hide and show targets
targets = { show: options.show.target, hide: options.hide.target };
events = {
show: $.trim('' + options.show.event).replace(/ /g, namespace+' ') + namespace,
hide: $.trim('' + options.hide.event).replace(/ /g, namespace+' ') + namespace
};

/*
* Make sure hoverIntent functions properly by using mouseleave as a hide event if
* mouseenter/mouseout is used for show.event, even if it isn't in the users options.
*/
if(/mouse(over|enter)/i.test(events.show) && !/mouse(out|leave)/i.test(events.hide)) {
events.hide += ' mouseleave' + namespace;
}

/*
* Also make sure initial mouse targetting works correctly by caching mousemove coords
* on show targets before the tooltip has rendered.
*
* Also set onTarget when triggered to keep mouse tracking working
*/
targets.show.bind('mousemove'+namespace, function(event) {
api._storeMouse(event);
api.cache.onTarget = TRUE;
});

// Define hoverIntent function
function hoverIntent(event) {
function render() {
// Cache mouse coords,render and render the tooltip
api.render(typeof event === 'object' || options.show.ready);

// Unbind show and hide events
targets.show.add(targets.hide).unbind(namespace);
}

// Only continue if tooltip isn't disabled
if(api.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);
// $.fn.qtip Bind method
QTIP.bind = function(opts, event)
{

// Prerendering is enabled, create tooltip now
if(options.show.ready || options.prerender) { hoverIntent(event); }
});
};

// Populated in render method
Expand Down
2 changes: 1 addition & 1 deletion src/core/position.js
Expand Up @@ -48,7 +48,7 @@ PROTOTYPE.reposition = function(event, effect) {

// Calculate body and container offset and take them into account below
if(type !== 'static') { position = container.offset(); }
if(doc.body.offsetWidth !== (window.innerWidth || doc.documentElement.clientWidth)) { offset = $(doc.body).offset(); }
if(doc.body.offsetWidth !== (window.innerWidth || doc.documentElement.clientWidth)) { offset = docBody.offset(); }

// Use event coordinates for position
position = {
Expand Down
7 changes: 4 additions & 3 deletions src/tips/tips.js
Expand Up @@ -81,7 +81,7 @@ $.extend(Tip.prototype, {

// Setup constant parameters
context.lineJoin = 'miter';
context.miterLimit = 100;
context.miterLimit = 100000;
context.save();
}
else {
Expand Down Expand Up @@ -333,7 +333,7 @@ $.extend(Tip.prototype, {
// Grab canvas context and clear/save it
context = inner[0].getContext('2d');
context.restore(); context.save();
context.clearRect(0,0,3000,3000);
context.clearRect(0,0,6000,6000);

// Set properties
context.fillStyle = color[0];
Expand All @@ -343,6 +343,7 @@ $.extend(Tip.prototype, {
// Draw the tip
context.translate(translate[0], translate[1]);
context.beginPath();

context.moveTo(coords[0], coords[1]);
context.lineTo(coords[2], coords[3]);
context.lineTo(coords[4], coords[5]);
Expand Down Expand Up @@ -588,7 +589,7 @@ CHECKS.tip = {
},
'^style.tip.(height|width)$': function(obj) {
// Re-set dimensions and redraw the tip
this.size = size = [ obj.width, obj.height ];
this.size = [ obj.width, obj.height ];
this.update();

// Reposition the tooltip
Expand Down

0 comments on commit a0ea0ad

Please sign in to comment.