Adding an HTML menu to Articulate Storyline

Run Demo: This deals with adding a HTML CSS3 Jquery menu to a Articulate Storyline eLearning project (Flash version Storyline 1)

The example has only 5 pages only. (the other 41 pages would also work if you added them)

Click image to run Demo: then right click the custom menu (that’s right it’s an HML page). view the source. It’s a table but could have used ul css menus too.

New Version 1.0.2
Updated April 14, 2015

Fixes April 14:
Moved some repeating code to the master slide.
Added the following code so you can have up to 999 slides.
var pagenum = player.GetVar(‘page’).slice(-3).replace(/\D/g,”); //good for 999
if (pagenum && ~~Number(pagenum) > 0 ) { getResumeStates(pagenum,’1′); }

Fixes April 13:
In version 1.0.0 all of the JavaScript code was located in NavMenu.html
Storyline doesn’t insert the iframe until a trigger opens it.
Thus, no loaded NavMenu.html, no updates to the table rows when iframe page is hidden.

To fix this, I had to make a global.js file.
To load the global.js file into the story.html was like pulling teeth.
Storyline is definitely not like Lectora when it comes to adding custom code to the main page. In fact, it can’t do it at all.

I had to add an extra JavaScipt Trigger on the Master slide:

if (! parent.document.getElementById(“globalScript”)) {
var player = GetPlayer();
var webObjectFolder = player.GetVar(‘webObjectFolder’);
var imported = parent.document.createElement(“script”);
imported.id=”globalScript”;
imported.src = “story_content/WebObjects/”+webObjectFolder+”/global.js”;
document.getElementsByTagName(“head”)[0].appendChild(imported);
}

Why does Storyline put every function call on every slide in user.js ?? Shouldn’t I have a choice? I only neeeded to call the above code once on the page load.
Hence, all the extra (what if) code, to prevent Storyline from insert a million elements to the head of the storyline.html page.
Storyline staff: please add the ability to add custom code to story.html

Why does Storyline generate cryptic keys and ids (and some elements with no ids)
Storyline staff: please add the ability to add your own DOM ids and CSS class names.

Seriously, a HTML menu could have been easy created with just a few lines of code if not for their coding methods.
Are the trying to hide something? Have they never heard of Sothink, decomplilers.
Get with the program. If Lectora ever gets a timeline control I may switch.
By the way, I charge clients twice as much if they insist on Lectora.
Why? because it takes twice as long without a timeline editor.

Next beef: Look at the stupid generate folder name below:
story_content/WebObjects/6JDSFFoygud/global.js
Would have made my life easier if I had the abilty to name the folder in Storyline.

Enough said – Let’s continue:

The example has only 5 pages (the other 41 pages would also work if you added them)

How it works:

There are now 5 custom storyline variable to track:
gotoPage : Number
page : Text
resumeStates : Text
totalPages :  Number
webObjectFolder:  Text

Each Page:

On each page there is a Image Trigger:
The page number is controlled by the last character in the page variable.
example: ‘page 1′ or ‘Viewing page number 1′

Just copy and paste the image trigger to your new pages then change ‘Set page to page #’
e.g. ‘Set page to page 5′ The html table will be given an id of 5 automatically
on the fifth row that does not a ‘.header’ class.

You can edit the HTML table rows and css styles to suit your needs.

Slide Master:

The WebObject html NavMenu is a layer (menu) but it can be placed anywhere.
The menu layer also has a image Trigger and it has a ‘jump to XXX’ for each and every page you add.

Yes. I know, this really sucks – Storyline Development staff (INTERNAL PAGE VARIABLE ANYONE?).
So for now just copy and paste it a gazillion times and change Slide and number to match.

Everything is controlled by the  two JavaScripts triggers on ‘timeline starts’ and ‘timeline ends’ on the Master Slide.

Known problems:
When I refresh the page the ‘Would you like to resume’ does not save our custom variables for the current page.  This may be just be in my JavaScript order. Any JavaScript Master please find and fix.

Update (April 12, 2015): Seems Storyline doesn’t save your custom variable until you change pages. Would be better if they were saved at (both) timeline start and timeline end.

From Articulate Storyline Forum about this:

http://www.articulate.com/blog/save-states-slide-upon-resume-storyline/

I am giving this away for free so please post any new version that make this a better solution.  This is Beta version 1.0 – so use at own risk. I have not tested this on LMS to see if resumeStates is stored on LMS.

