123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- import { loadScript } from '../utils/loader.js'
-
- /**
- * Manages loading and registering of reveal.js plugins.
- */
- export default class Plugins {
-
- constructor( reveal ) {
-
- this.Reveal = reveal;
-
- // Flags our current state (idle -> loading -> loaded)
- this.state = 'idle';
-
- // An id:instance map of currently registered plugins
- this.registeredPlugins = {};
-
- this.asyncDependencies = [];
-
- }
-
- /**
- * Loads reveal.js dependencies, registers and
- * initializes plugins.
- *
- * Plugins are direct references to a reveal.js plugin
- * object that we register and initialize after any
- * synchronous dependencies have loaded.
- *
- * Dependencies are defined via the 'dependencies' config
- * option and will be loaded prior to starting reveal.js.
- * Some dependencies may have an 'async' flag, if so they
- * will load after reveal.js has been started up.
- */
- load( plugins, dependencies ) {
-
- this.state = 'loading';
-
- plugins.forEach( this.registerPlugin.bind( this ) );
-
- return new Promise( resolve => {
-
- let scripts = [],
- scriptsToLoad = 0;
-
- dependencies.forEach( s => {
- // Load if there's no condition or the condition is truthy
- if( !s.condition || s.condition() ) {
- if( s.async ) {
- this.asyncDependencies.push( s );
- }
- else {
- scripts.push( s );
- }
- }
- } );
-
- if( scripts.length ) {
- scriptsToLoad = scripts.length;
-
- const scriptLoadedCallback = (s) => {
- if( s && typeof s.callback === 'function' ) s.callback();
-
- if( --scriptsToLoad === 0 ) {
- this.initPlugins().then( resolve );
- }
- };
-
- // Load synchronous scripts
- scripts.forEach( s => {
- if( typeof s.id === 'string' ) {
- this.registerPlugin( s );
- scriptLoadedCallback( s );
- }
- else if( typeof s.src === 'string' ) {
- loadScript( s.src, () => scriptLoadedCallback(s) );
- }
- else {
- console.warn( 'Unrecognized plugin format', s );
- scriptLoadedCallback();
- }
- } );
- }
- else {
- this.initPlugins().then( resolve );
- }
-
- } );
-
- }
-
- /**
- * Initializes our plugins and waits for them to be ready
- * before proceeding.
- */
- initPlugins() {
-
- return new Promise( resolve => {
-
- let pluginValues = Object.values( this.registeredPlugins );
- let pluginsToInitialize = pluginValues.length;
-
- // If there are no plugins, skip this step
- if( pluginsToInitialize === 0 ) {
- this.loadAsync().then( resolve );
- }
- // ... otherwise initialize plugins
- else {
-
- let initNextPlugin;
-
- let afterPlugInitialized = () => {
- if( --pluginsToInitialize === 0 ) {
- this.loadAsync().then( resolve );
- }
- else {
- initNextPlugin();
- }
- };
-
- let i = 0;
-
- // Initialize plugins serially
- initNextPlugin = () => {
-
- let plugin = pluginValues[i++];
-
- // If the plugin has an 'init' method, invoke it
- if( typeof plugin.init === 'function' ) {
- let promise = plugin.init( this.Reveal );
-
- // If the plugin returned a Promise, wait for it
- if( promise && typeof promise.then === 'function' ) {
- promise.then( afterPlugInitialized );
- }
- else {
- afterPlugInitialized();
- }
- }
- else {
- afterPlugInitialized();
- }
-
- }
-
- initNextPlugin();
-
- }
-
- } )
-
- }
-
- /**
- * Loads all async reveal.js dependencies.
- */
- loadAsync() {
-
- this.state = 'loaded';
-
- if( this.asyncDependencies.length ) {
- this.asyncDependencies.forEach( s => {
- loadScript( s.src, s.callback );
- } );
- }
-
- return Promise.resolve();
-
- }
-
- /**
- * Registers a new plugin with this reveal.js instance.
- *
- * reveal.js waits for all registered plugins to initialize
- * before considering itself ready, as long as the plugin
- * is registered before calling `Reveal.initialize()`.
- */
- registerPlugin( plugin ) {
-
- // Backwards compatibility to make reveal.js ~3.9.0
- // plugins work with reveal.js 4.0.0
- if( arguments.length === 2 && typeof arguments[0] === 'string' ) {
- plugin = arguments[1];
- plugin.id = arguments[0];
- }
- // Plugin can optionally be a function which we call
- // to create an instance of the plugin
- else if( typeof plugin === 'function' ) {
- plugin = plugin();
- }
-
- let id = plugin.id;
-
- if( typeof id !== 'string' ) {
- console.warn( 'Unrecognized plugin format; can\'t find plugin.id', plugin );
- }
- else if( this.registeredPlugins[id] === undefined ) {
- this.registeredPlugins[id] = plugin;
-
- // If a plugin is registered after reveal.js is loaded,
- // initialize it right away
- if( this.state === 'loaded' && typeof plugin.init === 'function' ) {
- plugin.init( this.Reveal );
- }
- }
- else {
- console.warn( 'reveal.js: "'+ id +'" plugin has already been registered' );
- }
-
- }
-
- /**
- * Checks if a specific plugin has been registered.
- *
- * @param {String} id Unique plugin identifier
- */
- hasPlugin( id ) {
-
- return !!this.registeredPlugins[id];
-
- }
-
- /**
- * Returns the specific plugin instance, if a plugin
- * with the given ID has been registered.
- *
- * @param {String} id Unique plugin identifier
- */
- getPlugin( id ) {
-
- return this.registeredPlugins[id];
-
- }
-
- getRegisteredPlugins() {
-
- return this.registeredPlugins;
-
- }
-
- destroy() {
-
- Object.values( this.registeredPlugins ).forEach( plugin => {
- if( typeof plugin.destroy === 'function' ) {
- plugin.destroy();
- }
- } );
-
- this.registeredPlugins = {};
- this.asyncDependencies = [];
-
- }
-
- }
|