%PDF- %PDF-
| Direktori : /home/dopla/www/wp-content/plugins/ml-slider/admin/assets/tether-shepherd/src/js/ |
| Current File : /home/dopla/www/wp-content/plugins/ml-slider/admin/assets/tether-shepherd/src/js/shepherd.js |
/* global Tether */
const {
Evented,
addClass,
extend,
hasClass,
removeClass,
uniqueId
} = Tether.Utils;
let Shepherd = new Evented;
function isUndefined(obj) {
return typeof obj === 'undefined'
};
function isArray(obj) {
return obj && obj.constructor === Array;
};
function isObject(obj) {
return obj && obj.constructor === Object;
};
function isObjectLoose(obj) {
return typeof obj === 'object';
};
const ATTACHMENT = {
'top right': 'bottom left',
'top left': 'bottom right',
'top center': 'bottom center',
'middle right': 'middle left',
'middle left': 'middle right',
'middle center': 'middle center',
'bottom left': 'top right',
'bottom right': 'top left',
'bottom center': 'top center',
'top': 'bottom center',
'left': 'middle right',
'right': 'middle left',
'bottom': 'top center',
'center': 'middle center',
'middle': 'middle center'
};
function createFromHTML (html) {
let el = document.createElement('div');
el.innerHTML = html;
return el.children[0];
}
function matchesSelector (el, sel) {
let matches;
if (!isUndefined(el.matches)) {
matches = el.matches;
} else if (!isUndefined(el.matchesSelector)) {
matches = el.matchesSelector;
} else if (!isUndefined(el.msMatchesSelector)) {
matches = el.msMatchesSelector;
} else if (!isUndefined(el.webkitMatchesSelector)) {
matches = el.webkitMatchesSelector;
} else if (!isUndefined(el.mozMatchesSelector)) {
matches = el.mozMatchesSelector;
} else if (!isUndefined(el.oMatchesSelector)) {
matches = el.oMatchesSelector;
}
return matches.call(el, sel);
}
const positionRe = /^(.+) (top|left|right|bottom|center|\[[a-z ]+\])$/
function parsePosition (str) {
if (isObjectLoose(str)) {
if (str.hasOwnProperty("element") && str.hasOwnProperty("on")) {
return str;
}
return null;
}
let matches = positionRe.exec(str);
if (!matches) {
return null;
}
let on = matches[2];
if (on[0] === '['){
on = on.substring(1, on.length - 1);
}
return {
'element': matches[1],
'on': on
};
}
function parseShorthand (obj, props) {
if (obj === null || isUndefined(obj)) {
return obj;
} else if (isObjectLoose(obj)) {
return obj;
}
let vals = obj.split(' ');
let out = {};
let j = props.length - 1;
for (let i = vals.length - 1; i >= 0; i--){
if (j === 0){
out[props[j]] = vals.slice(0, i + 1).join(' ');
break;
} else {
out[props[j]] = vals[i];
}
j--;
}
return out;
}
class Step extends Evented {
constructor(tour, options) {
super(tour, options);
this.tour = tour;
this.bindMethods();
this.setOptions(options);
return this;
}
bindMethods() {
const methods = [
'_show',
'show',
'hide',
'isOpen',
'cancel',
'complete',
'scrollTo',
'destroy',
'render'
];
methods.map((method) => {
this[method] = this[method].bind(this);
});
}
setOptions(options={}) {
this.options = options;
this.destroy();
this.id = this.options.id || this.id || `step-${ uniqueId() }`;
const when = this.options.when;
if (when) {
for (let event in when) {
if ({}.hasOwnProperty.call(when, event)) {
let handler = when[event];
this.on(event, handler, this);
}
}
}
// Button configuration
const buttonsJson = JSON.stringify(this.options.buttons);
const buttonsAreDefault = isUndefined(buttonsJson) ||
buttonsJson === "true";
const buttonsAreEmpty = buttonsJson === "{}" ||
buttonsJson === "[]" ||
buttonsJson === "null" ||
buttonsJson === "false";
const buttonsAreArray = !buttonsAreDefault && isArray(this.options.buttons)
const buttonsAreObject = !buttonsAreDefault && isObject(this.options.buttons)
// Show default button if undefined or 'true'
if (buttonsAreDefault) {
this.options.buttons = [{
text: 'Next',
action: this.tour.next,
classes: 'btn'
}];
// Can pass in an object which will assume asingle button
} else if (!buttonsAreEmpty && buttonsAreObject) {
this.options.buttons = [this.options.buttons];
// Falsey/empty values or non-object values prevent buttons from rendering
} else if (buttonsAreEmpty || !buttonsAreArray) {
this.options.buttons = false;
}
}
getTour() {
return this.tour;
}
bindAdvance() {
// An empty selector matches the step element
const {event, selector} = parseShorthand(this.options.advanceOn, ['selector', 'event']);
const handler = (e) => {
if (!this.isOpen()) {
return;
}
if (!isUndefined(selector)) {
if (matchesSelector(e.target, selector)) {
this.tour.next();
}
} else {
if (this.el && e.target === this.el) {
this.tour.next();
}
}
};
// TODO: this should also bind/unbind on show/hide
document.body.addEventListener(event, handler);
this.on('destroy', () => {
return document.body.removeEventListener(event, handler);
});
}
getAttachTo() {
let opts = parsePosition(this.options.attachTo) || {};
let returnOpts = extend({}, opts);
if (typeof opts.element === 'string') {
// Can't override the element in user opts reference because we can't
// guarantee that the element will exist in the future.
returnOpts.element = document.querySelector(opts.element);
if (!returnOpts.element) {
console.error(`The element for this Shepherd step was not found ${opts.element}`);
}
}
return returnOpts;
}
setupTether() {
if (isUndefined(Tether)) {
throw new Error("Using the attachment feature of Shepherd requires the Tether library");
}
let opts = this.getAttachTo();
let attachment = ATTACHMENT[opts.on] || ATTACHMENT.right;
if (isUndefined(opts.element)) {
opts.element = 'viewport';
attachment = 'middle center';
}
const tetherOpts = {
classPrefix: 'shepherd',
element: this.el,
constraints: [{
to: 'window',
pin: true,
attachment: 'together'
}],
target: opts.element,
offset: opts.offset || '0 0',
attachment: attachment
};
if (this.tether) {
this.tether.destroy();
}
this.tether = new Tether(extend(tetherOpts, this.options.tetherOptions));
}
show() {
if (!isUndefined(this.options.beforeShowPromise)) {
const beforeShowPromise = this.options.beforeShowPromise();
if (!isUndefined(beforeShowPromise)) {
return beforeShowPromise.then(() => this._show());
}
}
this._show();
}
_show() {
this.trigger('before-show');
if (!this.el) {
this.render();
}
addClass(this.el, 'shepherd-open');
document.body.setAttribute('data-shepherd-step', this.id);
this.setupTether();
if (this.options.scrollTo) {
setTimeout(() => {
this.scrollTo();
});
}
this.trigger('show');
}
hide() {
this.trigger('before-hide');
removeClass(this.el, 'shepherd-open');
document.body.removeAttribute('data-shepherd-step');
if (this.tether) {
this.tether.destroy();
}
this.tether = null;
this.trigger('hide');
}
isOpen() {
return this.el && hasClass(this.el, 'shepherd-open');
}
cancel() {
this.tour.cancel();
this.trigger('cancel');
}
complete() {
this.tour.complete();
this.trigger('complete');
}
scrollTo() {
const {element} = this.getAttachTo();
if (!isUndefined(this.options.scrollToHandler)) {
this.options.scrollToHandler(element);
} else if (!isUndefined(element)) {
element.scrollIntoView();
}
}
destroy() {
if (!isUndefined(this.el) && this.el.parentNode) {
this.el.parentNode.removeChild(this.el);
delete this.el;
}
if (this.tether) {
this.tether.destroy();
}
this.tether = null;
this.trigger('destroy');
}
render() {
if (!isUndefined(this.el)) {
this.destroy();
}
this.el = createFromHTML(`<div class='shepherd-step ${ this.options.classes || '' }' data-id='${ this.id }' ${ this.options.idAttribute ? 'id="' + this.options.idAttribute + '"' : '' }></div>`);
let content = document.createElement('div');
content.className = 'shepherd-content';
this.el.appendChild(content);
let header = document.createElement('header');
content.appendChild(header);
if (this.options.title) {
header.innerHTML += `<h3 class='shepherd-title'>${ this.options.title }</h3>`;
this.el.className += ' shepherd-has-title';
}
if (this.options.showCancelLink) {
const link = createFromHTML("<a href class='shepherd-cancel-link'>✕</a>");
header.appendChild(link);
this.el.className += ' shepherd-has-cancel-link';
this.bindCancelLink(link);
}
if (!isUndefined(this.options.text)) {
const text = createFromHTML("<div class='shepherd-text'></div>");
let paragraphs = this.options.text;
if (typeof paragraphs === 'function') {
paragraphs = paragraphs.call(this, text);
}
if (paragraphs instanceof HTMLElement) {
text.appendChild(paragraphs);
} else {
if (typeof paragraphs === 'string') {
paragraphs = [paragraphs];
}
paragraphs.map(paragraph => {
text.innerHTML += `<p>${ paragraph }</p>`;
});
}
content.appendChild(text);
}
if (this.options.buttons) {
const footer = document.createElement('footer');
let buttons = createFromHTML("<ul class='shepherd-buttons'></ul>");
this.options.buttons.map(cfg => {
const button = createFromHTML(`<li><a class='shepherd-button ${ cfg.classes || '' }'>${ cfg.text }</a>`);
buttons.appendChild(button);
this.bindButtonEvents(cfg, button.querySelector('a'));
});
footer.appendChild(buttons);
content.appendChild(footer);
}
document.body.appendChild(this.el);
this.setupTether();
if (this.options.advanceOn) {
this.bindAdvance();
}
}
bindCancelLink(link) {
link.addEventListener('click', (e) => {
e.preventDefault();
this.cancel();
});
}
bindButtonEvents(cfg, el) {
cfg.events = cfg.events || {};
if (!isUndefined(cfg.action)) {
// Including both a click event and an action is not supported
cfg.events.click = cfg.action;
}
for (let event in cfg.events) {
if ({}.hasOwnProperty.call(cfg.events, event)) {
let handler = cfg.events[event];
if (typeof handler === 'string') {
const page = handler;
handler = () => this.tour.show(page);
}
el.addEventListener(event, handler);
}
}
this.on('destroy', () => {
for (let event in cfg.events) {
if ({}.hasOwnProperty.call(cfg.events, event)) {
const handler = cfg.events[event];
el.removeEventListener(event, handler);
}
}
});
}
}
class Tour extends Evented {
constructor(options={}) {
super(options);
this.bindMethods();
this.options = options;
this.steps = this.options.steps || [];
// Pass these events onto the global Shepherd object
const events = ['complete', 'cancel', 'hide', 'start', 'show', 'active', 'inactive'];
events.map(event => {
((e) => {
this.on(e, (opts) => {
opts = opts || {};
opts.tour = this;
Shepherd.trigger(e, opts);
});
})(event);
});
return this;
}
bindMethods() {
const methods = [
'next',
'back',
'cancel',
'complete',
'hide'
];
methods.map((method) => {
this[method] = this[method].bind(this);
});
}
addStep(name, step) {
if (isUndefined(step)) {
step = name;
}
if (!(step instanceof Step)) {
if (typeof name === 'string' || typeof name === 'number') {
step.id = name.toString();
}
step = extend({}, this.options.defaults, step);
step = new Step(this, step);
} else {
step.tour = this;
}
this.steps.push(step);
return this;
}
removeStep(name) {
const current = this.getCurrentStep();
for (let i = 0; i < this.steps.length; ++i) {
const step = this.steps[i];
if (step.id === name) {
if (step.isOpen()) {
step.hide();
}
step.destroy();
this.steps.splice(i, 1);
break;
}
}
if (current && current.id === name){
this.currentStep = undefined;
if (this.steps.length)
this.show(0);
else
this.hide();
}
}
getById(id) {
for (let i = 0; i < this.steps.length; ++i) {
const step = this.steps[i];
if (step.id === id) {
return step;
}
}
}
getCurrentStep() {
return this.currentStep;
}
next() {
const index = this.steps.indexOf(this.currentStep);
if (index === this.steps.length - 1) {
this.hide(index);
this.trigger('complete');
this.done();
} else {
this.show(index + 1, true);
}
}
back() {
const index = this.steps.indexOf(this.currentStep);
this.show(index - 1, false);
}
cancel() {
if (this.currentStep) {
this.currentStep.hide();
}
this.trigger('cancel');
this.done();
}
complete() {
if (this.currentStep) {
this.currentStep.hide();
}
this.trigger('complete');
this.done();
}
hide() {
if (this.currentStep) {
this.currentStep.hide();
}
this.trigger('hide');
this.done();
}
done() {
Shepherd.activeTour = null;
removeClass(document.body, 'shepherd-active');
this.trigger('inactive', {tour: this});
}
show(key=0, forward=true) {
if (this.currentStep) {
this.currentStep.hide();
} else {
addClass(document.body, 'shepherd-active');
this.trigger('active', {tour: this});
}
Shepherd.activeTour = this;
let next;
if (typeof key === 'string') {
next = this.getById(key);
} else {
next = this.steps[key];
}
if (next) {
if (!isUndefined(next.options.showOn) && !next.options.showOn()) {
const index = this.steps.indexOf(next);
const nextIndex = forward ? index + 1 : index - 1;
this.show(nextIndex, forward);
} else {
this.trigger('show', {
step: next,
previous: this.currentStep
});
if (this.currentStep) {
this.currentStep.hide();
}
this.currentStep = next;
next.show();
}
}
}
start() {
this.trigger('start');
this.currentStep = null;
this.next();
}
}
extend(Shepherd, {Tour, Step, Evented});