/*

 * (C)2006-7 Stephen Chalmers  

 *

 * This notice must not be removed 

 *

 * Plays media files on hover to provide gratuitous 

 * sound effects or 'talking tooltips'.

 *

 * If not included here, documentation available at:

 * http://www.hotspot.freeserve.co.uk/ttdemo/

 *

 * Please notify any site on which the code is used.

 *

 */





/*** These instructions may be removed ***





Installation and Configuration

==============================



SAVE THIS TEXT/DOCUMENT AS: playmedia.js 



All the links that will play media files, must be given a 'title'

attribute if they do not have one already, e.g.



<A href='/content/index.htm' title='Contents Page'>Contents</A>



At any point in the HTML file /below/ the last link, insert the

following code. Note: If playmedia.js is located in a different

folder, specify a relative path.



<SCRIPT type='text/javascript' src='playmedia.js'> </SCRIPT>



<SCRIPT type='text/javascript'>



 PlayMedia.mediaPath="";  // <-- See 'Paths' 



 PlayMedia.setup( "title1", "file1.wav", 

                 "title2", "file2.wav",

                 ........ );



 PlayMedia.once('tick.wav'); // <-- Cause plugin to load (See 'Performance') 

  

</SCRIPT>



The parameters passed to PlayMedia.setup() above must be substituted

with your own, as explained below.



Example.



You have three links whose titles are: "Products", "Ordering", and 

"Site Map" and you want to assign them the sound files: 'newprod.wav',

'ordering.wav', and 'map.wav' respectively.



 PlayMedia.setup( "new products", "newprod.wav", 

                  "ordering", "ordering.wav", 

                  "site map", "map.wav" );



Notes

=====



There should be only one call to PlayMedia.setup per document.



Not all the links in the document need be involved in playing sounds.



Title / Filename parameter pairs need not be passed in the order in

which the links appear in the document.



The title specified for each link need not be its full title, a unique

substring is sufficient, provided that it does not appear within the

title of a different link. Thus the example above could have been written:



 PlayMedia.setup( "new p", "newprod.wav", 

                  "ord", "ordering.wav", 

                  "map", "map.wav" );

              

This feature makes it very easy to configure all links to play the

same file (if you must), by specifying a single character common to

the titles of all the links.              

For instance, if all link titles end with a period (.), the 

following statement makes all links play 'blip.wav':              

              

 PlayMedia.setup( ".", "blip.wav");



There is no guarantee that all types of plugin on all platforms will

remain hidden.



Form Buttons

============

Form elements of type 'button', 'reset' & 'submit' can be used to

play sounds when hovered in exactly the same way as links, the only 

difference being that they must be identified via the text of their 'value'

attribute instead of via 'title'.



Performance

===========

Plugins do not load into memory until first required, therefore to prevent 

unwanted delay in playing the first sound, it is advisable to play a small,

virtually inaudible sound file automatially when the page loads. 

The PlayMedia.once() function is provided for this purpose. Include it as

shown in 'Installation' and pass it the name of either a small unobtrusive/

inaudible sound file, or perhaps one with a short 'welcome' message.



Alternativeley PlayMedia.once can be called by the onload event:

 

 window.onload=function(){ PlayMedia.once('tick.wav'); }

 

This option ensures that the document's content is rendered before the plugin

loads, which is a process that can delay other actions.

If you use onload, ensure that you combine the handler with that of any other

script that may use the event.



Paths

=====

If the sound files are located all together in a different folder, 

specify a /relative/ path in the PlayMedia.mediaPath variable, otherwise leave

it unchanged.



For example, if the files are in a parallel folder called 'media', specify:



 PlayMedia.mediaPath="../media/";



If the media files are in the same folder as the document, the line above 

can be omitted.



Alternatively, paths may be specified as a part of each filename parameter.



Mute

====

To allow users to disable sound, place the following link anywhere

in your HTML.



<a href='#' title='Mute' onclick="PlayMedia.toggle();return false">Sound Mute</a>



Such a link could play a sound file that says 'mute'.



Timeout

=======  

To prevent premature triggering, there is a default timeout of 400 

milliseconds between mouseover and the instruction to play a file. 

The overall delay may vary between different systems.

If the mouse cursor is removed before the timeout expires, the file

is not played. 



If a media-playing link loads a new document into the current frame or

window, the script will be dismissed so there may not be time to play the

file entirely or at all. Having the script work on hover rather than on click,

increases the potential time available for playing to begin.



Operation

=========

This script will attempt to combine its operation with other mouseover

scripts operating on the same links, provided that it is loaded after any such

scripts.





******** DO NOT EDIT BELOW THIS LINE ************/  





PlayMedia=

