jQuery Preview

jQuery Preview is a plugin by Embedly that allows
developers to create tools that enable users to share links with rich previews
attached. This method of letting users select thumbnails, edit title and
description has been adopted as the norm across the web. This plugin allows
developers to easily implement this functionality without building the entire
infrastructure themselves. Instead relying on on Embedly to generate the
metadata.

We have made this plugin overly verbose and infinitely customizable. Our goal
is not to dictate design, merely give a set of tools to make it easy to create
a custom experience.

Basic Setup

To get started you need to put jQuery,
Embedly jQuery,
jquery.preview.js
and preview.css. into
your page:

<head>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js" type="text/javascript"></script>
  <script src="http://cdn.embed.ly/jquery.embedly-3.0.5.min.js" type="text/javascript"></script>
  <script src="http://cdn.embed.ly/jquery.preview-0.3.2.min.js" type="text/javascript"></script>
  <link rel="stylesheet" href="http://cdn.embed.ly/jquery.preview-0.3.2.css" />
</head>

Next set up a simple form that allows a user to input link:

<form action="/update" method="POST">
    <input id="url" type="text" name="url"/>

    <!-- Placeholder that tells Preview where to put the selector-->
    <div class="selector-wrapper"></div>
</form>

You then need to tell preview what field to listen to:

<script>
    // Set up preview.
    $('#url').preview({key:'your_embedly_key'})

    // On submit add hidden inputs to the form.
    $('form').on('submit', function(){
      $(this).addInputs($('#url').data('preview'));
      return true;
    });
</script>

And you are done setting up the front end solution for jQuery Preview. The
rest of this document will go into how to customize Preview.

How it Works

The plugin works by listening to the field on paste, keyup, preview
and blur. If a URL is entered a call is made to Embedly’s Extract endpoint and the
result is then passed to the render function. render uses sprintf
to create a selector, so the user can pick a thumbnail associated with the
URL.

jQuery Preview just saves all the data and changes associated with the URL on
the input using jQuery’s data. It’s up to the developer to choose how they want
to deal with that data on submit. jQuery Preview comes with a helper function
addInputs so all the data can be added to the form. This is the code to
enable it:

// On submit add hidden inputs to the form.
$('form').on('submit', function(){
  $(this).addInputs($('#url').data('preview'));
  return true;
});

The developer can then choose how they wish to display the preview in the feed.
We will show some simple examples for handling this in the documentation.

Preview

Preview holds all the logic for calls to Embedly and rendering the selector.

Options

bind

By default preview will bind to keyup, blur and paste if you
wish to define your own bindings you can set this attribute to false:

// Don't bind the listeners
$('#url').preview({bind:false});

// When a use hits Attach, trigger a preview of the link.
$('a.attach').on('click', function(){$('#url').trigger('preview')});
error

Called when the url that the user inputed throws an error somewhere along
the way. Depending on the use case you may want notify the user or hide it
from them. The default behavior is to not notify the user. To notify them
you can use:

$('#url').preview({
  error: function(obj){
    alert('The URL you entered was not processed.');
  }});
success

Called after a URL has been successfully rendered by the selector. Useful
if you want to change state after the URL has been successfully processed.
For example if you want to change a button from ‘Share’ to ‘Submit’ you can
do it like so:

$('#url').preview({
  success : function(obj){
    $('button').text('Submit');
  }
});

render

If you would like to create your own selector, overwrite render with
your own function. We will go in more detail, in the writing your own
selector function, but here is the simplest example I could think of:

$('#url').preview({
  render: function(obj, options){
    // Put the title after the input.
    $(this).after(obj.title);
  }});

Events

preview

Manually trigger the input to fetch the URL. This is generally only needed
if bind is set to false:

$('a.attach').on('click', function(){$('#url').trigger('preview')});
loading

Triggered when the request is being made to the API endpoint:

$('#url').on('loading', function(){$('.loading').show()});
loaded

