Bookmarklets and you!

By Adam Heim / @truckingsim / @croscon

Real world examples

Real world examples

Real world examples

Building a draggable bookmarklet

(function(){
    window._project_name_url='http://example.dev';
    var s=document.createElement('script');
    s.setAttribute('src','http://example.dev/js/bookmarklet.js');
    s.setAttribute('type', 'text/javascript');
    document.getElementsByTagName('head')[0].appendChild(s);
})();
<a href="javascript: ..." onClick="return false">Drag Me!</a>

So now what?

  • Scrape
  • Manipulate
  • Delete random DOM nodes in 3 second intervals

Scraping the parent page for data

var ProjectBookmarkletObject = {
    appHost: window._project_name_url,
    metaTags: {},
    initialize: function(){
        this.loadMetaTags();
        this.generateIframe()
    }
    loadMetaTags: function(){
        var tags = document.getElementsByTagName('meta');
        for(var i = 0; i < tags.length; i++){
            var key = tags[i].name || tags[i].getAttribute('itemprop');
            var content = tags[i].getAttribute('content');
            if(key && content){
                this.metaTags[key] = content;
            }
        }
    }
};

Generate the iframe

var ProjectBookmarkletObject = {
    appHost: window._project_name_url,
    metaTags: {},
    initialize: function(){
        this.loadMetaTags();
        this.generateIframe();
    },
    generateIframe: function(){
        var container = document.createElement('div'), that = this;
        container.setAttribute('id', 'ProjectContainerUniqueId');

        var iframe = document.createElement('iframe');
        iframe.setAttribute('src', this.appHost);
        iframe.setAttribute('frameBorder', '0');
        iframe.setAttribute('id', 'project_iframe');
        iframe.setAttribute('allowTransparency', 'true');

        container.appendChild(iframe);
        document.body.appendChild(container);

        //On load we will actually send the data via window.postMessage
        iframe.onload = function(){ that.sendPostMessage(iframe); };
    }
}

How do I send data to the iframe?

Don't use GET variables use postMessage!

  • IE8 and IE9 can send strings only
  • IE8, IE9, and IE10 does not work cross-origin in new windows.

What is postMessage?


The window.postMessage method safely enables cross-origin communication. - http://mdn.io/postMessage

Pass data easily between a third party parent page and a iframe on a domain you control.

Using window.postMessage

var ProjectBookmarkletObject = {
  appHost: window._project_name_url,
  metaTags: {},
  initialize: function(){
    this.loadMetaTags();
    this.generateIframe();
  },
  sendPostMessage: function(iframe){
    var that = this;
    iframe.contentWindow.postMessage(
      JSON.stringify(this.metaTags),
      this.appHost
    );

    window.addEventListener('message', function(event){
      if(event.origin == that.appHost && event.data == 'some_trigger'){
        // Do some action
      }
    });
  }
}

http://mdn.io/postMessage

Listening in the iframe

var ProjectIframe = {};
window.addEventListener('message', function(event){
    ProjectIframe._preload.data = JSON.parse(event.data);
    ProjectIframe.data_loaded = true;
    $(function(){
        $(window).trigger('data:loaded');
        $('body').on('click', '.close_frame', function(){
            event.source.postMessage('close_frame', event.origin);
        });
    });
}, false);

Examples!

Basic Code

parent
var iframe = document.getElementById('basic-iframe');
$('#basic-send').click(function(){
    iframe.contentWindow.postMessage('food', location.origin);
});
iframe
window.addEventListener('message', function(event){
    if(event.data === 'food'){
        $('.text').addClass('bg-success').text("I'm fed!");
    }
});

The basics!

iframe
parent

Advanced Code

parent
var advanced_iframe = document.getElementById('advanced-iframe');
$('#advanced-send').click(function(){
    $('#advanced-send').addClass('hide');
    advanced_iframe.contentWindow.postMessage('food', location.origin);
});
$('#advanced-send-2').click(function(){
    $('#advanced-send-2').addClass('hide');
    advanced_iframe.contentWindow.postMessage('more-food', location.origin);
});

window.addEventListener('message', function(event){
    if(event.data === 'feed-me-more'){
        $('#advanced-send-2').removeClass('hide');
    }
    if(event.data === 'close-frame'){
        $('#advanced-iframe').remove();
    }
});

Advanced Code

iframe
window.addEventListener('message', function(event){
    if(event.data === 'food'){
        $('#first').addClass('hide');
        $('#second').removeClass('hide');
    }
    if(event.data === 'more-food'){
        $('#second').addClass('hide');
        $('#third').removeClass('hide');
    }
});

$('#give-me-more').click(function(){
    $('#second').html('Give me more!');
    window.parent.postMessage('feed-me-more', location.origin);
});
$('#close-frame').click(function(){
    window.parent.postMessage('close-frame', location.origin);
});
iframe
parent

That's It

Twitter: @truckingsim

Github: http://github.com/truckingsim

Slides: truckingsim/queens-js-2014-09-slides