{

 contains:String.prototype.contains=function(s)

 {

  return new RegExp(s,"i").test(this);

 },  

 

 push:(typeof Array().push == 'function') ? Array.push : Array.prototype.push=function(elem)

 {

  this[this.length]=elem;

  return this.length;  

 },

 

 pop:(typeof Array().pop == 'function') ? Array.pop : Array.prototype.pop=function()

 {

  var elem;

  

  elem=this[ Math.max(this.length-1,0) ];

  

  if(this.length>0)

   this.length--;

     

  return elem;

 },

 

 hoverDelay:400,

   

 mediaPath:"", objTable:[], canPlay:true,  

 

 useObject:typeof window.pageXOffset!='undefined',

 

 hasSupport:(document.body && document.createElement),

 

 build:function(soundFile)

 {

  this.soundFile=soundFile;

  this.objRef=null;  

  this.tm=null;

  this.buffer=new Image(); //may be ineffective  

  this.buffer.src=this.soundFile;

 },



 sound:function(idx)

 {

  

  if(this.hasSupport && this.canPlay)

  {

   if(this.objTable[idx].objRef!=null)

    {

     document.body.removeChild( this.objTable[idx].objRef );

     this.objTable[idx].objRef=null;

    }

         

   if( (this.objTable[idx].objRef=document.createElement(this.useObject?'OBJECT':'EMBED'))==null )

    window.status="ERROR - Element not created: ["+(typeof this.objTable[idx].objRef)+"]";

   else

   {

     this.objTable[idx].objRef.setAttribute("width","0");

     this.objTable[idx].objRef.setAttribute("height","0");

     this.objTable[idx].objRef.setAttribute("hidden","true");

     this.objTable[idx].objRef.setAttribute("autoplay","true");

     this.objTable[idx].objRef.setAttribute("autostart","true");

     this.objTable[idx].objRef.setAttribute("type", 'audio/wav');

     this.objTable[idx].objRef.setAttribute(this.useObject?"data":"src", this.objTable[idx].soundFile);     

     

     document.body.appendChild( this.objTable[idx].objRef ); 

   }

  }

 },



 stop:function(idx)

 {

  if(this.useObject)

  {

   var obj=this.objTable[idx]; 

   

   if(obj && obj.objRef!=null)

   {

    document.body.removeChild( this.objTable[idx].objRef );

    this.objTable[idx].objRef=null;

   }

  } 

  

 },

 

 once:function(sFile)

 {

  this.objTable.push(new this.build(sFile));

  this.sound(this.objTable.length-1);

  this.objTable.pop();  

 },



 addEvent:function(obj, evt, func)

 {

  if(obj[evt])

  {

   obj[evt]=function(f,g)

   {

    return function()

    {

     f.apply(this,arguments);

     return g.apply(this,arguments);

    };

   }(func, obj[evt]);

  }else obj[evt]=func;

 },

   

 setup:function()

 {

  if(document.body && document.body.appendChild)

  {

    for(var i=0, lnkl=document.links.length; i<lnkl; i++)

    {	

      for(var j=0, al=arguments.length; j<al && !document.links[i].title.contains( arguments[j] ); j+=2)

      ; 

      if( j!=al )

      { 

       var idx = this.objTable.length

       this.objTable[ idx ] = new this.build( this.mediaPath+arguments[ j+1 ] )

       

       this.addEvent(document.links[ i ], "onmouseover", new Function("PlayMedia.objTable["+idx+

       "].tm=setTimeout('PlayMedia.sound("+idx+")', "+this.hoverDelay+")") ); 

       

       this.addEvent(document.links[ i ], "onmouseout", new Function("clearTimeout(PlayMedia.objTable["+

       idx+"].tm); PlayMedia.stop("+

       idx+");")); 

       

      }

    } 



    for(var j=0; j<document.forms.length; j++)

     for(var k=0, df=document.forms[j], el=df.elements.length; k < el; k++)

      {

       for(var i=0, al=arguments.length; i<al && ( !/submit|button|reset/i.test( df.elements[k].type )

       || !df.elements[k].value.contains(arguments[i]) ); i+=2)

       ;

    

       if( i != al )

       {

        var idx = this.objTable.length

        this.objTable[ idx ] = new this.build( this.mediaPath+arguments[ i+1 ] )

       

        df.elements[k].onmouseover=new Function("PlayMedia.objTable["+idx+

        "].tm=setTimeout('PlayMedia.sound("+idx+")', "+this.hoverDelay+")");

       

        df.elements[k].onmouseout=new Function("clearTimeout(PlayMedia.objTable["+idx+"].tm);PlayMedia.stop("+

        idx+");"); 

       }

      }

  }

 },



 toggle:function()

 {

  return this.canPlay^=true;

 }

}



/*** End ***/