Update (April 12, 2015); tested on cloud.scorm will Flash cookies turn off on LMS. Worked as expected except for saving the current pages variable as mentioned above.

Hopefully, someone out there will improve this; as a custom navigation menu is sorrily needed in Storyline!

JavaScript testing:
When will Storyline staff fix the Web Object not updating when re-publishing !!!!!
In the meantime, I open the user.js (page triggers) and story_content\WebObjects\XXXX\NavMenu.html in notepad++
for fast editing and testing without re-publishing (just refresh the browser page after edits).
If I make changes, then re-publish, notepad++ will tell you the content has changed.
DO NOT RELOAD ! – click ‘No’ add a space to you edited page and save it or your lost your work to an old copy (the one that was inserted as the webObject). EVEN IF YOU ARE EDITING THE ORIGINAL HTML PAGE for the webobject folder you selected.

This broken webObject feature has been mentioned for over 2 yers on Storylines Forum. The only way to fix this manual is to delete the webObject and start all over again.

PLEASE FIX THIS STORYLINE so I can edit my HTML page from the selected folder of webObject!!!

Page reloads: Since storyline reloads the webObject every time you change pages,
the ‘timeline start’ has a delay so the javascript can load.

setTimeout(function (){visited();}, 200);

function visited() {
player = GetPlayer();
var pagenum = player.GetVar(‘page’).slice(-3).replace(/\D/g,”); //good for 999
if (pagenum && ~~Number(pagenum) > 0 ) { getResumeStates(pagenum,’1′); }
}

Timeout may not be the best solution. Better solutions anyone?

window.frames[0] and the navMenu.html file name:

It was pointed out to me that frames[0] will break if more than one web object is on page.

Change the following  global.js:

if(window.frames.length > 0) {
if ( typeof window.frames[0].addTableElements == 'function' ) { window.frames[0].addTableElements(resumeStates); }
}

to the code below (I’ll leave this up to you) as NavMenu.html would also fail if you renames the table page. More variable, more variables…

for (var i = 0; i < window.frames.length; i++) {
if ((window.frames[i].location).toString().indexOf("NavMenu.html") > 0 ) {
window.frames[i].addTableElements(resumeStates); break;
}
} //end loop through frames collections

In the NavMenu.html these is a windows resize function I got off the internet to resize the font in the web object table. If using IE9 or above or any other browser you can remove this function and simple add change vw font-size in the style section:

#menuTable {
font-family: Arial, Helvetica, sans-serif;
width: 300px;
 font-size: 4.33vw;
color: white;
}

The CSS3 vw and vh scales elements to 1/100 units of width or height.

e.g. My body font-size is 13px and #menuTable is 300px wide so .130 x 300 = 4.33 vw

This scales the font smaller when you make the browser window smaller and retains the size if you refreshed or reloaded; to which the window resize function could not.

P.S. In a perfect world.

The HTML navigation would be outside the Flash storyline player.
That is, it would be the parent DIV of the storyline FLASH pageDIV.
You would be able to just build your own CSS3 navigation and seekbar, volume, etc.
and storyline would not over write your index page when publishing.
And you could add simple links like ‘GotoPage 19′.
Storyline staff, give up on FLASH what’s the point when you have a canvas version?

How to improve: rewrite code to wrap it around Storyline’s Flash Div as mentioned above. Better still, put Story.html in iframe and have NavMenu as parent, totally high-jack Storyline.html page load so it works for any publishing setting then…  Oh, forget it. Back to the drawing board.

Demo:

http://robbiestewart.ca/storytest/NavMenu/story.html

Storyline 1 files:

http://robbiestewart.ca/storytest/NavMenu.zip

 

Posted in Storyline | Tagged , | 1 Comment

Jquery Timeline range control (like Flash, Storyline, Recording Software)

myRangeSlider Jquery Plugin
A horizontally or vertically Timeline Range Slider.


myRangeSlider

These type of range sliders can be found in timeline animation programs like Flash and Storyline. Range Slider are also used extensively in audio recording programs to display audio wave form ranges on music tracks and as normal mixing sliders.

The jquery plugin code is as minimal as I could get it.
You will need to add your own functions and routines.

Why? I was building an HTML animation timeline that looked and performed exactly like the one found in the Adobe Flash editor. I was used nouiSlider as my control but found it extremely difficult to perform simple tasks like change the handle’s color on mousedown event. The next range slider I used was JQslider which I also abandoned because it used jQuery UI (I prefer to be in total control of my code).

