Search code examples
javascriptoverwritekeycode

Overwrite event.keycode in plugin (impress.js) without changing code in plugin


I am using impress.js as a plugin and I am trying to overwrite the keycode definitions without altering impress.js itself (otherwise during the next update the changes will be overwritten.)

This is how the keycode definitions are implemented in impress.js:

    // KEYBOARD NAVIGATION HANDLERS

    // Prevent default keydown action when one of supported key is pressed.
    document.addEventListener( "keydown", function( event ) {
        if ( event.keyCode === 9 ||
           ( event.keyCode >= 32 && event.keyCode <= 34 ) ||
           ( event.keyCode >= 37 && event.keyCode <= 40 ) ) {
            event.preventDefault();
        }
    }, false );


        if ( event.shiftKey || event.altKey || event.ctrlKey || event.metaKey ) {
            return;
        }

        if ( event.keyCode === 9 ||
           ( event.keyCode >= 32 && event.keyCode <= 34 ) ||
           ( event.keyCode >= 37 && event.keyCode <= 40 ) ) {
            switch ( event.keyCode ) {
                case 33: // Page up
                case 37: // Left
                case 38: // Up
                         api.prev();
                         break;
                case 9:  // Tab
                case 32: // Space
                case 34: // Page down
                case 39: // Right
                case 40: // Down
                         api.next();
                         break;
            }

            event.preventDefault();
        }
    }, false );

This is how I am trying to overwrite their definition (in a separate js file, but code is executed after impress.js is initiated):

  • space key should call pause
  • the other keys should have no effect.

    // Bind keyboard events.. document.addEventListener('keyup', function (event) {

    if (event.keyCode === 9 || (event.keyCode >= 32 && event.keyCode <= 34) || (event.keyCode >= 37 && event.keyCode <= 40)) {
      switch (event.keyCode) {
        // ..left key arrow, go to previous slide
        case 37:
          return deck.prev();
          break;
          // ..right key arrow, go to previous slide
        case 39:
          return deck.next();
          break;
        case 32: // Space
          return deck.pause();
          break;
        case 9: // Tab
        case 33: // Page up
        case 38: // Up
        case 34: // Page down
        case 40: // Down
           return;
      }
    
      event.preventDefault();
    }
    

    }, false);

However, the function of the keys is not altered.

Can keycodes be overwritten and how can I achieve this?


