decktape/plugins/generic.js

77 lines
2.6 KiB
JavaScript

// The generic plugin emulates end-user interaction by pressing keyboard and detects changes to the DOM.
// The deck is considered over when no change is detected afterward.
exports.options = {
keycode: {
default: "Right",
help: "Key code pressed to navigate to next slide"
}
};
exports.help =
"Emulates the end-user interaction by pressing the key with the specified [keycode]\n" +
"and iterates over the presentation as long as any change to the DOM is detected\n" +
"by observing mutation events to the body element and its subtree.\n" +
"The [keycode] must be one of the PhantomJS page event keys and defaults to [Right].";
exports.create = function(page, options) {
return new Generic(page, options);
};
function Generic(page, options) {
this.page = page;
this.options = options;
this.isNextSlideDetected = false;
}
Generic.prototype = {
getName : function() {
return "Generic";
},
isActive : function() {
return true;
},
configure : function() {
this.page.evaluate(function() {
var observer = new window.MutationObserver(function() {
window.callPhantom({ isNextSlideDetected: true });
});
observer.observe(document.querySelector("body"), { attributes: true, childList: true, subtree: true });
});
var plugin = this;
this.page.onCallback = function(mutation) {
if (mutation.isNextSlideDetected)
plugin.isNextSlideDetected = true;
};
},
slideCount : function() {
return undefined;
},
hasNextSlide : function() {
// A priori knowledge is impossible to achieve in a generic way. Thus the only way is to actually emulate end-user interaction by pressing the configured key and check whether the DOM has changed a posteriori.
this.page.sendEvent("keypress", page.event.key[this.options.keycode || exports.options.keycode.default]);
var plugin = this;
return new Promise(function (fulfill) {
// TODO: use mutation event directly instead of relying on a timeout
setTimeout(function() {
fulfill(plugin.isNextSlideDetected);
}, 1000);
});
},
nextSlide : function() {
this.isNextSlideDetected = false;
},
currentSlideIndex : function() {
var fragment = this.page.evaluate(function() {
return window.location.hash.replace(/^#\/?/, "");
});
return fragment.length ? fragment : this.currentSlide;
}
};