Changeset 29888

Show
Ignore:
Timestamp:
17.05.2015 11:17:31 (4 years ago)
Author:
davidb
Message:

Working popup editor, saving to localStorage. Tidy up on space-bar for global pause and start play.

Location:
main/trunk/model-sites-dev/respooled/collect/popup-video-respooled
Files:
6 modified

Legend:

Unmodified
Added
Removed
  • main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/js/audiosynth.view.js

    r29885 r29888  
    221221            thisKey.appendChild(label); 
    222222            thisKey.setAttribute('ID', 'KEY_' + n + ',' + i); 
    223             thisKey.addEventListener(evtListener[0], (function(_temp) { return function() { fnPlayKeyboard({keyCode:_temp}); } })(reverseLookup[n + ',' + i])); 
     223            thisKey.addEventListener(evtListener[0], (function(_temp) { return function() {  
     224            console.log("**** bespoke evtListener for mousedown, away to call fnPlayKeyboard()"); 
     225            fnPlayKeyboard({keyCode:_temp}); } })(reverseLookup[n + ',' + i])); 
     226 
    224227            visualKeyboard[n + ',' + i] = thisKey; 
    225228            visualKeyboard.appendChild(thisKey); 
     
    282285 
    283286    var fnPlayKeyboard = function(e) { 
     287    console.log("***### fnPlayKeyboard() e=" + e); //JSON.stringify(e)); 
     288 
     289    // check to see if any modal dialogs are open 
     290    var active_modal_dialogs = $('.ui-widget-overlay:visible'); 
     291    if (active_modal_dialogs.length>0) { 
     292        return false; 
     293    } 
     294 
    284295 
    285296    if (e.ctrlKey) { 
     
    289300    } 
    290301 
    291     if (e.key == " ") { 
     302    console.log("**** testing keyboard event key: '" + e.key + "' keycode = " + e.keyCode); 
     303 
     304    if (e.keyCode == 32) { // <space-bar> 
    292305        togglePlayPause(); 
    293         e.preventDefault(); 
     306        //e.preventDefault(); 
    294307        return false; 
    295308    } 
     
    442455        while(i--) { 
    443456        keys.unshift(reverseLookup[arr[0][0][i]]); 
     457        console.log("**** In fnPlaySong(), away to call fnPlayKeyboard()"); 
    444458        fnPlayKeyboard({keyCode:keys[0]}); 
    445459        } 
  • main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/js/game-on.js

    r29886 r29888  
    11"use strict"; 
    22 
    3 var paper_x_dim = 920; 
    4 var paper_y_dim = 445; 
     3var goDocStorage = null; 
     4 
     5var goPaper = null; 
     6 
     7var go_paper_x_dim = 920; 
     8var go_paper_y_dim = 445; 
    59 
    610var gameOnCurrentTimeXPos = 0; 
    711var gameOnCurrentTimelineRect = null; 
    812 
     13var num_midi_pitches = 128; 
     14 
     15 
    916function updateGameOnCurrentTimeline() 
    1017{ 
    11     gameOnCurrentTimeXPos = (mediaPlayer.currentTime / mediaPlayer.duration) *  paper_x_dim; 
     18    gameOnCurrentTimeXPos = (mediaPlayer.currentTime / mediaPlayer.duration) *  go_paper_x_dim; 
    1219    //console.log("*** x pos = " + gameOnCurrentTimeXPos); 
    1320 
     
    1522} 
    1623 
    17 function initGameOn() 
    18 { 
    19     console.log("initGameOn()"); 
    20  
    21     var gmp_x_dim = $('#gameOnPaper').width(); 
    22     var gmp_y_dim = $('#gameOnPaper').height(); 
    23  
    24     console.log("*** gmp_x_dim = " + gmp_x_dim); 
    25     console.log("*** gmp_y_dim = " + gmp_y_dim); 
    26  
    27     var paper_x_dim = 920; 
    28     var paper_y_dim = 445; 
    29  
    30     var num_midi_pitches = 128; 
    31  
    32     //var paper = Raphael("gameOnPaper",gmp_x_dim,gmp_y_dim); 
    33     var paper = Raphael("gameOnPaper",paper_x_dim,paper_y_dim); 
    34     paper.canvas.style.backgroundColor = '#FFFFFF'; 
    35  
    36     console.log("*** hasLocalStorage = " + hasLocalStorage); 
    37  
    38     if (hasLocalStorage) { 
    39     var docOID = gs.cgiParams.d; 
     24function getDocStorage(docOID) 
     25{ 
     26    var docStorage = null; 
     27 
     28    if (hasLocalStorage) { 
     29 
     30    if (goDocStorage == null) { 
     31        var docStorageStr = localStorage.getItem(docOID); 
     32        //console.log("***docStorageStr = " + docStorageStr); 
    4033     
    41     var docStorageStr = localStorage.getItem(docOID); 
    42  
    43     var docStorage = (docStorageStr != null) ? eval("("+docStorageStr+")") : {palTracks:{}, popTracks:{}}; 
     34        //var docStorage = (docStorageStr != null) ? eval("("+docStorageStr+")") : {palTracks:{}, popTracks:{}}; 
     35        docStorage = eval("("+docStorageStr+")") || {palTracks:{}, popTracks:{}}; 
     36        goDocStorage = docStorage; 
     37    } 
     38    else { 
     39        docStorage = goDocStorage; 
     40    } 
     41    } 
     42 
     43    return docStorage; 
     44} 
     45 
     46function getActiveTrackLayers(opt_field) 
     47{ 
     48    var field = opt_field || "name"; 
     49 
     50    var palActiveLayers = []; 
     51    $('#palForm input:checked').each(function() { 
     52        palActiveLayers.push(this[field]); 
     53    }); 
     54 
     55    return palActiveLayers; 
     56} 
     57 
     58function populatePalList(docStorage) 
     59{ 
     60    // populate pal List 
     61    if (hasLocalStorage) { 
    4462 
    4563    var palTracks = docStorage.palTracks || {}; 
    4664 
    47     // 'palTracks' for the form: 
     65    //console.log("*** palTracks = " + JSON.stringify(palTracks)); 
     66    var palListKeys = Object.keys(palTracks).sort(); 
     67 
     68    for (var i=0; i<palListKeys.length; i++) { 
     69        var key = palListKeys[i]; 
     70        var track = palTracks[key]; 
     71        var name = key; 
     72        var cb_name = name.replace(/[ -]/g,""); 
     73        var cb_value = name; 
     74 
     75        var opt_checked = (i==0) ? ' checked="checked"' : ""; 
     76 
     77        $('#palList').append('<div id="pal'+cb_name+'"><input type="checkbox" ' 
     78                 + '" name="'+cb_name+'" value="' + cb_value + '"' 
     79                 + opt_checked + '>'  
     80                 + name + '</div>'); 
     81    } 
     82    } 
     83    else { 
     84    // Put in some fake data for now 
     85    $('#palList').append('<input type="checkbox" id="palPianoHero"    name="PianoHero" value="Piano Hero" checked="checked"/>Piano Hero<br />'); 
     86    $('#palList').append('<input type="checkbox" id="palDrumbeatHero" name="DrumbeatHero"  value="Drum-beat Hero" />Drum-beat Hero<br />'); 
     87    } 
     88} 
     89 
     90function displayActiveTrackLayers(docStorage) 
     91{ 
     92    console.log("displayActiveTrackLayers()"); 
     93 
     94    goPaper.clear(); 
     95 
     96    if (hasLocalStorage) { 
     97 
     98    // 'palTracks' have the form: 
    4899    //    palTracks[save_name] = [ { name: "my recording 1", baseCTime: 123.3, events: [ .... ] } ] 
    49100 
    50     var my_recording = palTracks['My Recording']; 
    51  
    52     if (my_recording != null) { 
    53         var total_duration = mediaPlayer.duration; 
    54         console.log("*** total duration = " + total_duration); 
    55  
    56         var min_midi_pitch = num_midi_pitches-1; 
    57         var max_midi_pitch = 0; 
    58  
    59         // calculate range of midi pitches present 
    60         for (var b=0; b<my_recording.length; b++) { 
    61         var track_block = my_recording[b]; 
    62         var base_ctime = track_block.baseCTime; 
    63         var block_events = track_block.events; 
    64  
    65         for (var ne=0; ne<block_events.length; ne++) { 
    66             var midi_pitch = block_events[ne].midiPitch; 
    67             if (midi_pitch < min_midi_pitch) { 
    68             min_midi_pitch = midi_pitch; 
    69             } 
    70             if (midi_pitch > max_midi_pitch) { 
    71             max_midi_pitch = midi_pitch; 
     101    var palTracks = docStorage.palTracks || {}; 
     102 
     103    var total_duration = mediaPlayer.duration; 
     104    //console.log("*** total duration = " + total_duration); 
     105 
     106    var atl = getActiveTrackLayers("value"); 
     107    //console.log("*** atl = " + JSON.stringify(atl)); 
     108 
     109    var min_midi_pitch = num_midi_pitches-1; 
     110    var max_midi_pitch = 0; 
     111 
     112    for (var i=0; i<atl.length; i++) { 
     113        var storage_name = atl[i]; 
     114        var track = palTracks[storage_name]; 
     115 
     116        if (track != null) { 
     117 
     118        // calculate range of midi pitches present 
     119        for (var b=0; b<track.length; b++) { 
     120            var track_block = track[b]; 
     121            var base_ctime = track_block.baseCTime; 
     122            var block_events = track_block.events; 
     123 
     124            for (var ne=0; ne<block_events.length; ne++) { 
     125            var midi_pitch = block_events[ne].midiPitch; 
     126            if (midi_pitch < min_midi_pitch) { 
     127                min_midi_pitch = midi_pitch; 
     128            } 
     129            if (midi_pitch > max_midi_pitch) { 
     130                max_midi_pitch = midi_pitch; 
     131            } 
    72132            } 
    73133        } 
    74134        } 
    75         console.log("*** max pitch = " + max_midi_pitch + ", min pitch = " + min_midi_pitch); 
    76  
    77         var raw_midi_range = max_midi_pitch - min_midi_pitch; 
    78         var midi_range = Math.max(4,raw_midi_range);  
    79  
    80         var midi_y_dim_spacing = paper_y_dim / midi_range; 
    81  
    82         for (var b=0; b<my_recording.length; b++) { 
    83  
    84         var track_block = my_recording[b]; 
    85         var base_ctime = track_block.baseCTime; 
    86  
    87         var block_events = track_block.events; 
    88  
    89         for (var ne=0; ne<block_events.length; ne++) { 
    90  
    91             var note_event = block_events[ne]; 
     135    } 
     136    //console.log("*** max pitch = " + max_midi_pitch + ", min pitch = " + min_midi_pitch); 
     137     
     138    var raw_midi_range = max_midi_pitch - min_midi_pitch; 
     139    var midi_range = Math.max(4,raw_midi_range);  
     140     
     141    var midi_y_dim_spacing = go_paper_y_dim / midi_range; 
     142 
     143    for (var i=0; i<atl.length; i++) { 
     144        var storage_name = atl[i]; 
     145        var track = palTracks[storage_name]; 
     146 
     147        if (track != null) { 
     148 
     149        for (var b=0; b<track.length; b++) { 
     150 
     151            var track_block = track[b]; 
     152            var base_ctime = track_block.baseCTime; 
    92153             
    93             var startPercTime = (base_ctime + note_event.startCurrentTime)/total_duration; 
    94             var rx_org = startPercTime * paper_x_dim; 
    95             var ry_org = paper_y_dim - ((note_event.midiPitch - min_midi_pitch) * midi_y_dim_spacing); 
     154            var block_events = track_block.events; 
    96155             
    97             var rx_dim = (note_event.duration/1000)/total_duration * paper_x_dim; 
    98             var ry_dim = midi_y_dim_spacing; 
    99              
    100             var rect = paper.rect(rx_org,ry_org,rx_dim,ry_dim); 
    101             rect.attr({stroke:"black",fill:"#2E52A4"}); 
     156            for (var ne=0; ne<block_events.length; ne++) { 
     157             
     158            var note_event = block_events[ne]; 
     159             
     160            var startPercTime = (base_ctime + note_event.startCurrentTime)/total_duration; 
     161            var rx_org = startPercTime * go_paper_x_dim; 
     162            var ry_org = go_paper_y_dim - ((note_event.midiPitch - min_midi_pitch) * midi_y_dim_spacing); 
     163             
     164            var rx_dim = (note_event.duration/1000)/total_duration * go_paper_x_dim; 
     165            var ry_dim = midi_y_dim_spacing; 
     166             
     167            var rect = goPaper.rect(rx_org,ry_org,rx_dim,ry_dim); 
     168            rect.attr({stroke:"black",fill:"#2E52A4"}); 
     169            } 
    102170        } 
    103171        } 
     
    105173    } 
    106174 
    107     gameOnCurrentTimelineRect = paper.rect(-2,0,1,paper_y_dim); 
    108     console.log("*** gameOnCurrentTimelineRect = " + gameOnCurrentTimelineRect); 
    109      
     175    gameOnCurrentTimelineRect = goPaper.rect(-2,0,1,go_paper_y_dim); 
    110176    gameOnCurrentTimelineRect.attr({fill: "red", stroke: "red"}); 
    111      
    112 } 
    113  
    114 function pamDelete() 
    115 { 
    116     //var pamActiveLayers = $('input[type=checkbox]:checked', '#pamForm'); 
    117  
    118     var pamActiveLayers = []; 
    119     $('#pamForm input:checked').each(function() { 
    120         pamActiveLayers.push({name: this.name, value: this.value}); 
    121     }); 
    122  
    123     return false; 
    124 } 
     177} 
     178 
     179function initGameOn() 
     180{ 
     181    console.log("initGameOn()"); 
     182 
     183    goDocStorage = getDocStorage(gs.cgiParams.d); 
     184 
     185    //var gmp_x_dim = $('#gameOnPaper').width(); 
     186    //var gmp_y_dim = $('#gameOnPaper').height(); 
     187 
     188    //console.log("*** gmp_x_dim = " + gmp_x_dim); 
     189    //console.log("*** gmp_y_dim = " + gmp_y_dim); 
     190 
     191 
     192    //var goPaper = Raphael("gameOnPaper",gmp_x_dim,gmp_y_dim); 
     193    goPaper = Raphael("gameOnPaper",go_paper_x_dim,go_paper_y_dim); 
     194    goPaper.canvas.style.backgroundColor = '#FFFFFF'; 
     195 
     196    console.log("Browser supports LocalStorage: " + hasLocalStorage); 
     197 
     198    populatePalList(goDocStorage); 
     199    displayActiveTrackLayers(goDocStorage); 
     200} 
     201 
     202 
     203function palDeleteConfirmed() 
     204{ 
     205    //var palActiveLayers = $('input[type=checkbox]:checked', '#palForm'); 
     206 
     207    var palActiveLayersID   = getActiveTrackLayers("name"); 
     208    var palActiveLayersValue = getActiveTrackLayers("value"); 
     209 
     210    var palTracks = goDocStorage.palTracks || {}; 
     211 
     212    for (var i=0; i<palActiveLayersID.length; i++) { 
     213    var id = palActiveLayersID[i]; 
     214    $('#pal'+id).remove(); 
     215 
     216    var value = palActiveLayersValue[i]; 
     217    delete palTracks[value];  
     218    } 
     219} 
     220 
     221 
     222function palDelete() 
     223{ 
     224    $('#delete-recording-popup').dialog('open'); 
     225 
     226    return false;  // no need to process the event any further 
     227} 
     228 
     229function palDisplay() 
     230{ 
     231    displayActiveTrackLayers(goDocStorage); 
     232 
     233    return false;  // no need to process the event any further 
     234} 
     235 
     236function palSave() 
     237{ 
     238    var palTracks = goDocStorage.palTracks || {}; 
     239 
     240    var json_edit_str = trackEditor.getSession().getValue(); 
     241    console.log("**** json edit str = " + json_edit_str); 
     242 
     243    var json_edit = eval("("+json_edit_str+")"); 
     244 
     245    for (var key in json_edit){ 
     246    if (json_edit.hasOwnProperty(key)) { 
     247        //console.log("*** key = " + key); 
     248        var val = json_edit[key]; 
     249        console.log("**** Saving under key[ " + key + "]: " + JSON.stringify(val)); 
     250        palTracks[key] = val;        
     251    } 
     252    } 
     253 
     254    if (hasLocalStorage) { 
     255    var docOID = gs.cgiParams.d; 
     256    console.log("Saving in Browser localStorage track data for '" + docOID + "'"); 
     257    localStorage.setItem(docOID,JSON.stringify(goDocStorage)); 
     258    } 
     259} 
     260 
     261function palEdit() 
     262{ 
     263    var palTracks = goDocStorage.palTracks || {}; 
     264 
     265    var palActiveLayers = getActiveTrackLayers("value"); 
     266 
     267    var edit_json = {}; 
     268 
     269    for (var i=0; i<palActiveLayers.length; i++) { 
     270    var track_name = palActiveLayers[i]; 
     271    edit_json[track_name] = palTracks[track_name]; 
     272    } 
     273 
     274    trackEditor.setValue(JSON.stringify(edit_json,null,'\t')); 
     275    trackEditor.clearSelection(); 
     276 
     277    $('#edit-recording-popup').dialog('open'); 
     278 
     279    return false;  // no need to process the event any further 
     280} 
     281 
  • main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/js/in-the-groove.js

    r29885 r29888  
    55var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); 
    66 
    7 if( 'webkitAudioContext' in window) { 
    8     console.log("*** Web Audio found in webkit namespace"); 
    9     audioCtx = new webkitAudioContext(); 
    10 } 
     7//if( 'webkitAudioContext' in window) { 
     8//    console.log("*** Web Audio found in webkit namespace"); 
     9//    audioCtx = new webkitAudioContext(); 
     10//} 
    1111 
    1212var InTheGroove = false; 
     
    1515//var bufferSize = 4096; 
    1616var bufferSize = 512; 
    17  
    18  
    19 //window.addEventListener('load', onLoad, false); 
    20  
    2117 
    2218var prev_input = [0,0]; 
     
    3228    // Feed the HTMLMediaElement into it 
    3329    var source = audioCtx.createMediaElementSource(this); 
    34     console.log("**** video source = " + source); 
     30    //console.log("**** video source = " + source); 
    3531 
    3632    // connect the AudioBufferSourceNode to the tinnyEffectNode 
  • main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/js/media-player.js

    r29885 r29888  
    2828 
    2929var hasLocalStorage = (typeof(Storage) !== "undefined"); 
     30var trackEditor = null; 
    3031 
    3132function initialiseMediaPlayer() { 
     
    8687 
    8788function togglePlayPause() { 
     89    //e = e || window.event; 
    8890    // If the mediaPlayer is currently paused or has ended 
    8991    console.log("togglePlayPause()"); 
     92 
     93    //console.log("**** event e = " + e); 
     94 
    9095    //console.log("*** mediaPlayer (paused,ended): (" + mediaPlayer.paused + "," + mediaPlayer.ended + ")"); 
    9196    //console.log("*** currentTime = " + mediaPlayer.currentTime); 
     
    129134        console.log("*** mediaPlayedNotes = " + JSON.stringify(mediaPlayedNotes)); 
    130135    } 
     136 
     137    // Loose keyboard focus so space-bar for global pause doesn't cause a focused play-button event 
     138    $('#play-pause-button').blur(); 
     139 
     140 
    131141} 
    132142 
     
    312322        var docOID = gs.cgiParams.d; 
    313323 
    314         var docStorageStr = localStorage.getItem(docOID); 
    315         var docStorage = (docStorageStr != null) ? eval("("+docStorageStr+")") : {palTracks:{}, popTracks:{}}; 
     324 
     325        // Force reset of what has been stored for this item 
     326        //localStorage.setItem(docOID, JSON.stringify(null)); 
     327 
     328        var docStorage = getDocStorage(docOID); 
     329 
     330        //var docStorageStr = localStorage.getItem(docOID); 
     331        //console.log("*** retrived docStorageStr: " + JSON.stringify(docStorage)); 
     332 
     333        //// var docStorage = (docStorageStr != null) ? eval("("+docStorageStr+")") : {palTracks:{}, popTracks:{}}; 
     334        //var docStorage = eval("("+docStorageStr+")") || {palTracks:{}, popTracks:{}}; 
     335        //console.log("*** set up docStorage: " + JSON.stringify(docStorage)); 
    316336 
    317337        var palTracks = docStorage.palTracks; 
     
    343363    } 
    344364 
     365    var cb_name = save_name.replace(/[ -]/g,""); 
     366    var cb_value = save_name; 
     367    var name     = save_name; 
     368 
     369    $('#palList').append('<div id="pal'+cb_name+'"><input type="checkbox" ' 
     370                 + '" name="'+cb_name+'" value="' + cb_value + '"' 
     371                 + ' checked="checked">'  
     372                 + name + '</div>'); 
    345373 
    346374    var $dialog = $('#save-recording-popup'); 
     
    363391    show: { 
    364392            effect: "blind", 
    365             duration: 1000 
     393            duration: 800 
    366394    }, 
    367395    hide: { 
    368396            effect: "blind", 
    369             duration: 500 
     397            duration: 300 
    370398    }, 
    371399 
     
    387415  
    388416 
     417    var delete_dialog = $('#delete-recording-popup').dialog({ 
     418    resizable: false, 
     419    autoOpen: false,  
     420    width: 500, 
     421    height:200, 
     422    modal: true, 
     423 
     424    show: { 
     425            effect: "blind", 
     426            duration: 800 
     427    }, 
     428    hide: { 
     429            effect: "blind", 
     430            duration: 300 
     431    }, 
     432 
     433    buttons: { 
     434            "Delete selected items": function() { 
     435        // call delete 
     436        palDeleteConfirmed(); 
     437        $( this ).dialog( "close" ); 
     438            }, 
     439            Cancel: function() { 
     440        $( this ).dialog( "close" ); 
     441            } 
     442    } 
     443    }); 
     444 
     445 
     446    var edit_dialog = $('#edit-recording-popup').dialog({ 
     447    resizable: true, 
     448    autoOpen: false,  
     449    width: 800, 
     450    height:600, 
     451    modal: true, 
     452 
     453    show: { 
     454            effect: "blind", 
     455            duration: 800 
     456    }, 
     457    hide: { 
     458            effect: "blind", 
     459            duration: 300 
     460    }, 
     461 
     462    buttons: { 
     463            "Save": function() { 
     464        // call delete 
     465        palSave(); 
     466        $( this ).dialog( "close" ); 
     467            }, 
     468            Cancel: function() { 
     469        $( this ).dialog( "close" ); 
     470            } 
     471    } 
     472    }); 
     473 
     474    trackEditor = ace.edit("trackEditor"); 
     475    trackEditor.getSession().setMode("ace/mode/json"); 
     476    trackEditor.getSession().setUseSoftTabs(false); 
     477    var UndoManager = require("ace/undomanager").UndoManager; 
     478    trackEditor.getSession().setUndoManager(new UndoManager()); 
     479 
     480 
    389481}); 
    390482 
  • main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/style/media-player.css

    r29877 r29888  
    108108    height: 100%; 
    109109    width: 100%; 
    110     opacity: 0.2; 
    111     filter: Alpha(Opacity=20); 
    112     background-color: black; 
     110    opacity: 0.4; 
     111    filter: Alpha(Opacity=40); 
     112    /*background-color: black; */ 
     113    /*background: #AAA url("images/ui-bg_flat_0_aaaaaa_40x100.png") repeat scroll 50%  */ 
     114 
     115    background-color: #AAA; 
     116    background-repeat: repeat; 
     117    background-attachment: scroll; 
     118    background-position: 50%; 
    113119} 
  • main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/transform/pages/document.xsl

    r29885 r29888  
    13991399     </div> 
    14001400 
     1401         <div id="delete-recording-popup" title="Delete Tracks"> 
     1402       <p>Are you sure you want to delete the selected tracks?</p> 
     1403     </div> 
     1404 
     1405 
     1406         <div id="edit-recording-popup" title="Edit Tracks"> 
     1407       <style> 
     1408         #trackEditor { 
     1409           position: absolute; 
     1410           top: 0; right: 0; bottom: 0; left: 0; 
     1411         } 
     1412       </style> 
     1413       <div id="trackEditor"><xsl:comment>Track Editor Area</xsl:comment></div> 
     1414     </div> 
     1415 
     1416 
     1417 
    14011418          <div style="color: white;"> 
    14021419 
     
    14831500 
    14841501 
    1485         <form id="pamForm" style="width: 99%; margin-top: 10px; margin-bottom: 10px; "> 
     1502        <form id="palForm" style="width: 99%; margin-top: 10px; margin-bottom: 10px; "> 
    14861503          <fieldset> 
    1487         <legend id="pam-legend">Play Along Layers: Game On!</legend> 
    1488         <input type="checkbox" name="PianoHero" value="PianoHero" />Piano Hero<br /> 
    1489         <input type="checkbox" name="DrumHero"  value="DrumHero" />Drum-beat Hero<br /> 
     1504        <legend id="pal-legend">Play Along Layers: Game On!</legend> 
     1505        <div id="palList"><xsl:comment>play along list</xsl:comment></div> 
    14901506         
    14911507        <div style="padding: 8px;"> 
    1492           <button id="pam-display-overlay" style="background-color:#2E52A4; color:#CCC; width:19%; text-align: center; margin-right: 8px;"> 
     1508          <button id="pal-display-overlay"  
     1509              style="background-color:#2E52A4; color:#CCC; width:19%; text-align: center; margin-right: 2px;" 
     1510              onclick="return palDisplay()"> 
    14931511            Display Selected 
    14941512          </button> 
    1495           <button id="pam-merge-overlay"   style="background-color:#2E52A4; color:#CCC; width:19%; text-align: center; margin-right: 8px;"> 
     1513          <button id="pal-merge-overlay"    
     1514              style="background-color:#2E52A4; color:#CCC; width:19%; text-align: center; margin-right: 2px;"> 
    14961515            Merge Selected 
    14971516          </button> 
    1498           <button id="pam-split-overlay"   style="background-color:#2E52A4; color:#CCC; width:19%; text-align: center; margin-right: 8px;"> 
     1517          <button id="pal-split-overlay"    
     1518              style="background-color:#2E52A4; color:#CCC; width:19%; text-align: center; margin-right: 2px;"> 
    14991519            Split Selected 
    15001520          </button> 
    1501           <button id="pam-edit-overlay"    style="background-color:#2E52A4; color:#CCC; width:19%; text-align: center; margin-right: 8px;"> 
     1521          <button id="pal-edit-overlay"     
     1522              style="background-color:#2E52A4; color:#CCC; width:19%; text-align: center; margin-right: 2px;" 
     1523              onclick="return palEdit()"> 
    15021524          Edit Selected 
    15031525          </button> 
    1504           <button id="pam-delete-overlay"   
     1526          <button id="pal-delete-overlay"   
    15051527              style="background-color:#2E52A4; color:#CCC; width:19%; text-align: center;" 
    1506               onclick="return pamDelete()"> 
     1528              onclick="return palDelete()"> 
    15071529          Delete Selected 
    15081530          </button>