Hide and Show Player Controls Dynamically

Oct 17, 2013

Through my investigation and subsequent frustration with the inability to selectively Hide or Disable player controls in the Storyline player, then Show or Enable them again I've come upon a solution that I thought I'd share.

Storyline creates and stores 'Control Layouts' in an XML file called frame.xml. The names of the layouts are arbitrary and referenced by each slide when loaded to bring about the selected layout prior to publishing. However, I did discover that Storyline exposes a callback to Javascript allowing the use of Javascript to change the control layout dynamically. The only hitch is that you must know the 'Name' of the control layout stored in the frame.xml file to reference it in your Javascript call.

My custom Javascript function looks something like this and is loaded on the first slide. The function can then be re-used throughout the presentation.

setSlideControls = function(controls) {

     var player = GetPlayer();

     var args = new Array();

     args[0] = controls;

     player.SetControlLayout(args);

};

What I did discover, however, is that you can build your own XML control layout nodes with known names and simply insert them into the frame.xml file after publishing and before upload. The XML is pretty self explanatory with each of the controls references within a given control layout node.

A couple of my 'Locked' layouts are as follows:

<control_layout name="lockedWithPrevious"><control name="volume" enabled="true" /><control name="seekbar" enabled="false" /><control name="replay" enabled="true" /><control name="pauseplay" enabled="true" /><control name="previous" enabled="true" /><control name="next" enabled="false" /><control name="submit" enabled="false" /><control name="resources" enabled="false" /><control name="glossary" enabled="false" /><control name="transcript" enabled="true" /><control name="outline" enabled="true"><controls><control name="search" enabled="false" /></controls></control></control_layout>

<control_layout name="lockedNoPrevious"><control name="volume" enabled="true" /><control name="seekbar" enabled="false" /><control name="replay" enabled="true" /><control name="pauseplay" enabled="true" /><control name="previous" enabled="false" /><control name="next" enabled="false" /><control name="submit" enabled="false" /><control name="resources" enabled="false" /><control name="glossary" enabled="false" /><control name="transcript" enabled="true" /><control name="outline" enabled="true"><controls><control name="search" enabled="false" /></controls></control></control_layout>

I have been successful in creating 'Locked' slide layouts where the seekbar and next button is removed at the start of the slide timeline and then re-appears at the end of the slide timeline allowing the user to freely navigate the slide and proceed to the next slide. I use custom variables to track slide completion so that when the user returns to the slide it will automatically be unlocked if it was previously viewed.

Please respond to this thread if you are interested in how to do this yourself. I will provide sample code.

Let me be clear that this method may become obsolete with newer versions of Storyline if the publishing output changes or Javascript callbacks are modified in the future.

I'd also like to add to the folks at Storyline that it would be a wonderful thing to have triggers for enabling and disabling player controls on demand so that this work around would not be necessary.

Thanks.

21 Replies
Jamie Smith

I've added the feature request.

Also, I'm now extending the Javascript functions to include support for HTML5 as the logic is different from the Flash output. Naturally, the HTML5 lends more easily to Javascript manipulation and utilizes the jQuery library. The Javascript is a bit more extensive. However, there is no need for custom XML control layouts with the HTML5 output support.

Jamie Smith

Code for both Flash and HTML5 is below.

NOTE:

For each slide you'll need to 'lock' and 'open' the slide with triggers. For example, you could lock the slide at timeline start and unlock the slide at timeline end. The Javascript functions used are 'lockSlide()' and 'openSlide()'.

A single parameter for lockSlide is used for specifying whether a previous button should be displayed. Two parameters are allowed for the openSlide function, the first for a previous button and the the second for a next button to be displayed. The parameters affect only the Flash display as we have to specify an entirely different control layout each time the functions are run. With HTML5, we're able to simply hide and show the next button and seek bar without actually changing the controls layout.

Example: lockSlide(1); = lock slide with a previous button displayed, openSlide(0,1); = open slide without a previous button and with a next button