Code break down (Top Section):

;(function($) { $.fn.myRangeSlider = function(options) {
var defaults = { HORIZ:true, BtnWH:20,LowerRange:'',UpperRange:'' }
var option = $.extend(defaults, options);
var Slider = this, handle = Slider.children(0); //jQuery objects.
var _mouseDownLT, _mouseDownXY, _lastMouseDownXY, xy, MouseXY;
var Hclass, origX, origY, origW, origH, origL, origT;
var a,b, constraint, drag, maxL, maxH, maxR, maxB, rs, mouseX, mouseY, formula;
var edge, _mouseDown = false, hasTouch = false, tip, Btn, dragHandle = false;
if (option.HORIZ==true) { edge='left'; } else { edge='top'; }

The Top Section basically just sets all the variables as local so it can run miniumally as a multi-instance plugin:
Add you own Plug init (this one does not conform to Jquery Plugin design best practises).

Next Section:

////////////// Build the drag Handles //////////////////
edge==='left' ? ( a='edgeL', b='edgeR') : ( a='edgeT', b='edgeB');
handle.prepend("<div class='"+a+"'></div><div class='"+b+"'></div>");
////////////// drag Handle routines //////////////////
$('.edgeL, .edgeR, .edgeT, .edgeB', this).on('mousedown', function(e){
dragHandle = true; Hclass = $(this).attr('class'); Btn = option.BtnWH;
origX = e.pageX-$(this).offset().left; origW = handle.outerWidth(); origL = handle.position().left
origY = e.pageY-$(this).offset().top; origH = handle.outerHeight(); origT = handle.position().top
});

$('.edgeL, .edgeR, .edgeT, .edgeB', this).on('mouseup', function(e){ dragHandle = false; });

Everything is built in the HTML and sized in CSS file except the drag handles on the sliders Btn (drag edges).

Code to init on HTML page:

$(document).ready(function () {
$('#Slider1').myRangeSlider({
  HORIZ: true,
  BtnWH: 60,
  LowerRange: '#LowerH',
  UpperRange: '#UpperH' });
});

<body>
    <div id="Slider1">
      <div class="Hhandle">H</div>
    </div>
    
<div id="LowerH">0</div><div id="UpperH">0</div>
    
</body>

1. Place a DIV on page and give it an ID “e.g. Slider1″.
2. Add a second DIV with the class “Hhandle” (horitontal) or “Vhandle” (vertical)

Rounded.css controls all positioning and styles.
Clean.css is the same without the fancy look.

The $().myRangeSlider parameters:

HORIZ: true (default) the slide is horizontal in design, false for vertical

BtnWH: number (20 default) the minimum width the drag handle (button) can be sized to. Going lower than 20 will have the button edges overlap or disappear.

LowerRange: string (“” default) name of a DIV that will receive lower range value as jquery HTML().

UpperRange: string (“” default) name of a DIV that will receive upper range value as jquery HTML().

Take Note: All dragging and sliding of the handle is executed in the
var Drag = function(e,MouseXY) { code… }
Everything after the Drag function code is just mouse events for desktop and touch events.
You should not have to change anything after the Drag function().

The clamp function does most of the range constraints.
Feed it a number and it return a number that does not exceed the min or max values:

var clamp = function(num, min, max) { return num < min ? min : (num > max ? max : num); };

Clamp uses a shorthand ‘if statement’ (ternary operator) where ?=Then and :=Else.

I also use a similar clamp using JavaScript Math:
constraint = Math.max(lower value, Math.min(Math.min(some value), upper value)));

The CSS.
It is very important to look at the ‘!important’ flags in the css file.
MyRangeFinder is pixel perfect. However, bugs in different versions of jQuery plus lots of bugs in browsers  make it almost impossible to get the exact width or height of elements that have borders, padding and/or margins.

If you exceed the clamp values by only a pixel (e.g. adding a border) then strange effects are produced.  Exceeding the right edge by just a pixel will have the handle move in unexpected ways. I played with changing width() to InnerWisth, OuterWidth(), Position(), offset(). I gave up, so best not to add borders and such. Use insert box shadows to fake borders or use before:after css.

Tip: Just need it to be just a slider?  add  display: none to *[class^=’edge’] in the css.

UPDATE (April 7, 2015): Just noticed that jQuery width() and position() are extremely slow in IE 11.

A Google search netted replies to use native JavaScript style.width and style.height:
I will update the Zip files in May with any other suggestions or fixes. In the mean time, you should change where appropriate, as in the following example:

  if (option.HORIZ==true) {
    if (option.LowerRange > '') { $(option.LowerRange).html(parseInt(handle[0].style.left)); }
    if (option.UpperRange > '') { $(option.UpperRange).html(parseInt(handle[0].style.left) + parseInt(handle[0].style.width)); }
  } else {
    if (option.LowerRange > '') { $(option.LowerRange).html(parseInt(handle[0].style.top)); }
    if (option.UpperRange > '') { $(option.UpperRange).html(parseInt(handle[0].style.top) + parseInt(handle[0].style.height)); }
  }

Sorry in advance if I do not answer any posts or emails. I am either extremely busy or extremely lazy on days.

View Demo:
http://RobbieStewart.ca/myRangeSlider/myRangeSlider.html

Zip file with code:
http://RobbieStewart.ca/myRangeSlider/myRangeSlider.zip

Robbie
Thank you.

Posted in html5, jQuery mouseSwipe | Tagged , , , , , , | Leave a comment

So you want Parallax Scrolling on iOS iPad, iPhone and iPod

parallaxparallaxSwipe for all touch and web browsers including iOS touch screens.
This week I looked at a jQuery parallax plugin by Jonathan Nicol at f6design. So, I grapped it and then spent hours designing a page to use for an iPad project for a car manufacturer. It worked OK in my browsers and my Android touch pad but not at all on my Apple iPod.

I then Googled the problem and got a link to a forum on css-tricks that explained Apples problems. Next, I saw a link on the forum to a Nike page that said the Nike jumpman23 parallax page actually worked on his iPad. See jumpman23 (really nice effect).

Well, you guessed it: I looked at the Nike source code and saw a billion js files. So, rather then sift through them, I though: ‘Hey, my mouseSwipe plugin (bottom of page) could do it by adding top layers and looping though them setting different speeds per layer.’

My mouseSwipe plugin does not use browser scroll functions, just math to position its swipe page. I then removed the panel swipe code and other features to leave just the swiping code I wrote for the plugin. Next, I only added three lines of code using the jQuery each() and an array to hold the speed of each parallax layers. My CSS file took care of the positioning.

Here’s the Demo: I used the images and layout from f6Design but shrunk them and re-arranged the layout to explain the code better.

And here’s the code in a zip file.

Have fun!
Apple can send me a donation, as I’m still looking for work.

Posted in jQuery mouseSwipe | Tagged , , , , | Leave a comment

jQuery selectSwipe Select option Scroller

selectSwipeHere’s an ipad/android style menu option select scroller that should work on all browsers and touch pads.

(except ie6 and ie7 due to css incompatibility! e.g. position: absolute, fixed and pointer-events: none; for overlaying glass image)

It might not look to impressive at first look. However it was the first swipe code on the internet that worked on both touch and desktop browsers (In under 100 lines and not using css3 web-kit). I’m sure others will copy the routines to drop about a 1000 lines off their poorly coded crap.

I’ve included the selectSwipe.js file uncompressed at 5kb (should be under 1kb when minimized). I didn’t included the auto Horizontal css code and removed the physics code used in mouseSwipe as apposed to using jQuery animate use in this demo).

My javascript file should give all the jQuery answers to how to adjust swipe panels. I’m posting this in a hope that jQuery plug-in designers will finish this prototype off and post additional updates and other swipe controls to me.

I’ve done most of the browser compatibility code and mouse vs touch events. I do not have the time to answer questions on this code so please take some of your time to understand the under-laying code (it’s really small to begin with).

I wrote this in about a day, using some code from my mouseSwipe plug-in. So lots of inprovemnets and changes can be added or shared here.

I used extra blank panels at the front and end as padding to center the dates. However, there has got to be a better way to do this. Best to work this out in order to get a panel number and the innerHTML dates during the update() function. I’m still looking for full-time work so I have no time at present. Cheers!

Demo of selectSwipe here

Download Zip file of selectSwipe.

Posted in jQuery mouseSwipe | Tagged , , , , , , , | Leave a comment

HTML5 Canvas example

canvasHere a re-post of my fancy ball reflection code using canvas on enabled HTML5 browers.
Everything can be viewed in the page source of Demo

Click here for Demo

Posted in html5 | Tagged , , , | Leave a comment

mouseSwipe Jquery Touch Content Slider Plugin

mouseSwipe is a jQuery content slider with tablet touch or mouse drag navigation. It weights in at under 4kb in size.

Uploaded new zip with complete original source Dec. 24th 2012.
Sorry, I will not be replying to questions on this plugin as I’m too busy.

mouseSwipeWhy? Because your panel swipes should work all your devices including the desktop browser. (not just ccs3 devices).

It’s also great to add as a fixed container in jquery mobile and other mobile html pages. I used it on a Honda jquery mobile phone app I developed to display huge horizontal grid tables on a small screen (fake iframe).

features:

  • Tablet touch swipe or mouse drag swipping.
  • Horizontal or Vertical layout.
  • Continuous Scroll with end bounce.
  • Or single panel image swipe.
  • Multiple mouseSwipes on single page.
  • Auto scroll with or without rewind.

April 16 2012 update:
This is version 1.0.2 so any input is welcome (don’t complain, its free)

Leave a comment

Tested on the following browers:

  1. IE9 and IE6,7,8 using IETester.
  2. Firefox 10.0.2
  3. Safari 5.1.1
  4. Chrome 17.0
  5. Opera 11.61
  6. iPod touch and Android touch default browsers

Settings and defaults:

  • HORIZ: true or false – horizontal or vertical display. / default = true.
  • TYPE: ‘mouseSwipe’ – drag scroll or touch swipe one or more panels.
  • TYPE: ‘panelSwipe’- swipe slides one panel length at a time. / default = ‘mouseSwipe’
  • SNAPDISTANCE: number – pixel distance before panel changes. / default = 20
  • DURATION: number – time it takes for next panel to slide in. / default = 250
  • EASING: string – must include jquery.easing.1.3.js types or / default = ‘swing’
  • ARROWS: true or false – display button arrows on sides of panel / default = false
  • FADEARROWS: true or false – do not show first or last panel arrows / default = false
  • SLIDESHOWTIME: number – auto scroll time in milliseconds / default = 4000
  • AUTOSTART: number > 0 – delay before autoscroll starts on load / default = 0
  • PAUSEONHOVER: true or false – stop auto slide on mouseover hover / default = false
  • PAGENUM: string – id of div or element to display page# / default = ‘#pagenum’

The Javascript setup:

We use bind dragstart to stop some browser’s drag & drop features.
panelSwipe example:

$(document).ready(function () {

  $(document).bind("dragstart", function() { return false; });

  $('#panelSwipe').swipe({
    TYPE:'panelSwipe',
    HORIZ: true,
    SNAPDISTANCE:20,
    DURATION:750,
    EASING:'easeOutBack',
    ARROWS:true,
    FADEARROWS:false,
    SLIDESHOWTIME:4000,
    AUTOSTART:100,
    PAUSEONHOVER:false,
    PAGENUM:'#pagenum'
  });
});

mouseSwipe example:
note that TYPE:’mouseSwipe’ does not use any of the other options.

$('#mouseSwipe').swipe({
    TYPE:'mouseSwipe',
    HORIZ: true
});

The CSS Setup:

You only need to match the width and height for the Viewport, mouseSwipe and Panel.

<div id="viewport">
<div id="mouseSwipe">
<div class="panel"><img alt="" src="images/01.jpg" /></div>
<div class="panel"><img alt="" src="images/02.jpg" /></div>
<div class="panel"><img alt="" src="images/03.jpg" /></div>
<div class="panel"><img alt="" src="images/04.jpg" /></div>
<div class="panel"><img alt="" src="images/05.jpg" /></div>
</div>
</div>

Fixes to Date:

December 24 2012: 5:15pm est:
Upload new zip with complete original source.  Do as you wish with it as I have no time.

April 16 2012 : 10:30am est:
Revision: 1.0.2 Had to add e.preventDefault() on touchStart=function(e) for older versions of Android to scroll properly.

February 28 2012 : 1:00 est. new version 1.0.1
1. Removed PERCENTAGE option in favour of SNAPDISTANCE and added a lot more panel swipe options. Improved animate stop() during mousedown.

View Demo

Download mouseSwipe zip file – mouseSwipe.zip  complete source December 24th, 2012

Posted in jQuery mouseSwipe | Tagged , , , , , , | Leave a comment