Solution

  • addEventListener does not overwrite previously added event listeners, this is one of its advantages over using the on* event properties / attributes.

    In order to do what you want you are going to need to add your own impress:init event listener, before the one added by impress, do the same setup as the library does, changing what needs changed, and then calling stopImmediatePropagation().

    stopImmediatePropagation will prevent any other listeners of the same type from being executed, meaning impress's impress:init event listener will not be triggered.

    //code executed before impress.js is loaded
    (function(document,window){
      "use strict";
       var throttle = function( fn, delay ) {
         var timer = null;
         return function() {
           var context = this, args = arguments;
           clearTimeout( timer );
           timer = setTimeout( function() {
             fn.apply( context, args );
           }, delay );
         };
      };
    
      document.addEventListener( "impress:init", function( event ) {
        event.stopImmediatePropagation();
    
        //parts of init code
    
        document.addEventListener('keyup', function(event) {
          if (event.keyCode === 9 || (event.keyCode >= 32 && event.keyCode <= 34) || (event.keyCode >= 37 && event.keyCode <= 40)) {
            switch (event.keyCode) {
              case 37:
                return deck.prev();
                break;
              case 39:
                return deck.next();
                break;
              case 32: // Space
                return deck.pause();
                break;
              case 9: // Tab
              case 33: // Page up
              case 38: // Up
              case 34: // Page down
              case 40: // Down
                return;
            }
            event.preventDefault();
          }
        }, false);
    
        //other part of init code
      });
    
    })(document, window)
    

    Demo

    <script>
    ( function( document, window ) {
        "use strict";
        var throttle = function( fn, delay ) {
            var timer = null;
            return function() {
                var context = this, args = arguments;
                clearTimeout( timer );
                timer = setTimeout( function() {
                    fn.apply( context, args );
                }, delay );
            };
        };
    
        document.addEventListener( "impress:init", function( event ) {
            event.stopImmediatePropagation();
            var api = event.detail.api;
            document.addEventListener( "keydown", function( event ) {
                if ( event.keyCode === 9 ||
                   ( event.keyCode >= 32 && event.keyCode <= 34 ) ||
                   ( event.keyCode >= 37 && event.keyCode <= 40 ) ) {
                    event.preventDefault();
                }
            }, false );
            document.addEventListener( "keyup", function( event ) {
                if ( event.shiftKey || event.altKey || event.ctrlKey || event.metaKey ) {
                    return;
                }
    
                if (event.keyCode === 9 || (event.keyCode >= 32 && event.keyCode <= 34) || (event.keyCode >= 37 && event.keyCode <= 40)) {
                  switch (event.keyCode) {
                    // ..left key arrow, go to previous slide
                    case 37:
                      //return deck.prev();
                      console.log("deck.prev() would have been called");
                      break;
                      // ..right key arrow, go to previous slide
                    case 39:
                      //return deck.next();
                      console.log("deck.next() would have been called");
                      break;
                    case 32: // Space
                      //return deck.pause();
                      console.log("deck.pause() would have been called");
                      break;
                    case 9: // Tab
                    case 33: // Page up
                    case 38: // Up
                    case 34: // Page down
                    case 40: // Down
                       return;
                  }
    
                  event.preventDefault();
                }
            }, false );
    
            document.addEventListener( "click", function( event ) {
                var target = event.target;
                while ( ( target.tagName !== "A" ) &&
                        ( target !== document.documentElement ) ) {
                    target = target.parentNode;
                }
    
                if ( target.tagName === "A" ) {
                    var href = target.getAttribute( "href" );
                    if ( href && href[ 0 ] === "#" ) {
                        target = document.getElementById( href.slice( 1 ) );
                    }
                }
    
                if ( api.goto( target ) ) {
                    event.stopImmediatePropagation();
                    event.preventDefault();
                }
            }, false );
    
            document.addEventListener( "click", function( event ) {
                var target = event.target;
    
                while ( !( target.classList.contains( "step" ) &&
                          !target.classList.contains( "active" ) ) &&
                          ( target !== document.documentElement ) ) {
                    target = target.parentNode;
                }
    
                if ( api.goto( target ) ) {
                    event.preventDefault();
                }
            }, false );
    
            document.addEventListener( "touchstart", function( event ) {
                if ( event.touches.length === 1 ) {
                    var x = event.touches[ 0 ].clientX,
                        width = window.innerWidth * 0.3,
                        result = null;
    
                    if ( x < width ) {
                        result = api.prev();
                    } else if ( x > window.innerWidth - width ) {
                        result = api.next();
                    }
    
                    if ( result ) {
                        event.preventDefault();
                    }
                }
            }, false );
    
            window.addEventListener( "resize", throttle( function() {
                api.goto( document.querySelector( ".step.active" ), 500 );
            }, 250 ), false );
      
        }, false );
    } )( document, window );
    </script>
    <link rel="styleshee" href="https://cdn.rawgit.com/impress/impress.js/master/css/impress-demo.css">
    
    <div id="impress">
        <div id="bored" class="step slide" data-x="-1000" data-y="-1500">
            <q>Aren’t you just <b>bored</b> with all those slides-based presentations?</q>
        </div>
        <div class="step slide" data-x="0" data-y="-1500">
            <q>Don’t you think that presentations given <strong>in modern browsers</strong> shouldn’t <strong>copy the limits</strong> of ‘classic’ slide decks?</q>
        </div>
        <div class="step slide" data-x="1000" data-y="-1500">
            <q>Would you like to <strong>impress your audience</strong> with <strong>stunning visualization</strong> of your talk?</q>
        </div>
        <div id="title" class="step" data-x="0" data-y="0" data-scale="4">
            <span class="try">then you should try</span>
            <h1>impress.js<sup>*</sup></h1>
            <span class="footnote"><sup>*</sup> no rhyme intended</span>
        </div>
        <div id="its" class="step" data-x="850" data-y="3000" data-rotate="90" data-scale="5">
            <p>It’s a <strong>presentation tool</strong> <br/>
            inspired by the idea behind <a href="http://prezi.com">prezi.com</a> <br/>
            and based on the <strong>power of CSS3 transforms and transitions</strong> in modern browsers.</p>
        </div>
        <div id="big" class="step" data-x="3500" data-y="2100" data-rotate="180" data-scale="6">
            <p>visualize your <b>big</b> <span class="thoughts">thoughts</span></p>
        </div>
        <div id="tiny" class="step" data-x="2825" data-y="2325" data-z="-3000" data-rotate="300" data-scale="1">
            <p>and <b>tiny</b> ideas</p>
        </div>
        <div id="ing" class="step" data-x="3500" data-y="-850" data-rotate="270" data-scale="6">
            <p>by <b class="positioning">positioning</b>, <b class="rotating">rotating</b> and <b class="scaling">scaling</b> them on an infinite canvas</p>
        </div>
        <div id="imagination" class="step" data-x="6700" data-y="-300" data-scale="6">
            <p>the only <b>limit</b> is your <b class="imagination">imagination</b></p>
        </div>
        <div id="source" class="step" data-x="6300" data-y="2000" data-rotate="20" data-scale="4">
            <p>want to know more?</p>
            <q><a href="http://github.com/bartaz/impress.js">use the source</a>, Luke!</q>
        </div>
        <div id="one-more-thing" class="step" data-x="6000" data-y="4000" data-scale="2">
            <p>one more thing...</p>
        </div>
        <div id="its-in-3d" class="step" data-x="6200" data-y="4300" data-z="-100" data-rotate-x="-40" data-rotate-y="10" data-scale="2">
            <p><span class="have">have</span> <span class="you">you</span> <span class="noticed">noticed</span> <span class="its">it’s</span> <span class="in">in</span> <b>3D<sup>*</sup></b>?</p>
            <span class="footnote">* beat that, prezi ;)</span>
        </div>
        <div id="overview" class="step" data-x="3000" data-y="1500" data-scale="10"></div>
    </div>
    
    <script src="https://cdn.rawgit.com/impress/impress.js/master/js/impress.js"></script>
    <script>impress().init();</script>