// JavaScript Document
// only run this once
if (typeof setSlideControls === 'undefined') {
    openSlide = function(prev, next)
    {
       var player = GetPlayer();
       var args = new Array();
       args[0] = "openWithPreviousWithNext";
       switch (prev)
       {
          case 1 :
             switch (next)
             {
             case 1 :
                args[0] = "openWithPreviousWithNext";
                break;
             default :
                args[0] = "openWithPreviousNoNext";
                break;
             }
             break;
          default :
             switch (next)
             {
             case 1 :
                args[0] = "openNoPreviousWithNext";
                break;
             default :
                args[0] = "openNoPreviousNoNext";
                break;
             }
             break;
       }
       if (player.useCanvas)
       {
            $("#control-next").css("visibility","visible");
            $("#progressbar").css("visibility","visible");
       }
       else
       {
          player.SetControlLayout(args);
       }
    };
    
    lockSlide = function(prev)
    {
       var player = GetPlayer();
       var args = new Array();
       switch (prev)
       {
          case 1 :
          args[0] = "lockedWithPrevious";
          break;
          default :
          args[0] = "lockedNoPrevious";
          break;
       }
       if (player.useCanvas)
       {
            $("#control-next").css("visibility","hidden");
            $("#progressbar").css("visibility","hidden");
       }
       else
       {
          player.SetControlLayout(args);
       }
    };
    
    setSlideControls = function(controls)
    {
       var player = GetPlayer();
       var args = new Array();
       args[0] = controls;
       player.SetControlLayout(args);
    };
                
}
Here are my example xml nodes to be inserted into the frame.xml file after publishing. This allows reference to the control layouts by a specific name and is only used for the Flash content.
(Remove the <pre> tags as I had to include them in order to get the other content to show as HTML.)
<pre><control_layout name="openWithPreviousWithNext"><control name="volume" enabled="true" /><control name="seekbar" enabled="true" /><control name="replay" enabled="true" /><control name="pauseplay" enabled="true" /><control name="previous" enabled="true" /><control name="next" enabled="true" /><control name="submit" enabled="false" /><control name="resources" enabled="false" /><control name="glossary" enabled="false" /><control name="transcript" enabled="true" /><control name="outline" enabled="true"><controls><control name="search" enabled="false" /></controls></control></control_layout>
<control_layout name="openWithPreviousNoNext"><control name="volume" enabled="true" /><control name="seekbar" enabled="true" /><control name="replay" enabled="true" /><control name="pauseplay" enabled="true" /><control name="previous" enabled="true" /><control name="next" enabled="false" /><control name="submit" enabled="false" /><control name="resources" enabled="false" /><control name="glossary" enabled="false" /><control name="transcript" enabled="true" /><control name="outline" enabled="true"><controls><control name="search" enabled="false" /></controls></control></control_layout>
<control_layout name="openNoPreviousWithNext"><control name="volume" enabled="true" /><control name="seekbar" enabled="true" /><control name="replay" enabled="true" /><control name="pauseplay" enabled="true" /><control name="previous" enabled="false" /><control name="next" enabled="true" /><control name="submit" enabled="false" /><control name="resources" enabled="false" /><control name="glossary" enabled="false" /><control name="transcript" enabled="true" /><control name="outline" enabled="true"><controls><control name="search" enabled="false" /></controls></control></control_layout>
<control_layout name="openNoPreviousNoNext"><control name="volume" enabled="true" /><control name="seekbar" enabled="true" /><control name="replay" enabled="true" /><control name="pauseplay" enabled="true" /><control name="previous" enabled="false" /><control name="next" enabled="false" /><control name="submit" enabled="false" /><control name="resources" enabled="false" /><control name="glossary" enabled="false" /><control name="transcript" enabled="true" /><control name="outline" enabled="true"><controls><control name="search" enabled="false" /></controls></control></control_layout>
<control_layout name="lockedWithPrevious"><control name="volume" enabled="true" /><control name="seekbar" enabled="false" /><control name="replay" enabled="true" /><control name="pauseplay" enabled="true" /><control name="previous" enabled="true" /><control name="next" enabled="false" /><control name="submit" enabled="false" /><control name="resources" enabled="false" /><control name="glossary" enabled="false" /><control name="transcript" enabled="true" /><control name="outline" enabled="true"><controls><control name="search" enabled="false" /></controls></control></control_layout>
<control_layout name="lockedNoPrevious"><control name="volume" enabled="true" /><control name="seekbar" enabled="false" /><control name="replay" enabled="true" /><control name="pauseplay" enabled="true" /><control name="previous" enabled="false" /><control name="next" enabled="false" /><control name="submit" enabled="false" /><control name="resources" enabled="false" /><control name="glossary" enabled="false" /><control name="transcript" enabled="true" /><control name="outline" enabled="true"><controls><control name="search" enabled="false" /></controls></control></control_layout></pre>
jyothi sita

