Skip to content

Commit

Permalink
feature: move from intro.js to free for commercial use shepherd.js
Browse files Browse the repository at this point in the history
  • Loading branch information
mutantsan committed Jan 3, 2024
1 parent a9b70db commit f4b28c0
Show file tree
Hide file tree
Showing 9 changed files with 1,533 additions and 25 deletions.
78 changes: 78 additions & 0 deletions ckanext/tour/assets/css/style.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ckanext/tour/assets/css/style.css.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions ckanext/tour/assets/css/vendor/shepherd.min.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

104 changes: 104 additions & 0 deletions ckanext/tour/assets/js/tour-init-intro.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/**
* This is a first implementation of tour with intro.js library.
* Unfortunately, the license of this library is not suitable for us, since it's
* not free for commercial use. Leaving it there for a while, maybe the new implementation
* with shepherd.js has some significant flaws.
*/
this.ckan.module('tour-init', function (jQuery) {
return {
options: {
template: [
'<a id="intro-switch" href="#" class="btn btn-sm question"><i class="fa fa-lg fa-question-circle"></i></a>',
'<i class="icon-question-sign"></i>',
'</i>',
'</a>'
].join('\n')
},

initialize: function () {
$.proxyAll(this, /_/);

this.intro = null;
this.isMobile = this._isMobile()

$.ajax({
url: this.sandbox.url("/api/action/tour_list"),
success: this._onSuccessRequest
});
},

_isMobile: function () {
var md = new MobileDetect(window.navigator.userAgent);
return md.mobile() ? true : false;
},

/**
* Creates a tour mark if not exist
*
* @returns
*/
createMark: function () {
if (!this.mark) {
this.mark = jQuery(this.options.template);
}
return this.mark;
},

_onSuccessRequest: function (data) {
data.result.forEach(element => this._initIntro(element));
},

_initIntro: function (introData) {
console.log(introData);
var showed = localStorage.getItem('intro-' + introData.id);
var shouldAttach = introData.state === "active";
var shouldStart = !showed && !this.isMobile && window.location.pathname == introData.page;
var anchorExists = $(introData.anchor).length;

this.intro = introJs();
this.intro.setOptions({
overlayOpacity: 0.7,
nextLabel: ' &rarr; ',
prevLabel: '&larr; ',
skipLabel: this._('Skip'),
doneLabel: this._('Got it!'),
showStepNumbers: false,
exitOnEsc: true, // default
exitOnOverlayClick: true, // default
keyboardNavigation: true, // default
showButtons: true, // default
showBullets: true, // default,
showProgress: false, // default
steps: this._prepareSteps(introData.steps),
});

if (shouldAttach && !shouldStart) {
this.createMark();

this.mark.insertAfter(anchorExists ? introData.anchor : '.breadcrumb .active');
this.mark.on('click', this._onClick);
}

if (shouldStart) {
localStorage.setItem('intro-' + introData.id, 1);
this.intro.start();
}
},

_prepareSteps: function (steps) {
steps.forEach(step => {
if (step.image) {
step.intro = step.intro + "<br><br>" + $("<img />", {
src: step.image.url
})[0].outerHTML;
}
});

return steps;
},

_onClick: function (e) {
this.intro.start();
}
}
});
106 changes: 84 additions & 22 deletions ckanext/tour/assets/js/tour-init.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,11 @@ this.ckan.module('tour-init', function (jQuery) {
initialize: function () {
$.proxyAll(this, /_/);

this.intro = null;
this.tour = null;
this.isMobile = this._isMobile()

$.ajax({
url: this.sandbox.url("/api/action/tour_list"),
// data: {},
success: this._onSuccessRequest
});
},
Expand All @@ -44,29 +43,63 @@ this.ckan.module('tour-init', function (jQuery) {
},

_initIntro: function (introData) {
console.log(introData);
var showed = localStorage.getItem('intro-' + introData.id);
var shouldAttach = introData.state === "active";
var shouldStart = !showed && !this.isMobile && window.location.pathname == introData.page;
var anchorExists = $(introData.anchor).length;

this.intro = introJs();
this.intro.setOptions({
overlayOpacity: 0.7,
nextLabel: ' &rarr; ',
prevLabel: '&larr; ',
skipLabel: this._('Skip'),
doneLabel: this._('Got it!'),
showStepNumbers: false,
exitOnEsc: true, // default
exitOnOverlayClick: true, // default
keyboardNavigation: true, // default
showButtons: true, // default
showBullets: true, // default,
showProgress: false, // default
steps: this._prepareSteps(introData.steps),
this.tour = new Shepherd.Tour({
useModalOverlay: true,
defaultStepOptions: {
floatingUIOptions: { middleware: [FloatingUICore.offset(20)]},
cancelIcon: {
enabled: true,
label: "Skip tour"
},
modalOverlayOpeningPadding: 5,
modalOverlayOpeningRadius: 5,
classes: 'tour-step',
scrollTo: { behavior: 'smooth', block: 'center' },
when: {
show() {
// prevent scrolling while we are showing tour
bodyScrollLock.disableBodyScroll(".tour-step");

const currentStep = this;
const currentStepIdx = this.tour.steps.indexOf(currentStep);

const progressListEl = document.createElement('ul');
progressListEl.classList = ["list-unstyled shepherd-stats"]

for (let i = 0; i < this.tour.steps.length; i++) {
const bulletElement = document.createElement('li');
bulletElement.innerText = " ";
bulletElement.dataset.stepId = this.tour.steps[i].id;

if (i === currentStepIdx) {
bulletElement.classList = ["active"];
}

$(bulletElement).click((el) => {
Shepherd.activeTour.show(el.target.dataset.stepId);
})

progressListEl.append(bulletElement)
}

$('.shepherd-footer').before(progressListEl);
},
destroy() {
// release scroll after tour
bodyScrollLock.clearAllBodyScrollLocks();
}
}
},

});

this.tour.addSteps(this._prepareSteps(introData.steps));

if (shouldAttach && !shouldStart) {
this.createMark();

Expand All @@ -76,24 +109,53 @@ this.ckan.module('tour-init', function (jQuery) {

if (shouldStart) {
localStorage.setItem('intro-' + introData.id, 1);
this.intro.start();
this.tour.start();
}
},

_prepareSteps: function (steps) {
steps.forEach(step => {
steps.forEach((step, idx) => {
let isLast = steps.length - 1 === idx;
let isFirst = idx === 0;
let lastButtonText = isLast ? this._("Done") : "→";
let firstButtonClasses = isFirst ? 'shepherd-back disabled' : 'shepherd-back';

if (step.image) {
step.intro = step.intro + "<br><br>" + $("<img />", {
step.text = step.intro + "<br><br>" + $("<img />", {
src: step.image.url
})[0].outerHTML;
} else {
step.text = step.intro;
}

step.buttons = [
{
action() {
return this.back();
},
classes: firstButtonClasses,
text: "←"
},
{
action() {
return this.next();
},
classes: 'shepherd-next',
text: lastButtonText
}
]

step.attachTo = {
element: step.element,
on: step.position
}
});

return steps;
},

_onClick: function (e) {
this.intro.start();
this.tour.start();
}
}
});
1 change: 1 addition & 0 deletions ckanext/tour/assets/js/vendor/bodyScrollLock.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit f4b28c0

Please sign in to comment.