foundation.joyride.js 30 KB

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