Add deprecation notice
[web.git] / js / foundation / foundation.joyride.js
1 ;
2 (function ($, window, document, undefined) {
3 'use strict';
4
5 var Modernizr = Modernizr || false;
6
7 Foundation.libs.joyride = {
8 name: 'joyride',
9
10 version: '5.5.0',
11
12 defaults: {
13 expose: false, // turn on or off the expose feature
14 modal: true, // Whether to cover page with modal during the tour
15 keyboard: true, // enable left, right and esc keystrokes
16 tip_location: 'bottom', // 'top' or 'bottom' in relation to parent
17 nub_position: 'auto', // override on a per tooltip bases
18 scroll_speed: 1500, // Page scrolling speed in milliseconds, 0 = no scroll animation
19 scroll_animation: 'linear', // supports 'swing' and 'linear', extend with jQuery UI.
20 timer: 0, // 0 = no timer , all other numbers = timer in milliseconds
21 start_timer_on_click: true, // true or false - true requires clicking the first button start the timer
22 start_offset: 0, // the index of the tooltip you want to start on (index of the li)
23 next_button: true, // true or false to control whether a next button is used
24 prev_button: true, // true or false to control whether a prev button is used
25 tip_animation: 'fade', // 'pop' or 'fade' in each tip
26 pause_after: [], // array of indexes where to pause the tour after
27 exposed: [], // array of expose elements
28 tip_animation_fade_speed: 300, // when tipAnimation = 'fade' this is speed in milliseconds for the transition
29 cookie_monster: false, // true or false to control whether cookies are used
30 cookie_name: 'joyride', // Name the cookie you'll use
31 cookie_domain: false, // Will this cookie be attached to a domain, ie. '.notableapp.com'
32 cookie_expires: 365, // set when you would like the cookie to expire.
33 tip_container: 'body', // Where will the tip be attached
34 abort_on_close: true, // When true, the close event will not fire any callback
35 tip_location_patterns: {
36 top: ['bottom'],
37 bottom: [], // bottom should not need to be repositioned
38 left: ['right', 'top', 'bottom'],
39 right: ['left', 'top', 'bottom']
40 },
41 post_ride_callback: function () {
42 }, // A method to call once the tour closes (canceled or complete)
43 post_step_callback: function () {
44 }, // A method to call after each step
45 pre_step_callback: function () {
46 }, // A method to call before each step
47 pre_ride_callback: function () {
48 }, // A method to call before the tour starts (passed index, tip, and cloned exposed element)
49 post_expose_callback: function () {
50 }, // A method to call after an element has been exposed
51 template: { // HTML segments for tip layout
52 link: '<a href="#close" class="joyride-close-tip">&times;</a>',
53 timer: '<div class="joyride-timer-indicator-wrap"><span class="joyride-timer-indicator"></span></div>',
54 tip: '<div class="joyride-tip-guide"><span class="joyride-nub"></span></div>',
55 wrapper: '<div class="joyride-content-wrapper"></div>',
56 button: '<a href="#" class="small button joyride-next-tip"></a>',
57 prev_button: '<a href="#" class="small button joyride-prev-tip"></a>',
58 modal: '<div class="joyride-modal-bg"></div>',
59 expose: '<div class="joyride-expose-wrapper"></div>',
60 expose_cover: '<div class="joyride-expose-cover"></div>'
61 },
62 expose_add_class: '' // One or more space-separated class names to be added to exposed element
63 },
64
65 init: function (scope, method, options) {
66 Foundation.inherit(this, 'throttle random_str');
67
68 this.settings = this.settings || $.extend({}, this.defaults, (options || method));
69
70 this.bindings(method, options)
71 },
72
73 go_next: function () {
74 if (this.settings.$li.next().length < 1) {
75 this.end();
76 } else if (this.settings.timer > 0) {
77 clearTimeout(this.settings.automate);
78 this.hide();
79 this.show();
80 this.startTimer();
81 } else {
82 this.hide();
83 this.show();
84 }
85 },
86
87 go_prev: function () {
88 if (this.settings.$li.prev().length < 1) {
89 // Do nothing if there are no prev element
90 } else if (this.settings.timer > 0) {
91 clearTimeout(this.settings.automate);
92 this.hide();
93 this.show(null, true);
94 this.startTimer();
95 } else {
96 this.hide();
97 this.show(null, true);
98 }
99 },
100
101 events: function () {
102 var self = this;
103
104 $(this.scope)
105 .off('.joyride')
106 .on('click.fndtn.joyride', '.joyride-next-tip, .joyride-modal-bg', function (e) {
107 e.preventDefault();
108 this.go_next()
109 }.bind(this))
110 .on('click.fndtn.joyride', '.joyride-prev-tip', function (e) {
111 e.preventDefault();
112 this.go_prev();
113 }.bind(this))
114
115 .on('click.fndtn.joyride', '.joyride-close-tip', function (e) {
116 e.preventDefault();
117 this.end(this.settings.abort_on_close);
118 }.bind(this))
119
120 .on('keyup.fndtn.joyride', function (e) {
121 // Don't do anything if keystrokes are disabled
122 // or if the joyride is not being shown
123 if (!this.settings.keyboard || !this.settings.riding) return;
124
125 switch (e.which) {
126 case 39: // right arrow
127 e.preventDefault();
128 this.go_next();
129 break;
130 case 37: // left arrow
131 e.preventDefault();
132 this.go_prev();
133 break;
134 case 27: // escape
135 e.preventDefault();
136 this.end(this.settings.abort_on_close);
137 }
138 }.bind(this));
139
140 $(window)
141 .off('.joyride')
142 .on('resize.fndtn.joyride', self.throttle(function () {
143 if ($('[' + self.attr_name() + ']').length > 0 && self.settings.$next_tip && self.settings.riding) {
144 if (self.settings.exposed.length > 0) {
145 var $els = $(self.settings.exposed);
146
147 $els.each(function () {
148 var $this = $(this);
149 self.un_expose($this);
150 self.expose($this);
151 });
152 }
153
154 if (self.is_phone()) {
155 self.pos_phone();
156 } else {
157 self.pos_default(false);
158 }
159 }
160 }, 100));
161 },
162
163 start: function () {
164 var self = this,
165 $this = $('[' + this.attr_name() + ']', this.scope),
166 integer_settings = ['timer', 'scrollSpeed', 'startOffset', 'tipAnimationFadeSpeed', 'cookieExpires'],
167 int_settings_count = integer_settings.length;
168
169 if (!$this.length > 0) return;
170
171 if (!this.settings.init) this.events();
172
173 this.settings = $this.data(this.attr_name(true) + '-init');
174
175 // non configureable settings
176 this.settings.$content_el = $this;
177 this.settings.$body = $(this.settings.tip_container);
178 this.settings.body_offset = $(this.settings.tip_container).position();
179 this.settings.$tip_content = this.settings.$content_el.find('> li');
180 this.settings.paused = false;
181 this.settings.attempts = 0;
182 this.settings.riding = true;
183
184 // can we create cookies?
185 if (typeof $.cookie !== 'function') {
186 this.settings.cookie_monster = false;
187 }
188
189 // generate the tips and insert into dom.
190 if (!this.settings.cookie_monster || this.settings.cookie_monster && !$.cookie(this.settings.cookie_name)) {
191 this.settings.$tip_content.each(function (index) {
192 var $this = $(this);
193 this.settings = $.extend({}, self.defaults, self.data_options($this));
194
195 // Make sure that settings parsed from data_options are integers where necessary
196 var i = int_settings_count;
197 while (i--) {
198 self.settings[integer_settings[i]] = parseInt(self.settings[integer_settings[i]], 10);
199 }
200 self.create({$li: $this, index: index});
201 });
202
203 // show first tip
204 if (!this.settings.start_timer_on_click && this.settings.timer > 0) {
205 this.show('init');
206 this.startTimer();
207 } else {
208 this.show('init');
209 }
210
211 }
212 },
213
214 resume: function () {
215 this.set_li();
216 this.show();
217 },
218
219 tip_template: function (opts) {
220 var $blank, content;
221
222 opts.tip_class = opts.tip_class || '';
223
224 $blank = $(this.settings.template.tip).addClass(opts.tip_class);
225 content = $.trim($(opts.li).html()) +
226 this.prev_button_text(opts.prev_button_text, opts.index) +
227 this.button_text(opts.button_text) +
228 this.settings.template.link +
229 this.timer_instance(opts.index);
230
231 $blank.append($(this.settings.template.wrapper));
232 $blank.first().attr(this.add_namespace('data-index'), opts.index);
233 $('.joyride-content-wrapper', $blank).append(content);
234
235 return $blank[0];
236 },
237
238 timer_instance: function (index) {
239 var txt;
240
241 if ((index === 0 && this.settings.start_timer_on_click && this.settings.timer > 0) || this.settings.timer === 0) {
242 txt = '';
243 } else {
244 txt = $(this.settings.template.timer)[0].outerHTML;
245 }
246 return txt;
247 },
248
249 button_text: function (txt) {
250 if (this.settings.tip_settings.next_button) {
251 txt = $.trim(txt) || 'Next';
252 txt = $(this.settings.template.button).append(txt)[0].outerHTML;
253 } else {
254 txt = '';
255 }
256 return txt;
257 },
258
259 prev_button_text: function (txt, idx) {
260 if (this.settings.tip_settings.prev_button) {
261 txt = $.trim(txt) || 'Previous';
262
263 // Add the disabled class to the button if it's the first element
264 if (idx == 0)
265 txt = $(this.settings.template.prev_button).append(txt).addClass('disabled')[0].outerHTML;
266 else
267 txt = $(this.settings.template.prev_button).append(txt)[0].outerHTML;
268 } else {
269 txt = '';
270 }
271 return txt;
272 },
273
274 create: function (opts) {
275 this.settings.tip_settings = $.extend({}, this.settings, this.data_options(opts.$li));
276 var buttonText = opts.$li.attr(this.add_namespace('data-button'))
277 || opts.$li.attr(this.add_namespace('data-text')),
278 prevButtonText = opts.$li.attr(this.add_namespace('data-button-prev'))
279 || opts.$li.attr(this.add_namespace('data-prev-text')),
280 tipClass = opts.$li.attr('class'),
281 $tip_content = $(this.tip_template({
282 tip_class: tipClass,
283 index: opts.index,
284 button_text: buttonText,
285 prev_button_text: prevButtonText,
286 li: opts.$li
287 }));
288
289 $(this.settings.tip_container).append($tip_content);
290 },
291
292 show: function (init, is_prev) {
293 var $timer = null;
294
295 // are we paused?
296 if (this.settings.$li === undefined
297 || ($.inArray(this.settings.$li.index(), this.settings.pause_after) === -1)) {
298
299 // don't go to the next li if the tour was paused
300 if (this.settings.paused) {
301 this.settings.paused = false;
302 } else {
303 this.set_li(init, is_prev);
304 }
305
306 this.settings.attempts = 0;
307
308 if (this.settings.$li.length && this.settings.$target.length > 0) {
309 if (init) { //run when we first start
310 this.settings.pre_ride_callback(this.settings.$li.index(), this.settings.$next_tip);
311 if (this.settings.modal) {
312 this.show_modal();
313 }
314 }
315
316 this.settings.pre_step_callback(this.settings.$li.index(), this.settings.$next_tip);
317
318 if (this.settings.modal && this.settings.expose) {
319 this.expose();
320 }
321
322 this.settings.tip_settings = $.extend({}, this.settings, this.data_options(this.settings.$li));
323
324 this.settings.timer = parseInt(this.settings.timer, 10);
325
326 this.settings.tip_settings.tip_location_pattern = this.settings.tip_location_patterns[this.settings.tip_settings.tip_location];
327
328 // scroll and hide bg if not modal
329 if (!/body/i.test(this.settings.$target.selector)) {
330 var joyridemodalbg = $('.joyride-modal-bg');
331 if (/pop/i.test(this.settings.tipAnimation)) {
332 joyridemodalbg.hide();
333 } else {
334 joyridemodalbg.fadeOut(this.settings.tipAnimationFadeSpeed);
335 }
336 this.scroll_to();
337 }
338
339 if (this.is_phone()) {
340 this.pos_phone(true);
341 } else {
342 this.pos_default(true);
343 }
344
345 $timer = this.settings.$next_tip.find('.joyride-timer-indicator');
346
347 if (/pop/i.test(this.settings.tip_animation)) {
348
349 $timer.width(0);
350
351 if (this.settings.timer > 0) {
352
353 this.settings.$next_tip.show();
354
355 setTimeout(function () {
356 $timer.animate({
357 width: $timer.parent().width()
358 }, this.settings.timer, 'linear');
359 }.bind(this), this.settings.tip_animation_fade_speed);
360
361 } else {
362 this.settings.$next_tip.show();
363
364 }
365
366
367 } else if (/fade/i.test(this.settings.tip_animation)) {
368
369 $timer.width(0);
370
371 if (this.settings.timer > 0) {
372
373 this.settings.$next_tip
374 .fadeIn(this.settings.tip_animation_fade_speed)
375 .show();
376
377 setTimeout(function () {
378 $timer.animate({
379 width: $timer.parent().width()
380 }, this.settings.timer, 'linear');
381 }.bind(this), this.settings.tip_animation_fade_speed);
382
383 } else {
384 this.settings.$next_tip.fadeIn(this.settings.tip_animation_fade_speed);
385 }
386 }
387
388 this.settings.$current_tip = this.settings.$next_tip;
389
390 // skip non-existant targets
391 } else if (this.settings.$li && this.settings.$target.length < 1) {
392
393 this.show(init, is_prev);
394
395 } else {
396
397 this.end();
398
399 }
400 } else {
401
402 this.settings.paused = true;
403
404 }
405
406 },
407
408 is_phone: function () {
409 return matchMedia(Foundation.media_queries.small).matches && !matchMedia(Foundation.media_queries.medium).matches;
410 },
411
412 hide: function () {
413 if (this.settings.modal && this.settings.expose) {
414 this.un_expose();
415 }
416
417 if (!this.settings.modal) {
418 $('.joyride-modal-bg').hide();
419 }
420
421 // Prevent scroll bouncing...wait to remove from layout
422 this.settings.$current_tip.css('visibility', 'hidden');
423 setTimeout($.proxy(function () {
424 this.hide();
425 this.css('visibility', 'visible');
426 }, this.settings.$current_tip), 0);
427 this.settings.post_step_callback(this.settings.$li.index(),
428 this.settings.$current_tip);
429 },
430
431 set_li: function (init, is_prev) {
432 if (init) {
433 this.settings.$li = this.settings.$tip_content.eq(this.settings.start_offset);
434 this.set_next_tip();
435 this.settings.$current_tip = this.settings.$next_tip;
436 } else {
437 if (is_prev)
438 this.settings.$li = this.settings.$li.prev();
439 else
440 this.settings.$li = this.settings.$li.next();
441 this.set_next_tip();
442 }
443
444 this.set_target();
445 },
446
447 set_next_tip: function () {
448 this.settings.$next_tip = $('.joyride-tip-guide').eq(this.settings.$li.index());
449 this.settings.$next_tip.data('closed', '');
450 },
451
452 set_target: function () {
453 var cl = this.settings.$li.attr(this.add_namespace('data-class')),
454 id = this.settings.$li.attr(this.add_namespace('data-id')),
455 $sel = function () {
456 if (id) {
457 return $(document.getElementById(id));
458 } else if (cl) {
459 return $('.' + cl).first();
460 } else {
461 return $('body');
462 }
463 };
464
465 this.settings.$target = $sel();
466 },
467
468 scroll_to: function () {
469 var window_half, tipOffset;
470
471 window_half = $(window).height() / 2;
472 tipOffset = Math.ceil(this.settings.$target.offset().top - window_half + this.settings.$next_tip.outerHeight());
473
474 if (tipOffset != 0) {
475 $('html, body').stop().animate({
476 scrollTop: tipOffset
477 }, this.settings.scroll_speed, 'swing');
478 }
479 },
480
481 paused: function () {
482 return ($.inArray((this.settings.$li.index() + 1), this.settings.pause_after) === -1);
483 },
484
485 restart: function () {
486 this.hide();
487 this.settings.$li = undefined;
488 this.show('init');
489 },
490
491 pos_default: function (init) {
492 var $nub = this.settings.$next_tip.find('.joyride-nub'),
493 nub_width = Math.ceil($nub.outerWidth() / 2),
494 nub_height = Math.ceil($nub.outerHeight() / 2),
495 toggle = init || false;
496
497 // tip must not be "display: none" to calculate position
498 if (toggle) {
499 this.settings.$next_tip.css('visibility', 'hidden');
500 this.settings.$next_tip.show();
501 }
502
503 if (!/body/i.test(this.settings.$target.selector)) {
504 var topAdjustment = this.settings.tip_settings.tipAdjustmentY ? parseInt(this.settings.tip_settings.tipAdjustmentY) : 0,
505 leftAdjustment = this.settings.tip_settings.tipAdjustmentX ? parseInt(this.settings.tip_settings.tipAdjustmentX) : 0;
506
507 if (this.bottom()) {
508 if (this.rtl) {
509 this.settings.$next_tip.css({
510 top: (this.settings.$target.offset().top + nub_height + this.settings.$target.outerHeight() + topAdjustment),
511 left: this.settings.$target.offset().left + this.settings.$target.outerWidth() - this.settings.$next_tip.outerWidth() + leftAdjustment
512 });
513 } else {
514 this.settings.$next_tip.css({
515 top: (this.settings.$target.offset().top + nub_height + this.settings.$target.outerHeight() + topAdjustment),
516 left: this.settings.$target.offset().left + leftAdjustment
517 });
518 }
519
520 this.nub_position($nub, this.settings.tip_settings.nub_position, 'top');
521
522 } else if (this.top()) {
523 if (this.rtl) {
524 this.settings.$next_tip.css({
525 top: (this.settings.$target.offset().top - this.settings.$next_tip.outerHeight() - nub_height + topAdjustment),
526 left: this.settings.$target.offset().left + this.settings.$target.outerWidth() - this.settings.$next_tip.outerWidth()
527 });
528 } else {
529 this.settings.$next_tip.css({
530 top: (this.settings.$target.offset().top - this.settings.$next_tip.outerHeight() - nub_height + topAdjustment),
531 left: this.settings.$target.offset().left + leftAdjustment
532 });
533 }
534
535 this.nub_position($nub, this.settings.tip_settings.nub_position, 'bottom');
536
537 } else if (this.right()) {
538
539 this.settings.$next_tip.css({
540 top: this.settings.$target.offset().top + topAdjustment,
541 left: (this.settings.$target.outerWidth() + this.settings.$target.offset().left + nub_width + leftAdjustment)
542 });
543
544 this.nub_position($nub, this.settings.tip_settings.nub_position, 'left');
545
546 } else if (this.left()) {
547
548 this.settings.$next_tip.css({
549 top: this.settings.$target.offset().top + topAdjustment,
550 left: (this.settings.$target.offset().left - this.settings.$next_tip.outerWidth() - nub_width + leftAdjustment)
551 });
552
553 this.nub_position($nub, this.settings.tip_settings.nub_position, 'right');
554
555 }
556
557 if (!this.visible(this.corners(this.settings.$next_tip)) && this.settings.attempts < this.settings.tip_settings.tip_location_pattern.length) {
558
559 $nub.removeClass('bottom')
560 .removeClass('top')
561 .removeClass('right')
562 .removeClass('left');
563
564 this.settings.tip_settings.tip_location = this.settings.tip_settings.tip_location_pattern[this.settings.attempts];
565
566 this.settings.attempts++;
567
568 this.pos_default();
569
570 }
571
572 } else if (this.settings.$li.length) {
573
574 this.pos_modal($nub);
575
576 }
577
578 if (toggle) {
579 this.settings.$next_tip.hide();
580 this.settings.$next_tip.css('visibility', 'visible');
581 }
582
583 },
584
585 pos_phone: function (init) {
586 var tip_height = this.settings.$next_tip.outerHeight(),
587 tip_offset = this.settings.$next_tip.offset(),
588 target_height = this.settings.$target.outerHeight(),
589 $nub = $('.joyride-nub', this.settings.$next_tip),
590 nub_height = Math.ceil($nub.outerHeight() / 2),
591 toggle = init || false;
592
593 $nub.removeClass('bottom')
594 .removeClass('top')
595 .removeClass('right')
596 .removeClass('left');
597
598 if (toggle) {
599 this.settings.$next_tip.css('visibility', 'hidden');
600 this.settings.$next_tip.show();
601 }
602
603 if (!/body/i.test(this.settings.$target.selector)) {
604
605 if (this.top()) {
606
607 this.settings.$next_tip.offset({top: this.settings.$target.offset().top - tip_height - nub_height});
608 $nub.addClass('bottom');
609
610 } else {
611
612 this.settings.$next_tip.offset({top: this.settings.$target.offset().top + target_height + nub_height});
613 $nub.addClass('top');
614
615 }
616
617 } else if (this.settings.$li.length) {
618 this.pos_modal($nub);
619 }
620
621 if (toggle) {
622 this.settings.$next_tip.hide();
623 this.settings.$next_tip.css('visibility', 'visible');
624 }
625 },
626
627 pos_modal: function ($nub) {
628 this.center();
629 $nub.hide();
630
631 this.show_modal();
632 },
633
634 show_modal: function () {
635 if (!this.settings.$next_tip.data('closed')) {
636 var joyridemodalbg = $('.joyride-modal-bg');
637 if (joyridemodalbg.length < 1) {
638 var joyridemodalbg = $(this.settings.template.modal);
639 joyridemodalbg.appendTo('body');
640 }
641
642 if (/pop/i.test(this.settings.tip_animation)) {
643 joyridemodalbg.show();
644 } else {
645 joyridemodalbg.fadeIn(this.settings.tip_animation_fade_speed);
646 }
647 }
648 },
649
650 expose: function () {
651 var expose,
652 exposeCover,
653 el,
654 origCSS,
655 origClasses,
656 randId = 'expose-' + this.random_str(6);
657
658 if (arguments.length > 0 && arguments[0] instanceof $) {
659 el = arguments[0];
660 } else if (this.settings.$target && !/body/i.test(this.settings.$target.selector)) {
661 el = this.settings.$target;
662 } else {
663 return false;
664 }
665
666 if (el.length < 1) {
667 if (window.console) {
668 console.error('element not valid', el);
669 }
670 return false;
671 }
672
673 expose = $(this.settings.template.expose);
674 this.settings.$body.append(expose);
675 expose.css({
676 top: el.offset().top,
677 left: el.offset().left,
678 width: el.outerWidth(true),
679 height: el.outerHeight(true)
680 });
681
682 exposeCover = $(this.settings.template.expose_cover);
683
684 origCSS = {
685 zIndex: el.css('z-index'),
686 position: el.css('position')
687 };
688
689 origClasses = el.attr('class') == null ? '' : el.attr('class');
690
691 el.css('z-index', parseInt(expose.css('z-index')) + 1);
692
693 if (origCSS.position == 'static') {
694 el.css('position', 'relative');
695 }
696
697 el.data('expose-css', origCSS);
698 el.data('orig-class', origClasses);
699 el.attr('class', origClasses + ' ' + this.settings.expose_add_class);
700
701 exposeCover.css({
702 top: el.offset().top,
703 left: el.offset().left,
704 width: el.outerWidth(true),
705 height: el.outerHeight(true)
706 });
707
708 if (this.settings.modal) this.show_modal();
709
710 this.settings.$body.append(exposeCover);
711 expose.addClass(randId);
712 exposeCover.addClass(randId);
713 el.data('expose', randId);
714 this.settings.post_expose_callback(this.settings.$li.index(), this.settings.$next_tip, el);
715 this.add_exposed(el);
716 },
717
718 un_expose: function () {
719 var exposeId,
720 el,
721 expose,
722 origCSS,
723 origClasses,
724 clearAll = false;
725
726 if (arguments.length > 0 && arguments[0] instanceof $) {
727 el = arguments[0];
728 } else if (this.settings.$target && !/body/i.test(this.settings.$target.selector)) {
729 el = this.settings.$target;
730 } else {
731 return false;
732 }
733
734 if (el.length < 1) {
735 if (window.console) {
736 console.error('element not valid', el);
737 }
738 return false;
739 }
740
741 exposeId = el.data('expose');
742 expose = $('.' + exposeId);
743
744 if (arguments.length > 1) {
745 clearAll = arguments[1];
746 }
747
748 if (clearAll === true) {
749 $('.joyride-expose-wrapper,.joyride-expose-cover').remove();
750 } else {
751 expose.remove();
752 }
753
754 origCSS = el.data('expose-css');
755
756 if (origCSS.zIndex == 'auto') {
757 el.css('z-index', '');
758 } else {
759 el.css('z-index', origCSS.zIndex);
760 }
761
762 if (origCSS.position != el.css('position')) {
763 if (origCSS.position == 'static') {// this is default, no need to set it.
764 el.css('position', '');
765 } else {
766 el.css('position', origCSS.position);
767 }
768 }
769
770 origClasses = el.data('orig-class');
771 el.attr('class', origClasses);
772 el.removeData('orig-classes');
773
774 el.removeData('expose');
775 el.removeData('expose-z-index');
776 this.remove_exposed(el);
777 },
778
779 add_exposed: function (el) {
780 this.settings.exposed = this.settings.exposed || [];
781 if (el instanceof $ || typeof el === 'object') {
782 this.settings.exposed.push(el[0]);
783 } else if (typeof el == 'string') {
784 this.settings.exposed.push(el);
785 }
786 },
787
788 remove_exposed: function (el) {
789 var search, i;
790 if (el instanceof $) {
791 search = el[0]
792 } else if (typeof el == 'string') {
793 search = el;
794 }
795
796 this.settings.exposed = this.settings.exposed || [];
797 i = this.settings.exposed.length;
798
799 while (i--) {
800 if (this.settings.exposed[i] == search) {
801 this.settings.exposed.splice(i, 1);
802 return;
803 }
804 }
805 },
806
807 center: function () {
808 var $w = $(window);
809
810 this.settings.$next_tip.css({
811 top: ((($w.height() - this.settings.$next_tip.outerHeight()) / 2) + $w.scrollTop()),
812 left: ((($w.width() - this.settings.$next_tip.outerWidth()) / 2) + $w.scrollLeft())
813 });
814
815 return true;
816 },
817
818 bottom: function () {
819 return /bottom/i.test(this.settings.tip_settings.tip_location);
820 },
821
822 top: function () {
823 return /top/i.test(this.settings.tip_settings.tip_location);
824 },
825
826 right: function () {
827 return /right/i.test(this.settings.tip_settings.tip_location);
828 },
829
830 left: function () {
831 return /left/i.test(this.settings.tip_settings.tip_location);
832 },
833
834 corners: function (el) {
835 var w = $(window),
836 window_half = w.height() / 2,
837 //using this to calculate since scroll may not have finished yet.
838 tipOffset = Math.ceil(this.settings.$target.offset().top - window_half + this.settings.$next_tip.outerHeight()),
839 right = w.width() + w.scrollLeft(),
840 offsetBottom = w.height() + tipOffset,
841 bottom = w.height() + w.scrollTop(),
842 top = w.scrollTop();
843
844 if (tipOffset < top) {
845 if (tipOffset < 0) {
846 top = 0;
847 } else {
848 top = tipOffset;
849 }
850 }
851
852 if (offsetBottom > bottom) {
853 bottom = offsetBottom;
854 }
855
856 return [
857 el.offset().top < top,
858 right < el.offset().left + el.outerWidth(),
859 bottom < el.offset().top + el.outerHeight(),
860 w.scrollLeft() > el.offset().left
861 ];
862 },
863
864 visible: function (hidden_corners) {
865 var i = hidden_corners.length;
866
867 while (i--) {
868 if (hidden_corners[i]) return false;
869 }
870
871 return true;
872 },
873
874 nub_position: function (nub, pos, def) {
875 if (pos === 'auto') {
876 nub.addClass(def);
877 } else {
878 nub.addClass(pos);
879 }
880 },
881
882 startTimer: function () {
883 if (this.settings.$li.length) {
884 this.settings.automate = setTimeout(function () {
885 this.hide();
886 this.show();
887 this.startTimer();
888 }.bind(this), this.settings.timer);
889 } else {
890 clearTimeout(this.settings.automate);
891 }
892 },
893
894 end: function (abort) {
895 if (this.settings.cookie_monster) {
896 $.cookie(this.settings.cookie_name, 'ridden', {
897 expires: this.settings.cookie_expires,
898 domain: this.settings.cookie_domain
899 });
900 }
901
902 if (this.settings.timer > 0) {
903 clearTimeout(this.settings.automate);
904 }
905
906 if (this.settings.modal && this.settings.expose) {
907 this.un_expose();
908 }
909
910 // Unplug keystrokes listener
911 $(this.scope).off('keyup.joyride')
912
913 this.settings.$next_tip.data('closed', true);
914 this.settings.riding = false;
915
916 $('.joyride-modal-bg').hide();
917 this.settings.$current_tip.hide();
918
919 if (typeof abort === 'undefined' || abort === false) {
920 this.settings.post_step_callback(this.settings.$li.index(), this.settings.$current_tip);
921 this.settings.post_ride_callback(this.settings.$li.index(), this.settings.$current_tip);
922 }
923
924 $('.joyride-tip-guide').remove();
925 },
926
927 off: function () {
928 $(this.scope).off('.joyride');
929 $(window).off('.joyride');
930 $('.joyride-close-tip, .joyride-next-tip, .joyride-modal-bg').off('.joyride');
931 $('.joyride-tip-guide, .joyride-modal-bg').remove();
932 clearTimeout(this.settings.automate);
933 this.settings = {};
934 },
935
936 reflow: function () {
937 }
938 };
939 }(jQuery, window, window.document));