Triggered when a response has been returned from the API endpoint:

$('#url').on('loaded', function(){$('.loading').hide()});
close

Triggered when the selector should be closed. If you are implementing a
custom selector, you must listen for this event:

var render = function(data, options){
  // Insert selector
  $(this).on('close', function(){
    //Remove selector.
  });
}

Custom Selector

It’s actually recommended that you build a custom selector. While the default
one is pretty good, you are going to want to customize it more than just the
default styles. Here’s how you can create your own.

Render

To create our own selector you just need to pass in a function into the
render option when calling preview:

var render = function(data, options){
  // custom render
};
$('#url').preview({render:render});

The render function should accept a data argument that is the response from
the extract endpoint. options is also passed in if you would like to
set custom options in preview. this is the HTMLElement of the input. This
will let you listen for events or trigger events on the input.

The simplest version of a custom selector looks like so:

var render = function(data, options){
  // Add the title after the input.
  $(this).after('<span>'+data.title+'</span>');

  // remove the selector
  $(this).on('close', function(){
    $(this).siblings('span').remove();
  });
};

Display

jQuery Preview has no concept of displaying the item in a feed. This should be
handled by the developer. This is a simple example from one of the demos:

$('#preview_form').on('submit', function(){
  // Preview data.
  var preview = $('#id_url').data('preview');

  // Close the selector
  $('#id_url').trigger('close');
  $('#id_url').val('');

  // Create a post using mustache, i.e. the nice way.
  var template = ['<div class="row">',
    '<div class="large-3 columns">',
      '<img class="thumb" src="{{thumbnail_url}}"></img>',
    '</div>',
    '<div class="large-9 column">',
      '<a href="{{original_url}}">{{title}}</a>',
      '<p>{{description}}</p>',
    '</div>',
  '</div>'].join('');

  html = $(Mustache.to_html(template, preview));
  html.data('preview', preview);
  html.on('click', function(){
    var data = $(this).data('preview');
    // Insert the video or rich object.
    if (data.media.type === 'video' || data.media.type === 'rich'){
      $(this).html(data.media.html);
      return false;
    }
    return true;
  });
  // Display the item in the feed.
  $('#feed').append(html);
  return false;
});

Server Side

When the user submits the link, we must save it and echo it back to the page
so it can be displayed. The code contains a simple Tornado example of this dance in app.py.
When we set up the form we need to specify where we are going to be making the
the AJAX post. In this case it’s ‘/update’:

<form method="post" action="/update">
  <input type="text" class="xlarge" name="url" id="id_url" />
  <input id="id_submit" type="submit" class="btn btn-primary" value="Share"/>
</form>

We then build a handler to deal with the form data:

class UpdateHandler(tornado.web.RequestHandler):

    def post(self):
        #Overly verbose
        data = {}
        for name in ['type', 'original_url', 'url', 'title', 'description',
            'favicon_url', 'provider_url', 'provider_display', 'safe',
            'html', 'thumbnail_url', 'object_type', 'image_url']:
            data[name] = self.get_argument(name, None)

        # This also works
        # data = dict([(k, v[0]) for k, v in self.request.arguments.items()])

        # Save the data off and return the object that we will pass back.
        obj = db.save(data)

        # Write a json response
        self.write(json.dumps(obj))

Once the data is successfully posted the response is passed into the Display
object to be rendered and displayed.

CDN

To get you going even faster, Embedly hosts all the files you need on
scripts.embed.ly. The latest version is available here:

http://cdn.embed.ly/jquery.preview-0.3.2.min.js
http://cdn.embed.ly/jquery.preview-0.3.2.css

Changelog

0.3.2

  • Fixed a bug with media types in addInputs

0.3.1

  • Fixed a bug with sprintf and added secure images.

0.3

  • Full rewrite to simplify adding jQuery Preview to a site.

0.2

  • Added the $.preview so it can be used before the a form is initialized.
  • Added error and callback to the Preview object.

GitHub

View Github