docs: function(event, callback) {
  		
  		var self = this;
  		
  		// if the destruction process has not begun and if this was not
  		// triggered by an unwanted emulated click event
  		if (!self.__destroying) {
  			
  			// check that the origin is still in the DOM
  			if (	bodyContains(self._$origin)
  				// if the tooltip is enabled
  				&&	self.__enabled
  			) {
  				
  				var ok = true;
  				
  				// if the tooltip is not open yet, we need to call functionBefore.
  				// otherwise we can jst go on
  				if (self.__state == 'closed') {
  					
  					// trigger an event. The event.stop function allows the callback
  					// to prevent the opening of the tooltip
  					self._trigger({
  						type: 'before',
  						event: event,
  						stop: function() {
  							ok = false;
  						}
  					});
  					
  					if (ok && self.__options.functionBefore) {
  						
  						// call our custom function before continuing
  						ok = self.__options.functionBefore.call(self, self, {
  							event: event,
  							origin: self._$origin[0]
  						});
  					}
  				}
  				
  				if (ok !== false) {
  					
  					// if there is some content
  					if (self.__Content !== null) {
  						
  						// save the method callback and cancel close method callbacks
  						if (callback) {
  							self.__callbacks.open.push(callback);
  						}
  						self.__callbacks.close = [];
  						
  						// get rid of any appearance timeouts
  						self.__timeoutsClear();
  						
  						var extraTime,
  							finish = function() {
  								
  								if (self.__state != 'stable') {
  									self.__stateSet('stable');
  								}
  								
  								// trigger any open method custom callbacks and reset them
  								$.each(self.__callbacks.open, function(i,c) {
  									c.call(self, self, {
  										origin: self._$origin[0],
  										tooltip: self._$tooltip[0]
  									});
  								});
  								
  								self.__callbacks.open = [];
  							};
  						
  						// if the tooltip is already open
  						if (self.__state !== 'closed') {
  							
  							// the timer (if any) will start (or restart) right now
  							extraTime = 0;
  							
  							// if it was disappearing, cancel that
  							if (self.__state === 'disappearing') {
  								
  								self.__stateSet('appearing');
  								
  								if (env.hasTransitions) {
  									
  									self._$tooltip
  										.clearQueue()
  										.removeClass('tooltipster-dying')
  										.addClass('tooltipster-show');
  									
  									if (self.__options.animationDuration[0] > 0) {
  										self._$tooltip.delay(self.__options.animationDuration[0]);
  									}
  									
  									self._$tooltip.queue(finish);
  								}
  								else {
  									// in case the tooltip was currently fading out, bring it back
  									// to life
  									self._$tooltip
  										.stop()
  										.fadeIn(finish);
  								}
  							}
  							// if the tooltip is already open, we still need to trigger the method
  							// custom callback
  							else if (self.__state == 'stable') {
  								finish();
  							}
  						}
  						// if the tooltip isn't already open, open it
  						else {
  							
  							// a plugin must bind on this and store the tooltip in this._$tooltip
  							self.__stateSet('appearing');
  							
  							// the timer (if any) will start when the tooltip has fully appeared
  							// after its transition
  							extraTime = self.__options.animationDuration[0];
  							
  							// insert the content inside the tooltip
  							self.__contentInsert();
  							
  							// reposition the tooltip and attach to the DOM
  							self.reposition(event, true);
  							
  							// animate in the tooltip. If the display plugin wants no css
  							// animations, it may override the animation option with a
  							// dummy value that will produce no effect
  							if (env.hasTransitions) {
  								
  								// note: there seems to be an issue with start animations which
  								// are randomly not played on fast devices in both Chrome and FF,
  								// couldn't find a way to solve it yet. It seems that applying
  								// the classes before appending to the DOM helps a little, but
  								// it messes up some CSS transitions. The issue almost never
  								// happens when delay[0]==0 though
  								self._$tooltip
  									.addClass('tooltipster-'+ self.__options.animation)
  									.addClass('tooltipster-initial')
  									.css({
  										'-moz-animation-duration': self.__options.animationDuration[0] + 'ms',
  										'-ms-animation-duration': self.__options.animationDuration[0] + 'ms',
  										'-o-animation-duration': self.__options.animationDuration[0] + 'ms',
  										'-webkit-animation-duration': self.__options.animationDuration[0] + 'ms',
  										'animation-duration': self.__options.animationDuration[0] + 'ms',
  										'transition-duration': self.__options.animationDuration[0] + 'ms'
  									});
  								
  								setTimeout(
  									function() {
  										
  										// a quick hover may have already triggered a mouseleave
  										if (self.__state != 'closed') {
  											
  											self._$tooltip
  												.addClass('tooltipster-show')
  												.removeClass('tooltipster-initial');
  											
  											if (self.__options.animationDuration[0] > 0) {
  												self._$tooltip.delay(self.__options.animationDuration[0]);
  											}
  											
  											self._$tooltip.queue(finish);
  										}
  									},
  									0
  								);
  							}
  							else {
  								
  								// old browsers will have to live with this
  								self._$tooltip
  									.css('display', 'none')
  									.fadeIn(self.__options.animationDuration[0], finish);
  							}
  							
  							// checks if the origin is removed while the tooltip is open
  							self.__trackerStart();
  							
  							// NOTE: the listeners below have a '-triggerClose' namespace
  							// because we'll remove them when the tooltip closes (unlike
  							// the '-triggerOpen' listeners). So some of them are actually
  							// not about close triggers, rather about positioning.
  							
  							$(env.window)
  								// reposition on resize
  								.on('resize.'+ self.__namespace +'-triggerClose', function(e) {
  									
  									var $ae = $(document.activeElement);
  									
  									// reposition only if the resize event was not triggered upon the opening
  									// of a virtual keyboard due to an input field being focused within the tooltip
  									// (otherwise the repositioning would lose the focus)
  									if (	(!$ae.is('input') && !$ae.is('textarea'))
  										||	!$.contains(self._$tooltip[0], $ae[0])
  									) {
  										self.reposition(e);
  									}
  								})
  								// same as below for parents
  								.on('scroll.'+ self.__namespace +'-triggerClose', function(e) {
  									self.__scrollHandler(e);
  								});
  							
  							self.__$originParents = self._$origin.parents();
  							
  							// scrolling may require the tooltip to be moved or even
  							// repositioned in some cases
  							self.__$originParents.each(function(i, parent) {
  								
  								$(parent).on('scroll.'+ self.__namespace +'-triggerClose', function(e) {
  									self.__scrollHandler(e);
  								});
  							});
  							
  							if (	self.__options.triggerClose.mouseleave
  								||	(self.__options.triggerClose.touchleave && env.hasTouchCapability)
  							) {
  								
  								// we use an event to allow users/plugins to control when the mouseleave/touchleave
  								// close triggers will come to action. It allows to have more triggering elements
  								// than just the origin and the tooltip for example, or to cancel/delay the closing,
  								// or to make the tooltip interactive even if it wasn't when it was open, etc.
  								self._on('dismissable', function(event) {
  									
  									if (event.dismissable) {
  										
  										if (event.delay) {
  											
  											timeout = setTimeout(function() {
  												// event.event may be undefined
  												self._close(event.event);
  											}, event.delay);
  											
  											self.__timeouts.close.push(timeout);
  										}
  										else {
  											self._close(event);
  										}
  									}
  									else {
  										clearTimeout(timeout);
  									}
  								});
  								
  								// now set the listeners that will trigger 'dismissable' events
  								var $elements = self._$origin,
  									eventNamesIn = '',
  									eventNamesOut = '',
  									timeout = null;
  								
  								// if we have to allow interaction, bind on the tooltip too
  								if (self.__options.interactive) {
  									$elements = $elements.add(self._$tooltip);
  								}
  								
  								if (self.__options.triggerClose.mouseleave) {
  									eventNamesIn += 'mouseenter.'+ self.__namespace +'-triggerClose ';
  									eventNamesOut += 'mouseleave.'+ self.__namespace +'-triggerClose ';
  								}
  								if (self.__options.triggerClose.touchleave && env.hasTouchCapability) {
  									eventNamesIn += 'touchstart.'+ self.__namespace +'-triggerClose';
  									eventNamesOut += 'touchend.'+ self.__namespace +'-triggerClose touchcancel.'+ self.__namespace +'-triggerClose';
  								}
  								
  								$elements
  									// close after some time spent outside of the elements
  									.on(eventNamesOut, function(event) {
  										
  										// it's ok if the touch gesture ended up to be a swipe,
  										// it's still a "touch leave" situation
  										if (	self._touchIsTouchEvent(event)
  											||	!self._touchIsEmulatedEvent(event)
  										) {
  											
  											var delay = (event.type == 'mouseleave') ?
  												self.__options.delay :
  												self.__options.delayTouch;
  											
  											self._trigger({
  												delay: delay[1],
  												dismissable: true,
  												event: event,
  												type: 'dismissable'
  											});
  										}
  									})
  									// suspend the mouseleave timeout when the pointer comes back
  									// over the elements
  									.on(eventNamesIn, function(event) {
  										
  										// it's also ok if the touch event is a swipe gesture
  										if (	self._touchIsTouchEvent(event)
  											||	!self._touchIsEmulatedEvent(event)
  										) {
  											self._trigger({
  												dismissable: false,
  												event: event,
  												type: 'dismissable'
  											});
  										}
  									});
  							}
  							
  							// close the tooltip when the origin gets a mouse click (common behavior of
  							// native tooltips)
  							if (self.__options.triggerClose.originClick) {
  								
  								self._$origin.on('click.'+ self.__namespace + '-triggerClose', function(event) {
  									
  									// we could actually let a tap trigger this but this feature just
  									// does not make sense on touch devices
  									if (	!self._touchIsTouchEvent(event)
  										&&	!self._touchIsEmulatedEvent(event)
  									) {
  										self._close(event);
  									}
  								});
  							}
  							
  							// set the same bindings for click and touch on the body to close the tooltip
  							if (	self.__options.triggerClose.click
  								||	(self.__options.triggerClose.tap && env.hasTouchCapability)
  							) {
  								
  								// don't set right away since the click/tap event which triggered this method
  								// (if it was a click/tap) is going to bubble up to the body, we don't want it
  								// to close the tooltip immediately after it opened
  								setTimeout(function() {
  									
  									if (self.__state != 'closed') {
  										
  										var eventNames = '',
  											$body = $(env.window.document.body);
  										
  										if (self.__options.triggerClose.click) {
  											eventNames += 'click.'+ self.__namespace +'-triggerClose ';
  										}
  										if (self.__options.triggerClose.tap && env.hasTouchCapability) {
  											eventNames += 'touchend.'+ self.__namespace +'-triggerClose';
  										}
  										
  										$body.on(eventNames, function(event) {
  											
  											if (self._touchIsMeaningfulEvent(event)) {
  												
  												self._touchRecordEvent(event);
  												
  												if (!self.__options.interactive || !$.contains(self._$tooltip[0], event.target)) {
  													self._close(event);
  												}
  											}
  										});
  										
  										// needed to detect and ignore swiping
  										if (self.__options.triggerClose.tap && env.hasTouchCapability) {
  											
  											$body.on('touchstart.'+ self.__namespace +'-triggerClose', function(event) {
  												self._touchRecordEvent(event);
  											});
  										}
  									}
  								}, 0);
  							}
  							
  							self._trigger('ready');
  							
  							// call our custom callback
  							if (self.__options.functionReady) {
  								self.__options.functionReady.call(self, self, {
  									origin: self._$origin[0],
  									tooltip: self._$tooltip[0]
  								});
  							}
  						}
  						
  						// if we have a timer set, let the countdown begin
  						if (self.__options.timer > 0) {
  							
  							var timeout = setTimeout(function() {
  								self._close();
  							}, self.__options.timer + extraTime);
  							
  							self.__timeouts.close.push(timeout);
  						}
  					}
  				}
  			}
  		}
  		
  		return self;
  	}