Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Call javascript from Harlowe

I have this function I want to call during a passage:
window.GoGoGadgetMusic = function(youtube){
window.console.log('hi mom');
$('body').append('<iframe src="' + youtube + '?autoplay=1&amp;loop=1&amp;playlist=' + youtube + '" style="display:none"></iframe>');
(It adds a youtube soundtrack to the page - I'm hoping it will survive page refreshes attached to the body tag.)

Evidently script tags get sanitised so that's out. I've seen someone write a "hook-sniffer" script that executes code when a certain hook is dropped into a passage.

Should I be using something like that? Or is there an easier way?


  • Ha haaa!!

    The guys on my old forum were all web developers and would troll each other by sneaking javascript on to the page - because the sanitiser was only looking for <script> tags. It didn't count on this little trick:

    <div style="display: none;"><img src="!@#$"; onerror="GoGoGadgetMusic('l-dYNttdgl0');" /></div>

    So there you go. Just make sure you bind stuff to window to make it global (careful now) and then use a failed img load to fire it from the passage. And I can confirm that by binding to the body tag the music attachment doesn't get scrubbed when you change passage. (My function still needs to deal with the passage being revisited, but that should be easy to code.)

    I'll admit I had a total Kermit the Frog fit when this worked. I've been really wanting to play a piece of music in the last act.
  • I strongly suggest that you use your own Namespace if you are planing on adding global javascript functions or variables to a story, this way you won't "accidentally" break code that is not your own.

    The following is an example on how to do this, though you should replace the namespace Bob with your own unique name as well as the doit function with your own.

    // Bob namespace.
    if (typeof Bob == "undefined") {
    var Bob = {
    doit: function() {
    console.log('doit got called');

    window.Bob = Bob;
    Extending st33d's image example, you call your function as follows:

    <div style="display: none;"><img src="!@#$" onerror="Bob.doit();" /></div>
  • Will do.

    The script above is a bit broken from where a friend showed me how to do the jQuery but mangled the html. Below is a working youtube music hack I've tested.

    Put the following code in the Javascript window in the editor:
    if(typeof YouTubeTunes == "undefined"){
    $('body').append('<div id="youtubetunes"></div>');
    var YouTubeTunes = {
    play: function(id){
    console.log('YouTubeTunes:' + id);
    if(this.current != id){
    this.current = id;
    var container = $('#youtubetunes');
    container.append('<iframe src="' + id + '?autoplay=1&amp;amp;loop=1&amp;amp;playlist='+ id + '" style="visibility: hidden; width: 500px; height: 500px; position: absolute; top: -1000px; left: -1000px;"></iframe>');
    } else {
    console.log('already playing');
    stop: function(){
    this.current = "";
    console.log('stopped youtubetunes');
    window.YouTubeTunes = YouTubeTunes;
    Add the following to play a music track from a YouTube video id in a passage.
    <div style="display: none;"><img src="!@#$" onerror="'l-dYNttdgl0');" /></div>
    The music will keep playing till you request a new track or stop it:
    <div style="display: none;"><img src="!@#$" onerror="YouTubeTunes.stop();" /></div>
Sign In or Register to comment.