3 Copyright (c) 2011-2013 Small Improvements (http://www.small-improvements.com)
5 Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
11 if (typeof define === 'function' && define.amd) {
12 return define(['jquery'], factory);
14 return factory(jQuery);
17 var $document, $overlay, $window, classAlignLeft, classAlignRight, classBase, classBottom, classContent, classHint, classInitialized, classInstance, classLeft, classRight, classTheme, classTour, classTourClose, classTourCloseIcon, classTourContent, classTourFooter, classTourNext, classTourOverlay, classTourPrev, classTourProgress, cssAnimationsEnabled, currentTour, dataBeingShown, dataIsTour, dataPopupHovered, dataPosition, dataShown, dataTimerHide, dataTimerShow, dataTriggerHovered, dataXDistance, dataYDistance, dataZIndex, destroy, eventBlur, eventClick, eventFocus, eventKeyUp, eventMouseOut, eventMouseOver, eventResize, eventScroll, eventTouchEnd, fadeInPopup, fadeInPopupFinished, filterAlignmentClass, filterBaseClass, filterClass, forceRefreshPosition, getInstance, getOverlay, getTrigger, hideSmallipop, hideTourOverlay, instances, isElementFixed, killTimers, lastId, lastScrollCheck, nextInstanceId, onWindowKeyUp, onWindowScroll, popupTemplate, queueRefreshPosition, reAlignmentClass, reBaseClass, refreshPosition, refreshQueueTimer, resetTourZIndices, runTour, scrollTimer, setContent, showPopup, showSmallipop, showWhenVisible, sip, touchEnabled, tourClose, tourNext, tourPrev, tourShow, tours, triggerMouseout, triggerMouseover;
18 classBase = 'smallipop';
19 classHint = classBase + '-hint';
20 classInstance = classBase + '-instance';
21 classContent = classBase + '-content';
22 classLeft = classBase + '-left';
23 classRight = classBase + '-right';
24 classBottom = classBase + '-bottom';
25 classAlignLeft = classBase + '-align-left';
26 classAlignRight = classBase + '-align-right';
27 classInitialized = classBase + '-initialized';
28 classTheme = classBase + '-theme-';
29 classTour = classBase + '-tour';
30 classTourContent = classTour + '-content';
31 classTourOverlay = classTour + '-overlay';
32 classTourFooter = classTour + '-footer';
33 classTourCloseIcon = classTour + '-close-icon';
34 classTourProgress = classTour + '-progress';
35 classTourClose = classTour + '-close';
36 classTourPrev = classTour + '-prev';
37 classTourNext = classTour + '-next';
38 eventFocus = 'focus.' + classBase;
39 eventClick = 'click.' + classBase;
40 eventBlur = 'blur.' + classBase;
41 eventMouseOut = 'mouseout.' + classBase;
42 eventMouseOver = 'mouseover.' + classBase;
43 eventTouchEnd = 'touchend.' + classBase;
44 eventResize = 'resize.' + classBase;
45 eventScroll = 'scroll.' + classBase;
46 eventKeyUp = 'keyup.' + classBase;
47 dataZIndex = classBase + 'OriginalZIndex';
48 dataBeingShown = classBase + 'BeingShown';
49 dataTimerHide = classBase + 'HideDelayTimer';
50 dataTimerShow = classBase + 'ShowDelayTimer';
51 dataTriggerHovered = classBase + 'TriggerHovered';
52 dataPopupHovered = classBase + 'PopupHovered';
53 dataShown = classBase + 'Shown';
54 dataPosition = classBase + 'Position';
55 dataXDistance = classBase + 'XDistance';
56 dataYDistance = classBase + 'YDistance';
57 dataIsTour = classBase + 'IsTour';
58 reAlignmentClass = new RegExp(classBase + '-(align|bottom)\w*', "g");
59 reBaseClass = new RegExp(classBase + '\w+', "g");
60 $document = $(document);
70 refreshQueueTimer = null;
71 popupTemplate = "<div class='" + classInstance + "'><div class='" + classContent + "'/></div>";
75 autoscrollPadding: 200,
76 contentAnimationSpeed: 150,
79 show: 'animated fadeIn',
80 hide: 'animated fadeOut'
82 funcEase: 'easeInOutQuad',
86 hideOnPopupClick: true,
87 hideOnTriggerClick: true,
89 invertAnimation: false,
95 popupAnimationSpeed: 200,
96 preferredPosition: 'top',
97 referencedContent: null,
100 tourHighlight: false,
101 tourHighlightColor: '#222',
102 tourHighlightFadeDuration: 200,
103 tourHighlightOpacity: .5,
104 tourHighlightZIndex: 9997,
105 tourNavigationEnabled: true,
106 triggerAnimationSpeed: 150,
107 triggerOnClick: false,
124 if (!$.easing.easeInOutQuad) {
125 $.easing.easeInOutQuad = function(x, t, b, c, d) {
126 if ((t /= d / 2) < 1) {
127 return c / 2 * t * t + b;
129 return -c / 2 * ((--t) * (t - 2) - 1) + b;
133 resetTourZIndices = function() {
134 var step, steps, tour, tourTrigger, _results;
136 for (tour in tours) {
138 _results.push((function() {
139 var _i, _len, _results1;
141 for (_i = 0, _len = steps.length; _i < _len; _i++) {
143 tourTrigger = step.trigger;
144 if (tourTrigger.data(dataZIndex)) {
145 _results1.push(tourTrigger.css('zIndex', tourTrigger.data(dataZIndex)));
147 _results1.push(void 0);
155 touchEnabled = typeof Modernizr !== "undefined" && Modernizr !== null ? Modernizr.touch : void 0;
156 cssAnimationsEnabled = typeof Modernizr !== "undefined" && Modernizr !== null ? Modernizr.cssanimations : void 0;
157 getTrigger = function(id) {
158 return $("." + (classBase + id));
160 getOverlay = function() {
162 $overlay = $("<div id='" + classTourOverlay + "'/>").appendTo($('body')).fadeOut(0);
166 hideTourOverlay = function(options) {
167 getOverlay().fadeOut(options.tourHighlightFadeDuration);
168 return resetTourZIndices();
170 hideSmallipop = function(e) {
171 var direction, ignorePopupClick, ignoreTriggerClick, popup, popupData, popupId, shownId, target, trigger, triggerData, triggerIsTarget, triggerOptions, xDistance, yDistance, _base, _ref, _ref1, _results;
172 clearTimeout(scrollTimer);
173 target = (e != null ? e.target : void 0) ? $(e.target) : e;
175 for (popupId in instances) {
176 popup = instances[popupId];
177 popupData = popup.data();
178 if (!(shownId = popupData[dataShown])) {
181 trigger = getTrigger(shownId);
182 triggerIsTarget = trigger.is(target);
183 triggerData = trigger.data(classBase);
184 triggerOptions = triggerData.options || sip.defaults;
185 if ((popupData[dataIsTour] || triggerData.isFormElement) && !popup.is(target) && !(triggerIsTarget && popup.is(triggerOptions.popupInstance))) {
188 if (popupData[dataIsTour]) {
190 if ((_ref = trigger.data(classBase)) != null) {
191 if (typeof (_base = _ref.options).onTourClose === "function") {
195 hideTourOverlay(triggerOptions);
197 ignoreTriggerClick = !triggerOptions.hideOnTriggerClick && triggerIsTarget;
198 ignorePopupClick = !triggerOptions.hideOnPopupClick && popup.find(target).length;
199 if (target && trigger.length && ((_ref1 = e != null ? e.type : void 0) === 'click' || _ref1 === 'touchend') && (ignoreTriggerClick || ignorePopupClick)) {
202 if (shownId && triggerOptions.hideTrigger) {
203 trigger.stop(true).fadeTo(triggerOptions.triggerAnimationSpeed, 1);
205 popup.data(dataTimerHide, null).data(dataBeingShown, false);
206 if (triggerOptions.cssAnimations.enabled) {
207 popup.removeClass(triggerOptions.cssAnimations.show).addClass(triggerOptions.cssAnimations.hide).data(dataShown, '');
208 if (triggerOptions.onAfterHide) {
209 _results.push(window.setTimeout(triggerOptions.onAfterHide, triggerOptions.popupAnimationSpeed));
211 _results.push(void 0);
214 direction = triggerOptions.invertAnimation ? -1 : 1;
215 xDistance = popupData[dataXDistance] * direction;
216 yDistance = popupData[dataYDistance] * direction;
217 _results.push(popup.stop(true).animate({
218 top: "-=" + yDistance,
219 left: "+=" + xDistance,
221 }, triggerOptions.popupAnimationSpeed, triggerOptions.funcEase, function() {
224 if (!self.data(dataBeingShown)) {
225 self.css('display', 'none').data(dataShown, '');
227 return typeof triggerOptions.onAfterHide === "function" ? triggerOptions.onAfterHide() : void 0;
233 showSmallipop = function(e) {
234 var triggerData, _ref;
235 triggerData = $(this).data(classBase);
239 if (triggerData.popupInstance.data(dataShown) !== triggerData.id && ((_ref = !triggerData.type) === 'checkbox' || _ref === 'radio')) {
244 return triggerMouseover.call(this);
246 killTimers = function(popup) {
247 clearTimeout(popup.data(dataTimerHide));
248 return clearTimeout(popup.data(dataTimerShow));
250 queueRefreshPosition = function(delay) {
254 clearTimeout(refreshQueueTimer);
255 return refreshQueueTimer = setTimeout(refreshPosition, delay);
257 filterClass = function(classStr, re) {
259 return (classStr.match(re) || []).join(' ');
262 filterAlignmentClass = function(idx, classStr) {
263 return filterClass(classStr, reAlignmentClass);
265 filterBaseClass = function(idx, classStr) {
266 return filterClass(classStr, reBaseClass);
268 refreshPosition = function(resetTheme) {
269 var isFixed, offset, opacity, options, popup, popupCenter, popupData, popupDistanceBottom, popupDistanceLeft, popupDistanceRight, popupDistanceTop, popupH, popupId, popupOffsetLeft, popupOffsetTop, popupW, popupY, preferredPosition, selfHeight, selfWidth, selfY, shownId, themes, trigger, triggerData, win, winHeight, winScrollLeft, winScrollTop, winWidth, windowPadding, xDistance, xOffset, xOverflow, yDistance, yOffset, yOverflow, _results;
270 if (resetTheme == null) {
274 for (popupId in instances) {
275 popup = instances[popupId];
276 popupData = popup.data();
277 shownId = popupData[dataShown];
281 trigger = getTrigger(shownId);
282 triggerData = trigger.data(classBase);
283 options = triggerData.options;
284 popup.removeClass(filterAlignmentClass);
286 themes = classTheme + options.theme.split(' ').join(" " + classTheme);
287 popup.attr('class', "" + classInstance + " " + themes);
290 xDistance = yDistance = options.popupDistance;
291 xOffset = options.popupOffset;
292 yOffset = options.popupYOffset;
293 isFixed = popup.data(dataPosition) === 'fixed';
294 popupH = popup.outerHeight();
295 popupW = popup.outerWidth();
296 popupCenter = popupW / 2;
297 winWidth = win.width();
298 winHeight = win.height();
299 winScrollTop = win.scrollTop();
300 winScrollLeft = win.scrollLeft();
301 windowPadding = options.windowPadding;
302 offset = trigger.offset();
303 selfWidth = trigger.outerWidth();
304 selfHeight = trigger.outerHeight();
305 selfY = offset.top - winScrollTop;
306 popupOffsetLeft = offset.left + selfWidth / 2;
307 popupOffsetTop = offset.top - popupH + yOffset;
308 popupY = popupH + options.popupDistance - yOffset;
309 popupDistanceTop = selfY - popupY;
310 popupDistanceBottom = winHeight - selfY - selfHeight - popupY;
311 popupDistanceLeft = offset.left - popupW - xOffset;
312 popupDistanceRight = winWidth - offset.left - selfWidth - popupW;
313 preferredPosition = options.preferredPosition;
314 if (preferredPosition === 'left' || preferredPosition === 'right') {
316 popupOffsetTop += selfHeight / 2 + popupH / 2;
317 if ((preferredPosition === 'right' && popupDistanceRight > windowPadding) || popupDistanceLeft < windowPadding) {
318 popup.addClass(classRight);
319 popupOffsetLeft = offset.left + selfWidth + xOffset;
321 popup.addClass(classLeft);
322 popupOffsetLeft = offset.left - popupW - xOffset;
323 xDistance = -xDistance;
327 if (popupOffsetLeft + popupCenter > winWidth - windowPadding) {
328 popupOffsetLeft -= popupCenter * 2 - xOffset;
329 popup.addClass(classAlignLeft);
330 } else if (popupOffsetLeft - popupCenter < windowPadding) {
331 popupOffsetLeft -= xOffset;
332 popup.addClass(classAlignRight);
334 popupOffsetLeft -= popupCenter;
336 if (popupOffsetLeft < windowPadding) {
337 popupOffsetLeft = windowPadding;
339 if ((preferredPosition === 'bottom' && popupDistanceBottom > windowPadding) || popupDistanceTop < windowPadding) {
340 yDistance = -yDistance;
341 popupOffsetTop += popupH + selfHeight - 2 * yOffset;
342 popup.addClass(classBottom);
345 if (popupH < selfHeight) {
346 yOverflow = popupOffsetTop + popupH + windowPadding - yDistance + yOffset - winScrollTop - winHeight;
348 popupOffsetTop = Math.max(popupOffsetTop - yOverflow - windowPadding, offset.top + yOffset + windowPadding + yDistance);
351 if (popupW < selfWidth) {
352 xOverflow = popupOffsetLeft + popupW + windowPadding + xDistance + xOffset - winScrollLeft - winWidth;
354 popupOffsetLeft = Math.max(popupOffsetLeft - xOverflow + windowPadding, offset.left + xOffset + windowPadding - xDistance);
357 if (options.hideTrigger) {
358 trigger.stop(true).fadeTo(options.triggerAnimationSpeed, 0);
361 if (!popupData[dataBeingShown] || options.cssAnimations.enabled) {
362 popupOffsetTop -= yDistance;
363 popupOffsetLeft += xDistance;
364 xDistance = yDistance = 0;
368 popupOffsetLeft -= winScrollLeft;
369 popupOffsetTop -= winScrollTop;
371 popup.data(dataXDistance, xDistance).data(dataYDistance, yDistance).css({
373 left: popupOffsetLeft,
377 _results.push(fadeInPopup(popup, {
378 top: "-=" + yDistance,
379 left: "+=" + xDistance,
385 forceRefreshPosition = function() {
386 return refreshPosition(false);
388 fadeInPopup = function(popup, animationTarget) {
390 options = ((_ref = getTrigger(popup.data(dataShown)).data(classBase)) != null ? _ref.options : void 0) || sip.defaults;
391 if (options.cssAnimations.enabled) {
392 popup.addClass(options.cssAnimations.show);
393 return window.setTimeout(function() {
394 return fadeInPopupFinished(popup, options);
395 }, options.popupAnimationSpeed);
397 return popup.stop(true).animate(animationTarget, options.popupAnimationSpeed, options.funcEase, function() {
398 return fadeInPopupFinished(popup, options);
402 fadeInPopupFinished = function(popup, options) {
404 popupData = popup.data();
405 if (popupData[dataBeingShown]) {
406 popup.data(dataBeingShown, false);
407 return typeof options.onAfterShow === "function" ? options.onAfterShow(getTrigger(popupData[dataShown])) : void 0;
410 showPopup = function(trigger, content) {
411 var lastTrigger, lastTriggerOpt, popup, popupContent, popupPosition, shownId, tourOverlay, triggerData, triggerOptions;
412 if (content == null) {
415 triggerData = trigger.data(classBase);
416 triggerOptions = triggerData.options;
417 popup = triggerData.popupInstance;
418 if (!popup.data(dataTriggerHovered)) {
421 shownId = popup.data(dataShown);
423 lastTrigger = getTrigger(shownId);
424 if (lastTrigger.length) {
425 lastTriggerOpt = lastTrigger.data(classBase).options || sip.defaults;
426 if (lastTriggerOpt.hideTrigger) {
427 lastTrigger.stop(true).fadeTo(lastTriggerOpt.fadeSpeed, 1);
431 if (triggerOptions.tourHighlight && triggerOptions.tourIndex) {
432 tourOverlay = getOverlay().css({
433 backgroundColor: triggerOptions.tourHighlightColor,
434 zIndex: triggerOptions.tourHighlightZIndex
437 if (trigger.css('position') === 'static') {
438 trigger.css('position', 'relative');
440 if (!trigger.data(dataZIndex)) {
441 trigger.data(dataZIndex, trigger.css('zIndex'));
443 trigger.css('zIndex', triggerOptions.tourHighlightZIndex + 1);
444 tourOverlay.fadeTo(triggerOptions.tourHighlightFadeDuration, triggerOptions.tourHighlightOpacity);
445 } else if ($overlay) {
446 hideTourOverlay(triggerOptions);
448 popupContent = content || triggerData.hint;
449 if (triggerOptions.referencedContent && !content) {
450 popupContent = $(triggerOptions.referencedContent).clone(true, true) || popupContent;
452 popupPosition = isElementFixed(trigger) ? 'fixed' : 'absolute';
453 if (shownId !== triggerData.id) {
456 popup.data(dataBeingShown, true).data(dataShown, triggerData.id).data(dataPosition, popupPosition).find('.' + classContent).empty().append(popupContent);
457 popup.css('position', popupPosition);
458 return queueRefreshPosition(0);
460 isElementFixed = function(element) {
462 elemToCheck = element;
463 while (elemToCheck.length && elemToCheck[0].nodeName.toUpperCase() !== 'HTML') {
464 if (elemToCheck.css('position') === 'fixed') {
467 elemToCheck = elemToCheck.parent();
471 triggerMouseover = function() {
472 var isTrigger, popup, shownId, trigger, triggerData, _base;
473 trigger = popup = $(this);
474 isTrigger = trigger.hasClass(classInitialized);
476 trigger = getTrigger(popup.data(dataShown));
478 if (!trigger.length) {
481 triggerData = trigger.data(classBase);
482 popup = triggerData.popupInstance.data((isTrigger ? dataTriggerHovered : dataPopupHovered), true);
484 shownId = popup.data(dataShown);
485 if (shownId !== triggerData.id || popup.css('opacity') === 0) {
486 if (typeof (_base = triggerData.options).onBeforeShow === "function") {
487 _base.onBeforeShow(trigger);
489 return popup.data(dataTimerShow, setTimeout(function() {
490 return showPopup(trigger);
491 }, triggerData.options.popupDelay));
494 triggerMouseout = function() {
495 var isTrigger, popup, popupData, trigger, triggerData, _base;
496 trigger = popup = $(this);
497 isTrigger = trigger.hasClass(classInitialized);
499 trigger = getTrigger(popup.data(dataShown));
501 if (!trigger.length) {
504 triggerData = trigger.data(classBase);
505 popup = triggerData.popupInstance.data((isTrigger ? dataTriggerHovered : dataPopupHovered), false);
507 popupData = popup.data();
508 if (!(popupData[dataPopupHovered] || popupData[dataTriggerHovered])) {
509 if (typeof (_base = triggerData.options).onBeforeHide === "function") {
510 _base.onBeforeHide(trigger);
512 return popup.data(dataTimerHide, setTimeout(function() {
513 return hideSmallipop(popup);
514 }, triggerData.options.hideDelay));
517 onWindowScroll = function(e) {
518 clearTimeout(scrollTimer);
519 return scrollTimer = setTimeout(forceRefreshPosition, 250);
521 setContent = function(trigger, content) {
522 var partOfTour, popupContent, triggerData;
523 if (!(trigger != null ? trigger.length : void 0)) {
526 triggerData = trigger.data(classBase);
527 partOfTour = triggerData.tourTitle;
529 popupContent = triggerData.popupInstance.find('.' + classTourContent);
531 popupContent = triggerData.popupInstance.find('.' + classContent);
533 if (popupContent.html() !== content) {
534 return popupContent.stop(true).fadeTo(triggerData.options.contentAnimationSpeed, 0, function() {
535 $(this).html(content).fadeTo(triggerData.options.contentAnimationSpeed, 1);
536 return refreshPosition();
540 runTour = function(trigger, step) {
541 var currentTourItems, i, tourTitle, triggerData, _i, _ref;
542 triggerData = trigger.data(classBase);
543 tourTitle = triggerData != null ? triggerData.tourTitle : void 0;
544 if (!(tourTitle && tours[tourTitle])) {
547 tours[tourTitle].sort(function(a, b) {
548 return a.index - b.index;
550 if (!(typeof step === 'number' && step % 1 === 0)) {
555 currentTour = tourTitle;
556 currentTourItems = tours[tourTitle];
557 for (i = _i = 0, _ref = currentTourItems.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
558 if ((step >= 0 && i === step) || (step < 0 && currentTourItems[i].id === triggerData.id)) {
559 return tourShow(tourTitle, i);
563 tourShow = function(title, index) {
564 var $content, $trigger, currentTourItems, navigation, navigationEnabled, options, triggerData;
565 currentTourItems = tours[title];
566 if (!currentTourItems) {
569 $trigger = currentTourItems[index].trigger;
570 triggerData = $trigger.data(classBase);
571 options = triggerData.options;
572 navigationEnabled = options.tourNavigationEnabled;
574 if (navigationEnabled) {
575 navigation += ("<div class='" + classTourProgress + "'>") + ("" + (index + 1) + " " + options.labels.of + " " + currentTourItems.length + "</div>");
577 navigation += "<a href='#' class='" + classTourPrev + "'>" + options.labels.prev + "</a>";
579 if (index < currentTourItems.length - 1) {
580 navigation += "<a href='#' class='" + classTourNext + "'>" + options.labels.next + "</a>";
583 if (!navigationEnabled || index === currentTourItems.length - 1) {
584 navigation += "<a href='#' class='" + classTourClose + "'>" + options.labels.close + "</a>";
586 $content = $(("<div class='" + classTourContent + "'/>") + ("<a href='#' class='" + classTourCloseIcon + "'>Χ</a>") + ("<div class='" + classTourFooter + "'>" + navigation + "</div>"));
587 $content.eq(0).append(triggerData.hint);
588 killTimers(triggerData.popupInstance);
589 triggerData.popupInstance.data(dataTriggerHovered, true);
590 return showWhenVisible($trigger, $content);
592 showWhenVisible = function($trigger, content) {
593 var offset, targetPosition, triggerOptions, windowHeight;
594 targetPosition = $trigger.offset().top;
595 offset = targetPosition - $document.scrollTop();
596 windowHeight = $window.height();
597 triggerOptions = $trigger.data(classBase).options;
598 if (!isElementFixed($trigger) && (offset < triggerOptions.autoscrollPadding || offset > windowHeight - triggerOptions.autoscrollPadding)) {
599 return $('html, body').animate({
600 scrollTop: targetPosition - windowHeight / 2
601 }, 800, 'swing', function() {
602 return showPopup($trigger, content);
605 return showPopup($trigger, content);
608 tourNext = function(e) {
609 var $popup, currentTourItems, i, shownId, triggerOptions, _i, _ref;
613 currentTourItems = tours[currentTour];
614 if (!currentTourItems) {
617 $popup = currentTourItems[0].popupInstance;
618 shownId = $popup.data(dataShown) || currentTourItems[0].id;
619 for (i = _i = 0, _ref = currentTourItems.length - 2; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
620 if (!(currentTourItems[i].id === shownId)) {
623 triggerOptions = currentTourItems[i].trigger.data(classBase).options;
624 if (triggerOptions.tourNavigationEnabled) {
625 if (typeof triggerOptions.onTourNext === "function") {
626 triggerOptions.onTourNext(currentTourItems[i + 1].trigger);
628 return tourShow(currentTour, i + 1);
632 tourPrev = function(e) {
633 var $popup, currentTourItems, i, shownId, triggerOptions, _i, _ref;
637 currentTourItems = tours[currentTour];
638 if (!currentTourItems) {
641 $popup = currentTourItems[0].popupInstance;
642 shownId = $popup.data(dataShown) || currentTourItems[0].id;
643 for (i = _i = 1, _ref = currentTourItems.length - 1; 1 <= _ref ? _i <= _ref : _i >= _ref; i = 1 <= _ref ? ++_i : --_i) {
644 if (!(currentTourItems[i].id === shownId)) {
647 triggerOptions = currentTourItems[i].trigger.data(classBase).options;
648 if (triggerOptions.tourNavigationEnabled) {
649 if (typeof triggerOptions.onTourPrev === "function") {
650 triggerOptions.onTourPrev(currentTourItems[i - 1].trigger);
652 return tourShow(currentTour, i - 1);
656 tourClose = function(e) {
661 $popup = $(e.target).closest("." + classInstance);
662 return hideSmallipop($popup);
664 destroy = function(instances) {
665 return instances.each(function() {
668 data = self.data(classBase);
670 return self.unbind("." + classBase).data(classBase, {}).removeClass(filterBaseClass);
674 onWindowKeyUp = function(e) {
675 var popup, popupId, targetIsInput, _ref, _results;
676 targetIsInput = (_ref = e != null ? e.target.tagName.toLowerCase() : void 0) === 'input' || _ref === 'textarea';
680 for (popupId in instances) {
681 popup = instances[popupId];
682 _results.push(hideSmallipop(popup));
687 if (!targetIsInput) {
692 if (!targetIsInput) {
697 getInstance = function(id, isTour) {
702 if (isTour == null) {
706 return instances[id];
708 instance = $(popupTemplate).css('opacity', 0).attr('id', "" + (classBase + nextInstanceId++)).addClass(classInstance).data(dataXDistance, 0).data(dataYDistance, 0).data(dataIsTour, isTour).bind(eventMouseOver, triggerMouseover).bind(eventMouseOut, triggerMouseout);
709 $('body').append(instance);
711 instance.delegate("." + classTourPrev, eventClick, tourPrev).delegate("." + classTourNext, eventClick, tourNext).delegate("." + classTourClose + ", ." + classTourCloseIcon, eventClick, tourClose);
713 instance.delegate('a', eventClick, hideSmallipop);
715 if (nextInstanceId === 2) {
716 $document.bind("" + eventClick + " " + eventTouchEnd, hideSmallipop);
717 $window.bind(eventResize, queueRefreshPosition).bind(eventScroll, onWindowScroll).bind(eventKeyUp, onWindowKeyUp);
719 return instances[id] = instance;
721 return $.fn.smallipop = function(options, hint) {
723 if (options == null) {
729 if (typeof options === 'string') {
730 switch (options.toLowerCase()) {
732 showSmallipop.call(this.first().get(0));
735 hideSmallipop(this.first().get(0));
741 runTour(this.first(), hint);
744 setContent(this.first(), hint);
748 options = $.extend(true, {}, sip.defaults, options);
749 if (!cssAnimationsEnabled) {
750 options.cssAnimations.enabled = false;
752 $popup = getInstance(options.popupId);
753 return this.each(function() {
754 var $objInfo, $self, isFormElement, newId, objHint, option, optionName, tagName, touchTrigger, tourTitle, triggerData, triggerEvents, triggerOptions, triggerPopupInstance, type, value;
756 tagName = $self[0].tagName.toLowerCase();
757 type = $self.attr('type');
758 triggerData = $self.data();
759 objHint = hint || $self.attr('title');
760 $objInfo = $("> ." + options.infoClass + ":first", $self);
761 if ($objInfo.length) {
762 objHint = $objInfo.clone(true, true).removeClass(options.infoClass);
764 if (objHint && !$self.hasClass(classInitialized)) {
767 triggerPopupInstance = $popup;
768 triggerOptions = $.extend(true, {}, options);
769 if (typeof triggerData[classBase] === 'object') {
770 $.extend(true, triggerOptions, triggerData[classBase]);
772 for (option in triggerData) {
773 value = triggerData[option];
774 if (!(option.indexOf(classBase) >= 0)) {
777 optionName = option.replace(classBase, '');
779 optionName = optionName.substr(0, 1).toLowerCase() + optionName.substr(1);
780 triggerOptions[optionName] = value;
783 isFormElement = triggerOptions.handleInputs && (tagName === 'input' || tagName === 'select' || tagName === 'textarea');
784 if (triggerOptions.tourIndex) {
785 tourTitle = triggerOptions.tourTitle || 'defaultTour';
786 triggerOptions.hideOnTriggerClick = triggerOptions.hideOnPopupClick = false;
787 triggerPopupInstance = getInstance(tourTitle, true);
788 if (!tours[tourTitle]) {
789 tours[tourTitle] = [];
791 tours[tourTitle].push({
792 index: triggerOptions.tourIndex || 0,
795 popupInstance: triggerPopupInstance
798 touchTrigger = triggerOptions.touchSupport && touchEnabled;
800 triggerOptions.hideOnTriggerClick = false;
801 triggerEvents[eventFocus] = triggerMouseover;
802 triggerEvents[eventBlur] = triggerMouseout;
803 } else if (!touchTrigger) {
804 triggerEvents[eventMouseOut] = triggerMouseout;
806 if (triggerOptions.triggerOnClick || touchTrigger) {
807 triggerEvents[eventClick] = showSmallipop;
809 triggerEvents[eventClick] = triggerMouseout;
810 triggerEvents[eventMouseOver] = triggerMouseover;
813 $self.addClass("" + classInitialized + " " + classBase + newId).attr('title', '').data(classBase, {
816 options: triggerOptions,
819 tourTitle: tourTitle,
820 popupInstance: triggerPopupInstance,
821 isFormElement: isFormElement
822 }).bind(triggerEvents);
823 if (!triggerOptions.hideOnTriggerClick) {
824 return $self.delegate('a', eventClick, hideSmallipop);