Hi Jamie,

Thank you so much for your response. Awesome!! Thanks a lot....!

Could you please send a screenshot of chaning "javascript and control layout" code in frame.xml file. So that I will have a clear understanding of where to change the code. Now i am a bit confused to check and change the code in frame.xml file.

I have a question, can we remove the hand cursor on seekbar when it progress or else can we restrict the user from dragging the seekbar? Appreciate your help....!

Thanks,

Jyothi

Denise Bell

I found this forum discussion this morning while searching for the ability to do exactly what Jamie has found a solution to. Thank you Jamie! Before we go down the path of custom programming, we have been attempting to avoid this, I wanted to ask if this feature request has been considered for a future Articulate Storyline version? If so, is there a know release date?

Thanks so much,

Denise

Leslie McKerchie

Hi Denise and welcome to E-Learning Heroes!

You are more than welcome to submit a feature request. This will go to our development team, but we do not share release notes or dates for our software.

Threads are updated and releases are shared via social media, I would recommend following our blog here.

Mike F

Hey Jamie. Cool stuff. It may be my only option.

I added two custom player tabs (Help, Quiz). 'Help' opens a lightbox slide, and 'Quiz' takes you to the first slide in quiz scene. Allows users to go directly to the quiz.

Now, I want these tabs visible at all times EXCEPT during the quiz, and also on the very first slide in the course. This is a flash splash screen that I want to remain clean and clear of any controls.

SL doesn't provide an option to turn off custom tabs for individual slides. It's either all or nothing. Not helping me at this point. So, I'm thinking JS. I'm familiar with the Frame.xml file and control layouts, but I'm clunky with JS. The "tabs" optionlist contains the two tabs. Is it possible to access these using JS? How would it be coded?

-   <optionlist name="tabs">
-            <listitems>
-              <listitem name="outline" value="true" group="linkleft" />
-              <listitem name="customlink" value="true" group="linkleft">
-                <properties>
-                  <property name="title" value="Help" />
-                  <property name="data" value="68xHXdQcCxg" />
-                </properties>
-              </listitem>
-              <listitem name="customlink" value="true" group="linkleft">
-                <properties>
-                  <property name="title" value="Quiz" />
-                  <property name="data" value="6lf88Curzkc" />
-                </properties>
-              </listitem>
-             <listitem name="resources" value="true" group="linkright" />
-              <listitem name="glossary" value="false" group="sidebar" />
-              <listitem name="transcript" value="false" group="sidebar" />
-            </listitems>
-          </optionlist>

julie g.

Hi Jamie, I am after something along these lines and I have seen several of your posts while researching so maybe you have tackled this before. I want to change the frame.xml value: <option name="flow" value="restricted" /> to "free" on a case by case basis by adding a script function to our lms. I am looking for a script that can override the restricted navigation within a users account. We require a restricted menu but there are cases where we can allow students to skip ahead, especially if they get stuck for various reasons. Do you know of anyway to achieve this?