import Shepherd from 'shepherd.js'
(function () {
// utils
/**
* Merge defaults with user options
* @private
* @param {Object} defaults Default settings
* @param {Object} options User options
* @returns {Object} Merged values of defaults and options
* @thanks https://gist.github.com/pbojinov/8f3765b672efec122f66
*/
function extend (defaults, options) {
var extended = {}
var prop
for (prop in defaults) {
if (Object.prototype.hasOwnProperty.call(defaults, prop)) {
extended[prop] = defaults[prop]
}
}
for (prop in options) {
if (Object.prototype.hasOwnProperty.call(options, prop)) {
extended[prop] = options[prop]
}
}
return extended
}
/**
* JavaScript cookies - cookies.js
* @thanks https://gist.github.com/abhiomkar/1363648
*/
function getCookie (name) {
var dc = document.cookie
var prefix = name + '='
var begin = dc.indexOf('; ' + prefix)
if (begin == -1) {
begin = dc.indexOf(prefix)
if (begin != 0) return null
} else {
begin += 2
}
var end = document.cookie.indexOf(';', begin)
if (end == -1) {
end = dc.length
}
return unescape(dc.substring(begin + prefix.length, end))
}
function createCookie (name, value, days) {
if (days) {
var date = new Date()
date.setTime(date.getTime() + (days*24*60*60*1000))
var expires = '; expires=' + date.toGMTString()
}
else var expires = ''
document.cookie = name + '=' + value + expires + '; path=/'
}
function loadIntro () {
var intro = window._intro
if (!intro) return
var locales = intro.locales
var locale = intro.locale
var shepherdOptions = intro.shepherd_options
function Tour(tour) {
this.tour = tour
this.shepherd = new Shepherd.Tour(extend({
classPrefix: 'intro',
defaultStepOptions: {
scrollTo: true
},
useModalOverlay: tour.options.overlay_visible
}, shepherdOptions))
}
Tour.prototype.setup = function () {
this.configure()
this.start()
return this
}
Tour.prototype.test = function (options) {
this.tour.options.steps.forEach(function (step) {
if (step.element && !document.querySelector(step.element)) {
step.element = options.element
}
})
this.configure()
this.start()
}
Tour.prototype.configure = function () {
var btnCompleteText = this.tour.options['btn_complete_text_' + locale] || this.tour.options.btn_complete_text
locales.complete = btnCompleteText || locales.complete
this.configureSteps(this.tour.options.steps)
this.shepherd.on('complete', this.complete.bind(this))
this.shepherd.on('cancel', this.cancel.bind(this))
this.shepherd.on('show', this.show.bind(this))
}
Tour.prototype.configureSteps = function (steps) {
var self = this
steps.forEach(function (step, index) {
var baseOptions = self.configureStepBase(step, index)
var btnOptions = self.configureStepButtons(step, index, steps)
self.shepherd.addStep(extend(baseOptions, btnOptions))
})
}
Tour.prototype.configureStepBase = function (step, index) {
var options = {}
var popperOptions = {}
var stepTitle = step['title_' + locale] || step.title
var stepContent = step['content_' + locale] || step.content
options.id = 'tour-' + index
if (stepTitle) {
options.title = stepTitle
}
if (step.image_url) {
options.text = '
' +
'
' +
(stepContent ? ('
' + stepContent + '
') : '') +
'
'
} else if (stepContent) {
options.text = '' + stepContent + '
'
}
if (step.element) {
options.attachTo = {
element: step.element,
on: (step.placement || 'bottom')
}
options.showOn = function () {
return document.querySelector(step.element)
}
}
options.showCancelLink = step.cancel_link
// @see https://github.com/FezVrasta/popper.js/issues/670
if (step.fixed_placement) {
popperOptions.modifiers = {
preventOverflow: {
escapeWithReference: true
}
}
}
options.tippyOptions = {
zIndex: (step.z_index || 99),
maxWidth: null,
popperOptions: popperOptions
}
return options
}
Tour.prototype.configureStepButtons = function (step, index, steps) {
var options = {}
if (this.tour.options.btn_visible == 1) {
if (index === 0) {
options.buttons = [{ text: locales.exit, action: this.shepherd.cancel, secondary: true }]
if (steps.length === 1) {
options.buttons.push({ text: locales.complete, action: this.shepherd.complete })
} else {
options.buttons.push({ text: locales.next, action: this.next.bind(this) })
}
} else if (index === steps.length - 1) {
options.buttons = [
{ text: locales.back, action: this.shepherd.back, secondary: true },
{ text: locales.complete, action: this.shepherd.complete }
]
} else {
options.buttons = [
{ text: locales.back, action: this.shepherd.back, secondary: true },
{ text: locales.next, action: this.next.bind(this) }
]
}
} else {
options.buttons = []
}
return options
}
Tour.prototype.start = function () {
var firstStep = this.shepherd.steps[0]
if (firstStep && (!firstStep.options.attachTo || firstStep.options.showOn())) {
this.shepherd.start()
} else {
this.shepherd.cancel()
}
}
Tour.prototype.next = function () {
var shepherd = this.shepherd
var nextStep = shepherd.steps[shepherd.steps.indexOf(shepherd.getCurrentStep()) + 1]
if (nextStep && (!nextStep.options.attachTo || nextStep.options.showOn())) {
shepherd.next()
} else {
shepherd.cancel()
}
}
Tour.prototype.hide = function () {
this.shepherd.hide()
}
Tour.prototype.show = function (e) {
var self = this
setTimeout(function () {
var element = e.step.el
var image = element.querySelector('.shepherd-image-box img')
if (image) {
image.onload = function () {
document.body.scrollTop = document.documentElement.scrollTop = window.screenTop + 1
}
}
if (self.tour.options.overlay_visible) {
var container = element.closest('.tippy-popper')
var preContrainer = container && container.previousElementSibling
if (preContrainer.classList.contains((self.shepherd.classPrefix || '') + 'shepherd-modal-overlay-container')) {
preContrainer.style.zIndex = e.step.options.tippyOptions.zIndex
}
}
}, 0)
}
Tour.prototype.complete = function () {
this.record('complete')
if (this.tour.options.btn_complete_link) {
window.open(this.tour.options.btn_complete_link)
}
}
Tour.prototype.cancel = function () {
this.record('cancel')
}
Tour.prototype.record = function (action) {
if (!this.tour.id) return
createCookie('intro-tour-' + this.tour.id, (action || 'complete'), 7300)
if (!intro.signed) return
var xhr = new XMLHttpRequest()
var csrfToken = document.querySelector('meta[name="csrf-token"]')
xhr.open('POST', intro.record_tours_path)
csrfToken && xhr.setRequestHeader('X-CSRF-Token', csrfToken.content)
xhr.setRequestHeader('Content-Type', 'application/json')
xhr.send(JSON.stringify({
id: this.tour.id
}))
}
intro.Tour = Tour
function loadTours () {
var xhr = new XMLHttpRequest()
xhr.open(
'GET',
intro.tours_path +
'?controller_path=' + encodeURIComponent(intro.controller) +
'&action_name=' + encodeURIComponent(intro.action) +
'&original_url=' + encodeURIComponent(intro.original_url)
)
xhr.onload = function () {
if (xhr.status !== 200) return
var res = JSON.parse(xhr.response)
if (res.data) {
res.data.forEach(function (tour) {
if (tour && tour.options && !getCookie('intro-tour-' + tour.id)) {
new Tour(tour).setup()
}
})
}
}
xhr.send()
}
loadTours()
}
if (typeof Turbolinks !== 'undefined' && Turbolinks.supported) {
if (!window._introBindTurbolinks) {
document.addEventListener('turbolinks:load', loadIntro)
window._introBindTurbolinks = true
}
} else {
document.addEventListener('DOMContentLoaded', loadIntro)
}
})()