From 3bb704578af44cbc80f7f2b85cc7feefe9d6d08b Mon Sep 17 00:00:00 2001 From: Henrik Ingo Date: Mon, 23 Oct 2017 23:36:32 +0300 Subject: [PATCH] Add toolbar plugin The toolbar plugin produces a generic toolbar container, which then can contain buttons, drop-downs or any html inside it. The user can position and otherwise style the toolbar, and any widgets inside it will follow. Other plugins that wish to expose graphical controls (navigation-ui, autoplay) will use the impress:toolbar:appendChild event to 'send' their controls to this plugin. --- src/plugins/toolbar/README.md | 41 +++++++++ src/plugins/toolbar/toolbar.js | 157 +++++++++++++++++++++++++++++++++ 2 files changed, 198 insertions(+) create mode 100644 src/plugins/toolbar/README.md create mode 100644 src/plugins/toolbar/toolbar.js diff --git a/src/plugins/toolbar/README.md b/src/plugins/toolbar/README.md new file mode 100644 index 0000000..4b2b9d2 --- /dev/null +++ b/src/plugins/toolbar/README.md @@ -0,0 +1,41 @@ +Toolbar plugin +==================== + +This plugin provides a generic graphical toolbar. Other plugins that +want to expose a button or other widget, can add those to this toolbar. + +Using a single consolidated toolbar for all GUI widgets makes it easier +to position and style the toolbar rather than having to do that for lots +of different divs. + +To add/activate the toolbar in your presentation, add this div: + +
+ +Styling the toolbar is left to presentation author. Here's an example CSS: + + .impress-enabled div#impress-toolbar { + position: fixed; + right: 1px; + bottom: 1px; + opacity: 0.6; + } + .impress-enabled div#impress-toolbar > span { + margin-right: 10px; + } + +The [mouse-timeout](../mouse-timeout/README.md) plugin can be leveraged to hide +the toolbar from sight, and only make it visible when mouse is moved. + + body.impress-mouse-timeout div#impress-toolbar { + display: none; + } + +If you're writing a plugin and would like to add a widget to the toolbar, see +[the top of the source file for further instructions](toolbar.js). + + +Author +------ + +Henrik Ingo (@henrikingo), 2016 diff --git a/src/plugins/toolbar/toolbar.js b/src/plugins/toolbar/toolbar.js new file mode 100644 index 0000000..aa019b0 --- /dev/null +++ b/src/plugins/toolbar/toolbar.js @@ -0,0 +1,157 @@ +/** + * Toolbar plugin + * + * This plugin provides a generic graphical toolbar. Other plugins that + * want to expose a button or other widget, can add those to this toolbar. + * + * Using a single consolidated toolbar for all GUI widgets makes it easier + * to position and style the toolbar rather than having to do that for lots + * of different divs. + * + * + * *** For presentation authors: ***************************************** + * + * To add/activate the toolbar in your presentation, add this div: + * + *
+ * + * Styling the toolbar is left to presentation author. Here's an example CSS: + * + * .impress-enabled div#impress-toolbar { + * position: fixed; + * right: 1px; + * bottom: 1px; + * opacity: 0.6; + * } + * .impress-enabled div#impress-toolbar > span { + * margin-right: 10px; + * } + * + * The [mouse-timeout](../mouse-timeout/README.md) plugin can be leveraged to hide + * the toolbar from sight, and only make it visible when mouse is moved. + * + * body.impress-mouse-timeout div#impress-toolbar { + * display: none; + * } + * + * + * *** For plugin authors ********************************************** + * + * To add a button to the toolbar, trigger the `impress:toolbar:appendChild` + * or `impress:toolbar:insertBefore` events as appropriate. The detail object + * should contain following parameters: + * + * { group : 1, // integer. Widgets with the same group are grouped inside + * // the same element. + * html : "", // The html to add. + * callback : "mycallback", // Toolbar plugin will trigger event + * // `impress:toolbar:added:mycallback` when done. + * before: element } // The reference element for an insertBefore() call. + * + * You should also listen to the `impress:toolbar:added:mycallback` event. At + * this point you can find the new widget in the DOM, and for example add an + * event listener to it. + * + * You are free to use any integer for the group. It's ok to leave gaps. It's + * ok to co-locate with widgets for another plugin, if you think they belong + * together. + * + * See navigation-ui for an example. + * + * Copyright 2016 Henrik Ingo (@henrikingo) + * Released under the MIT license. + */ + +/* global document */ + +( function( document ) { + "use strict"; + var toolbar = document.getElementById( "impress-toolbar" ); + var groups = []; + + /** + * Get the span element that is a child of toolbar, identified by index. + * + * If span element doesn't exist yet, it is created. + * + * Note: Because of Run-to-completion, this is not a race condition. + * https://developer.mozilla.org/en/docs/Web/JavaScript/EventLoop#Run-to-completion + * + * :param: index Method will return the element + */ + var getGroupElement = function( index ) { + var id = "impress-toolbar-group-" + index; + if ( !groups[ index ] ) { + groups[ index ] = document.createElement( "span" ); + groups[ index ].id = id; + var nextIndex = getNextGroupIndex( index ); + if ( nextIndex === undefined ) { + toolbar.appendChild( groups[ index ] ); + } else { + toolbar.insertBefore( groups[ index ], groups[ nextIndex ] ); + } + } + return groups[ index ]; + }; + + /** + * Get the span element from groups[] that is immediately after given index. + * + * This can be used to find the reference node for an insertBefore() call. + * If no element exists at a larger index, returns undefined. (In this case, + * you'd use appendChild() instead.) + * + * Note that index needn't itself exist in groups[]. + */ + var getNextGroupIndex = function( index ) { + var i = index + 1; + while ( !groups[ i ] && i < groups.length ) { + i++; + } + if ( i < groups.length ) { + return i; + } + }; + + // API + // Other plugins can add and remove buttons by sending them as events. + // In return, toolbar plugin will trigger events when button was added. + if ( toolbar ) { + /** + * Append a widget inside toolbar span element identified by given group index. + * + * :param: e.detail.group integer specifying the span element where widget will be placed + * :param: e.detail.element a dom element to add to the toolbar + */ + toolbar.addEventListener( "impress:toolbar:appendChild", function( e ) { + var group = getGroupElement( e.detail.group ); + group.appendChild( e.detail.element ); + } ); + + /** + * Add a widget to toolbar using insertBefore() DOM method. + * + * :param: e.detail.before the reference dom element, before which new element is added + * :param: e.detail.element a dom element to add to the toolbar + */ + toolbar.addEventListener( "impress:toolbar:insertBefore", function( e ) { + toolbar.insertBefore( e.detail.element, e.detail.before ); + } ); + + /** + * Remove the widget in e.detail.remove. + */ + toolbar.addEventListener( "impress:toolbar:removeWidget", function( e ) { + toolbar.removeChild( e.detail.remove ); + } ); + + document.addEventListener( "impress:init", function( event ) { + var api = event.detail.api; + api.lib.gc.addCallback( function() { + toolbar.innerHTML = ""; + groups = []; + } ); + } ); + } // If toolbar + +} )( document );