Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / ui / new_ui / ui / javascripts / foundation / foundation.joyride.js @ e4a6c3b8

History | View | Annotate | Download (18.9 kB)

1
/*jslint unparam: true, browser: true, indent: 2 */
2

    
3
;(function ($, window, document, undefined) {
4
  'use strict';
5

    
6
  Foundation.libs.joyride = {
7
    name: 'joyride',
8

    
9
    version : '4.0.0',
10

    
11
    defaults : {
12
      tipLocation          : 'bottom',  // 'top' or 'bottom' in relation to parent
13
      nubPosition          : 'auto',    // override on a per tooltip bases
14
      scrollSpeed          : 300,       // Page scrolling speed in milliseconds
15
      timer                : 0,         // 0 = no timer , all other numbers = timer in milliseconds
16
      startTimerOnClick    : true,      // true or false - true requires clicking the first button start the timer
17
      startOffset          : 0,         // the index of the tooltip you want to start on (index of the li)
18
      nextButton           : true,      // true or false to control whether a next button is used
19
      tipAnimation         : 'fade',    // 'pop' or 'fade' in each tip
20
      pauseAfter           : [],        // array of indexes where to pause the tour after
21
      tipAnimationFadeSpeed: 300,       // when tipAnimation = 'fade' this is speed in milliseconds for the transition
22
      cookieMonster        : false,     // true or false to control whether cookies are used
23
      cookieName           : 'joyride', // Name the cookie you'll use
24
      cookieDomain         : false,     // Will this cookie be attached to a domain, ie. '.notableapp.com'
25
      cookieExpires        : 365,       // set when you would like the cookie to expire.
26
      tipContainer         : 'body',    // Where will the tip be attached
27
      postRideCallback     : function (){},    // A method to call once the tour closes (canceled or complete)
28
      postStepCallback     : function (){},    // A method to call after each step
29
      template : { // HTML segments for tip layout
30
        link    : '<a href="#close" class="joyride-close-tip">&times;</a>',
31
        timer   : '<div class="joyride-timer-indicator-wrap"><span class="joyride-timer-indicator"></span></div>',
32
        tip     : '<div class="joyride-tip-guide"><span class="joyride-nub"></span></div>',
33
        wrapper : '<div class="joyride-content-wrapper"></div>',
34
        button  : '<a href="#" class="small button joyride-next-tip"></a>'
35
      }
36
    },
37

    
38
    settings : {},
39

    
40
    init : function (scope, method, options) {
41
      this.scope = scope || this.scope;
42
      Foundation.inherit(this, 'throttle data_options scrollTo scrollLeft delay');
43

    
44
      if (typeof method === 'object') {
45
        $.extend(true, this.settings, this.defaults, method);
46
      } else {
47
        $.extend(true, this.settings, this.defaults, options);
48
      }
49

    
50
      if (typeof method != 'string') {
51
        if (!this.settings.init) this.events();
52

    
53
        return this.settings.init;
54
      } else {
55
        return this[method].call(this, options);
56
      }
57
    },
58

    
59
    events : function () {
60
      var self = this;
61

    
62
      $(this.scope)
63
        .on('click.joyride', '.joyride-next-tip, .joyride-modal-bg', function (e) {
64
          e.preventDefault();
65

    
66
          if (this.settings.$li.next().length < 1) {
67
            this.end();
68
          } else if (this.settings.timer > 0) {
69
            clearTimeout(this.settings.automate);
70
            this.hide();
71
            this.show();
72
            this.startTimer();
73
          } else {
74
            this.hide();
75
            this.show();
76
          }
77

    
78
        }.bind(this))
79

    
80
        .on('click.joyride', '.joyride-close-tip', function (e) {
81
          e.preventDefault();
82
          this.end();
83
        }.bind(this));
84

    
85
      $(window).on('resize.fndtn.joyride', self.throttle(function () {
86
        if ($('[data-joyride]').length > 0 && self.settings.$next_tip) {
87
          if (self.is_phone()) {
88
            self.pos_phone();
89
          } else {
90
            self.pos_default();
91
          }
92
        }
93
      }, 100));
94

    
95
      this.settings.init = true;
96
    },
97

    
98
    start : function () {
99
      var self = this,
100
          $this = $(this.scope).find('[data-joyride]'),
101
          integer_settings = ['timer', 'scrollSpeed', 'startOffset', 'tipAnimationFadeSpeed', 'cookieExpires'],
102
          int_settings_count = integer_settings.length;
103

    
104
      if (!this.settings.init) this.init();
105
      
106
      // non configureable settings
107
      this.settings.$content_el = $this;
108
      this.settings.body_offset = $(this.settings.tipContainer).position();
109
      this.settings.$tip_content = this.settings.$content_el.find('> li');
110
      this.settings.paused = false;
111
      this.settings.attempts = 0;
112

    
113
      this.settings.tipLocationPatterns = {
114
        top: ['bottom'],
115
        bottom: [], // bottom should not need to be repositioned
116
        left: ['right', 'top', 'bottom'],
117
        right: ['left', 'top', 'bottom']
118
      };
119

    
120
      // can we create cookies?
121
      if (typeof $.cookie !== 'function') {
122
        this.settings.cookieMonster = false;
123
      }
124

    
125
      // generate the tips and insert into dom.
126
      if (!this.settings.cookieMonster || this.settings.cookieMonster && $.cookie(this.settings.cookieName) === null) {
127
        this.settings.$tip_content.each(function (index) {
128
          var $this = $(this);
129
          $.extend(true, self.settings, self.data_options($this));
130
          // Make sure that settings parsed from data_options are integers where necessary
131
          for (var i = int_settings_count - 1; i >= 0; i--) {
132
            self.settings[integer_settings[i]] = parseInt(self.settings[integer_settings[i]], 10);
133
          }
134
          self.create({$li : $this, index : index});
135
        });
136

    
137
        // show first tip
138
        if (!this.settings.startTimerOnClick && this.settings.timer > 0) {
139
          this.show('init');
140
          this.startTimer();
141
        } else {
142
          this.show('init');
143
        }
144

    
145
      }
146
    },
147

    
148
    resume : function () {
149
      this.set_li();
150
      this.show();
151
    },
152

    
153
    tip_template : function (opts) {
154
      var $blank, content;
155

    
156
      opts.tip_class = opts.tip_class || '';
157

    
158
      $blank = $(this.settings.template.tip).addClass(opts.tip_class);
159
      content = $.trim($(opts.li).html()) +
160
        this.button_text(opts.button_text) +
161
        this.settings.template.link +
162
        this.timer_instance(opts.index);
163

    
164
      $blank.append($(this.settings.template.wrapper));
165
      $blank.first().attr('data-index', opts.index);
166
      $('.joyride-content-wrapper', $blank).append(content);
167

    
168
      return $blank[0];
169
    },
170

    
171
    timer_instance : function (index) {
172
      var txt;
173

    
174
      if ((index === 0 && this.settings.startTimerOnClick && this.settings.timer > 0) || this.settings.timer === 0) {
175
        txt = '';
176
      } else {
177
        txt = this.outerHTML($(this.settings.template.timer)[0]);
178
      }
179
      return txt;
180
    },
181

    
182
    button_text : function (txt) {
183
      if (this.settings.nextButton) {
184
        txt = $.trim(txt) || 'Next';
185
        txt = this.outerHTML($(this.settings.template.button).append(txt)[0]);
186
      } else {
187
        txt = '';
188
      }
189
      return txt;
190
    },
191

    
192
    create : function (opts) {
193
      var buttonText = opts.$li.attr('data-button') || opts.$li.attr('data-text'),
194
        tipClass = opts.$li.attr('class'),
195
        $tip_content = $(this.tip_template({
196
          tip_class : tipClass,
197
          index : opts.index,
198
          button_text : buttonText,
199
          li : opts.$li
200
        }));
201

    
202
      $(this.settings.tipContainer).append($tip_content);
203
    },
204

    
205
    show : function (init) {
206
      var $timer = null;
207

    
208
      // are we paused?
209
      if (this.settings.$li === undefined
210
        || ($.inArray(this.settings.$li.index(), this.settings.pauseAfter) === -1)) {
211

    
212
        // don't go to the next li if the tour was paused
213
        if (this.settings.paused) {
214
          this.settings.paused = false;
215
        } else {
216
          this.set_li(init);
217
        }
218

    
219
        this.settings.attempts = 0;
220

    
221
        if (this.settings.$li.length && this.settings.$target.length > 0) {
222

    
223
          this.settings.tipSettings = $.extend(this.settings, this.data_options(this.settings.$li));
224

    
225
          this.settings.timer = parseInt(this.settings.timer, 10);
226

    
227
          this.settings.tipSettings.tipLocationPattern = this.settings.tipLocationPatterns[this.settings.tipSettings.tipLocation];
228

    
229
          // scroll if not modal
230
          if (!/body/i.test(this.settings.$target.selector)) {
231
            this.scroll_to();
232
          }
233

    
234
          if (this.is_phone()) {
235
            this.pos_phone(true);
236
          } else {
237
            this.pos_default(true);
238
          }
239

    
240
          $timer = this.settings.$next_tip.find('.joyride-timer-indicator');
241

    
242
          if (/pop/i.test(this.settings.tipAnimation)) {
243

    
244
            $timer.width(0);
245

    
246
            if (thsi.settings.timer > 0) {
247

    
248
              this.settings.$next_tip.show();
249

    
250
              this.delay(function () {
251
                $timer.animate({
252
                  width: $timer.parent().width()
253
                }, this.settings.timer, 'linear');
254
              }.bind(this), this.settings.tipAnimationFadeSpeed);
255

    
256
            } else {
257
              this.settings.$next_tip.show();
258

    
259
            }
260

    
261

    
262
          } else if (/fade/i.test(this.settings.tipAnimation)) {
263

    
264
            $timer.width(0);
265

    
266
            if (this.settings.timer > 0) {
267

    
268
              this.settings.$next_tip
269
                .fadeIn(this.settings.tipAnimationFadeSpeed)
270
                .show();
271

    
272
              this.delay(function () {
273
                $timer.animate({
274
                  width: $timer.parent().width()
275
                }, this.settings.timer, 'linear');
276
              }.bind(this), this.settings.tipAnimationFadeSpeed);
277

    
278
            } else {
279
              this.settings.$next_tip.fadeIn(this.settings.tipAnimationFadeSpeed);
280

    
281
            }
282
          }
283

    
284
          this.settings.$current_tip = this.settings.$next_tip;
285

    
286
        // skip non-existant targets
287
        } else if (this.settings.$li && this.settings.$target.length < 1) {
288

    
289
          this.show();
290

    
291
        } else {
292

    
293
          this.end();
294

    
295
        }
296
      } else {
297

    
298
        this.settings.paused = true;
299

    
300
      }
301

    
302
    },
303

    
304
    is_phone : function () {
305
      if (Modernizr) {
306
        return Modernizr.mq('only screen and (max-width: 767px)') || $('.lt-ie9').length > 0;
307
      }
308

    
309
      return (this.settings.$window.width() < 767) ? true : false;
310
    },
311

    
312
    hide : function () {
313
      this.settings.postStepCallback(this.settings.$li.index(),
314
        this.settings.$current_tip);
315
      $('.joyride-modal-bg').hide();
316
      this.settings.$current_tip.hide();
317
    },
318

    
319
    set_li : function (init) {
320
      if (init) {
321
        this.settings.$li = this.settings.$tip_content.eq(this.settings.startOffset);
322
        this.set_next_tip();
323
        this.settings.$current_tip = this.settings.$next_tip;
324
      } else {
325
        this.settings.$li = this.settings.$li.next();
326
        this.set_next_tip();
327
      }
328

    
329
      this.set_target();
330
    },
331

    
332
    set_next_tip : function () {
333
      this.settings.$next_tip = $(".joyride-tip-guide[data-index='" + this.settings.$li.index() + "']");
334
      this.settings.$next_tip.data('closed', '');
335
    },
336

    
337
    set_target : function () {
338
      var cl = this.settings.$li.attr('data-class'),
339
          id = this.settings.$li.attr('data-id'),
340
          $sel = function () {
341
            if (id) {
342
              return $(document.getElementById(id));
343
            } else if (cl) {
344
              return $('.' + cl).first();
345
            } else {
346
              return $('body');
347
            }
348
          };
349

    
350
      this.settings.$target = $sel();
351
    },
352

    
353
    scroll_to : function () {
354
      var window_half, tipOffset;
355

    
356
      window_half = $(window).height() / 2;
357
      tipOffset = Math.ceil(this.settings.$target.offset().top - window_half + this.outerHeight(this.settings.$next_tip));
358
      if (tipOffset > 0) {
359
        this.scrollTo($('html, body'), tipOffset, this.settings.scrollSpeed);
360
      }
361
    },
362

    
363
    paused : function () {
364
      if (($.inArray((this.settings.$li.index() + 1), this.settings.pauseAfter) === -1)) {
365
        return true;
366
      }
367

    
368
      return false;
369
    },
370

    
371
    restart : function () {
372
      this.hide();
373
      this.settings.$li = undefined;
374
      this.show('init');
375
    },
376

    
377
    pos_default : function (init) {
378
      var half_fold = Math.ceil($(window).height() / 2),
379
          tip_position = this.settings.$next_tip.offset(),
380
          $nub = this.settings.$next_tip.find('.joyride-nub'),
381
          nub_height = Math.ceil(this.outerHeight($nub) / 2),
382
          toggle = init || false;
383

    
384
      // tip must not be "display: none" to calculate position
385
      if (toggle) {
386
        this.settings.$next_tip.css('visibility', 'hidden');
387
        this.settings.$next_tip.show();
388
      }
389

    
390
      if (!/body/i.test(this.settings.$target.selector)) {
391

    
392
          if (this.bottom()) {
393
            this.settings.$next_tip.css({
394
              top: (this.settings.$target.offset().top + nub_height + this.outerHeight(this.settings.$target)),
395
              left: this.settings.$target.offset().left});
396

    
397
            this.nub_position($nub, this.settings.tipSettings.nubPosition, 'top');
398

    
399
          } else if (this.top()) {
400

    
401
            this.settings.$next_tip.css({
402
              top: (this.settings.$target.offset().top - this.outerHeight(this.settings.$next_tip) - nub_height),
403
              left: this.settings.$target.offset().left});
404

    
405
            this.nub_position($nub, this.settings.tipSettings.nubPosition, 'bottom');
406

    
407
          } else if (this.right()) {
408

    
409
            this.settings.$next_tip.css({
410
              top: this.settings.$target.offset().top,
411
              left: (this.outerWidth(this.settings.$target) + this.settings.$target.offset().left)});
412

    
413
            this.nub_position($nub, this.settings.tipSettings.nubPosition, 'left');
414

    
415
          } else if (this.left()) {
416

    
417
            this.settings.$next_tip.css({
418
              top: this.settings.$target.offset().top,
419
              left: (this.settings.$target.offset().left - this.outerWidth(this.settings.$next_tip) - nub_height)});
420

    
421
            this.nub_position($nub, this.settings.tipSettings.nubPosition, 'right');
422

    
423
          }
424

    
425
          if (!this.visible(this.corners(this.settings.$next_tip)) && this.settings.attempts < this.settings.tipSettings.tipLocationPattern.length) {
426

    
427
            $nub.removeClass('bottom')
428
              .removeClass('top')
429
              .removeClass('right')
430
              .removeClass('left');
431

    
432
            this.settings.tipSettings.tipLocation = this.settings.tipSettings.tipLocationPattern[this.settings.attempts];
433

    
434
            this.settings.attempts++;
435

    
436
            this.pos_default(true);
437

    
438
          }
439

    
440
      } else if (this.settings.$li.length) {
441

    
442
        this.pos_modal($nub);
443

    
444
      }
445

    
446
      if (toggle) {
447
        this.settings.$next_tip.hide();
448
        this.settings.$next_tip.css('visibility', 'visible');
449
      }
450

    
451
    },
452

    
453
    pos_phone : function (init) {
454
      var tip_height = this.outerHeight(this.settings.$next_tip),
455
          tip_offset = this.settings.$next_tip.offset(),
456
          target_height = this.outerHeight(this.settings.$target),
457
          $nub = $('.joyride-nub', this.settings.$next_tip),
458
          nub_height = Math.ceil(this.outerHeight($nub) / 2),
459
          toggle = init || false;
460

    
461
      $nub.removeClass('bottom')
462
        .removeClass('top')
463
        .removeClass('right')
464
        .removeClass('left');
465

    
466
      if (toggle) {
467
        this.settings.$next_tip.css('visibility', 'hidden');
468
        this.settings.$next_tip.show();
469
      }
470

    
471
      if (!/body/i.test(this.settings.$target.selector)) {
472

    
473
        if (this.top()) {
474

    
475
            this.settings.$next_tip.offset({top: this.settings.$target.offset().top - tip_height - nub_height});
476
            $nub.addClass('bottom');
477

    
478
        } else {
479

    
480
          this.settings.$next_tip.offset({top: this.settings.$target.offset().top + target_height + nub_height});
481
          $nub.addClass('top');
482

    
483
        }
484

    
485
      } else if (this.settings.$li.length) {
486
        this.pos_modal($nub);
487
      }
488

    
489
      if (toggle) {
490
        this.settings.$next_tip.hide();
491
        this.settings.$next_tip.css('visibility', 'visible');
492
      }
493
    },
494

    
495
    pos_modal : function ($nub) {
496
      this.center();
497
      $nub.hide();
498
      if (!this.settings.$next_tip.data('closed')) {
499
        if ($('.joyride-modal-bg').length < 1) {
500
          $('body').append('<div class="joyride-modal-bg">').show();
501
        }
502

    
503
        if (/pop/i.test(this.settings.tipAnimation)) {
504
          $('.joyride-modal-bg').show();
505
        } else {
506
          $('.joyride-modal-bg').fadeIn(this.settings.tipAnimationFadeSpeed);
507
        }
508
      }
509
    },
510

    
511
    center : function () {
512
      var $w = $(window);
513

    
514
      this.settings.$next_tip.css({
515
        top : ((($w.height() - this.outerHeight(this.settings.$next_tip)) / 2) + $w.scrollTop()),
516
        left : ((($w.width() - this.outerWidth(this.settings.$next_tip)) / 2) + this.scrollLeft($w))
517
      });
518

    
519
      return true;
520
    },
521

    
522
    bottom : function () {
523
      return /bottom/i.test(this.settings.tipSettings.tipLocation);
524
    },
525

    
526
    top : function () {
527
      return /top/i.test(this.settings.tipSettings.tipLocation);
528
    },
529

    
530
    right : function () {
531
      return /right/i.test(this.settings.tipSettings.tipLocation);
532
    },
533

    
534
    left : function () {
535
      return /left/i.test(this.settings.tipSettings.tipLocation);
536
    },
537

    
538
    corners : function (el) {
539
      var w = $(window),
540
          right = w.width() + this.scrollLeft(w),
541
          bottom = w.width() + w.scrollTop();
542

    
543
      return [
544
        el.offset().top <= w.scrollTop(),
545
        right <= el.offset().left + this.outerWidth(el),
546
        bottom <= el.offset().top + this.outerHeight(el),
547
        this.scrollLeft(w) >= el.offset().left
548
      ];
549
    },
550

    
551
    visible : function (hidden_corners) {
552
      var i = hidden_corners.length;
553

    
554
      while (i--) {
555
        if (hidden_corners[i]) return false;
556
      }
557

    
558
      return true;
559
    },
560

    
561
    nub_position : function (nub, pos, def) {
562
      if (pos === 'auto') {
563
        nub.addClass(def);
564
      } else {
565
        nub.addClass(pos);
566
      }
567
    },
568

    
569
    startTimer : function () {
570
      if (this.settings.$li.length) {
571
        this.settings.automate = setTimeout(function () {
572
          this.hide();
573
          this.show();
574
          this.startTimer();
575
        }.bind(this), this.settings.timer);
576
      } else {
577
        clearTimeout(this.settings.automate);
578
      }
579
    },
580

    
581
    end : function () {
582
      if (this.settings.cookieMonster) {
583
        $.cookie(this.settings.cookieName, 'ridden', { expires: this.settings.cookieExpires, domain: this.settings.cookieDomain });
584
      }
585

    
586
      if (this.settings.timer > 0) {
587
        clearTimeout(this.settings.automate);
588
      }
589

    
590
      this.settings.$next_tip.data('closed', true);
591

    
592
      $('.joyride-modal-bg').hide();
593
      this.settings.$current_tip.hide();
594
      this.settings.postStepCallback(this.settings.$li.index(), this.settings.$current_tip);
595
      this.settings.postRideCallback(this.settings.$li.index(), this.settings.$current_tip);
596
    },
597

    
598
    outerHTML : function (el) {
599
      // support FireFox < 11
600
      return el.outerHTML || new XMLSerializer().serializeToString(el);
601
    },
602

    
603
    off : function () {
604
      $(this.scope).off('.joyride');
605
      $(window).off('.joyride');
606
      $('.joyride-close-tip, .joyride-next-tip, .joyride-modal-bg').off('.joyride');
607
      $('.joyride-tip-guide, .joyride-modal-bg').remove();
608
      clearTimeout(this.settings.automate);
609
      this.settings = {};
610
    }
611
  };
612
}(Foundation.zj, this, this.document));