/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.

Primary LanguageJavaScriptBSD 3-Clause "New" or "Revised" LicenseBSD-3-Clause

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. There are 5 different demos that you should take a look at before getting started. It will give you a quick overview of what you should be able to build.

Note: The Preview endpoint is available on our Paid plans, http://embed.ly/pricing.

Basic Setup

To get started you need to put jQuery, jquery.preview.full.js and preview.css. into the head of 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://scripts.embed.ly/p/0.2/jquery.preview.full.min.js" type="text/javascript"></script>
  <link rel="stylesheet" href="http://scripts.embed.ly/p/0.2/css/preview.css" />
</head>

jquery.preview.full.js bundles Underscore.js and Mustache.js in with jquery.preview.js. If you already have or use these two libs you can see up the head of the document like so:

<head>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js" type="text/javascript"></script>
  <script src="lib/mustache.js" type="text/javascript"></script>
  <script src="lib/underscore.js" type="text/javascript"></script>
  <script src="http://scripts.embed.ly/p/0.2/jquery.preview.min.js" type="text/javascript"></script>
  <link rel="stylesheet" href="http://scripts.embed.ly/p/0.2/css/preview.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"/>
</form>

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

<script>
    $('#url').preview({key:'your_embedly_key'})
</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.

Note that the Preview endpoint is only available to Embedly developers with a Starter plan or above. You can sign up for a Starter plan at embed.ly/pricing.

How it Works

The plugin works by listening to the field on paste, keyup, attach and blur. If a URL is entered a call is made to Embedly's Preview endpoint and the result is then passed to the Selector object and all the elements are added to the form as hidden inputs. The Selector is then rendered using a Mustache template. The user can use the selector to pick a thumbnail associated with the URL.

When the form is submitted each attribute it passed back to the action URL. The server then saves the information and either echos or augments the object and passes it back to the fronted. The Display object then renders the obj into the feed.

Each object is infinitely customizable, but the flow is the same. We will go over each object and how to customize them.

Objects

There are 3 basic objects that you should get familiar with in order to customize the selector.

Preview

Preview holds all the logic for calls to Embedly. You shouldn't have to do a ton of customizations here.

Functions

submit

Called when the form is submitted and all the attributes are passed in as an object. If you want to do something other than a POST to the action you can overwrite the method like so:

var preview = {
  // Instead of posting to the server, send the object to display for
  // rendering to the feed.
  submit : function(e, data){
    e.preventDefault();
    this.display.create(data);
  }
}
$('#url').preview({preview:preview});
bind

Called when the preview is set up to bind all the listeners to the file and the form. If you want to listen on custom events you can call it like so:

var preview = {
  bind : function(){
    // Instead of listening to the field, wait for the user to click
    // 'Attach Link'.
    $('a.attach').bind('click', this.fetch);

    // Still bind the form to ``_submit`` that cleans up the data
    // before calling ``submit``
    $(this.form).bind('submit', this._submit);
  }
}
$('#url').preview({preview: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:

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

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 'Attach' you can do it like so:

var preview = {
  callback : function(){
    $('button').text('Attach');
  }
}
$('#url').preview({preview:preview});

Using Attach

If you missed it jQuery Preview listens to a special event attach on the field. If you wish to have a two step process of attaching the link to the status and then sharing the link you can set something up like this:

<form id="preview_form" class="form-vertical" method="post" action=".">
    <input type="text" name="url" id="id_url" value="http://vimeo.com/18150336" />
    <button id="id_attach">Attach</button>
</form>
<script>
$('#id_attach').bind('click', function(e){
    e.preventDefault();
    $('#id_url').trigger('attach');

    $('#id_attach').replaceWith($('<input/>').attr({
      'id' : 'id_submit',
      'value' : 'Share',
      'type' : 'submit'
    }));
});
</script>

This triggers the attach event on the field and that tells Preview to go fetch the url and show it in the Selector.

Selector

Builds the selector that allows users to pick out a thumbnail.

Attributes

type

There are 3 different built-in types that a developer can choose from

Each allows for a different type of feel. We suggest using one of them to get started and customizing from there.

template

If you would like to use your own Mustache template to render the selector you can add it here. The default looks like:

<div id="selector" class="small">
  <div class="thumbnail">
    <div class="controls">
      <a class="left" href="#">&#9664;</a>
      <a class="right" href="#">&#9654;</a>
      <a class="nothumb" href="#">&#10005;</a>
    </div>
    <div class="items">
      <ul class="images">
        {{#images}}
        <li><img src="{{url}}"/></li>
        {{/images}}
      </ul>
    </div>
  </div>
  <div class="attributes">
    <a class="title" href="#">{{title}}</a>
    <p><a class="description" href="#">{{description}}</a></p>
    <span class="meta">
      <img class="favicon" src="{{favicon_url}}">
      <a class="provider" href="{{provider_url}}">{{provider_display}}</a>
    </span>
  </div>
  <div class="action"><a href="#" class="close">&#10005;</a></div>
</div>

By default Preview passes the following attributes to the template

  • type
  • original_url
  • url
  • title
  • description
  • favicon_url
  • provider_url
  • provider_display
  • safe
  • html
  • thumbnail_url
  • object_type
  • image_url

All these responses are defined here except for the following:

object_type
The oEmbed of the preview response. Will be either video, rich, photo or link. We use this to decide weather to embed the html attribute.
image_url
If the type is image or the object_type is photo an image_url will be the full sized image URL.
thumbnail_url
The URL that the user selected as the thumbnail for the embed.

template can also be a dictionary if you want to use different templates for different ``object_type``s. For instance:

template : {
  'video' : 'Video Template',
  'rich' : 'Rich Template',
  'photo' : 'Photo Template',
  'link' : 'Link Template'
}

Functions

title

Allows users to click on the title in the selector and edit the text. It is set up like this in the bind function:

$('.selector .title').bind('click', this.title);
description

Allows users to click on the description in the selector and edit the text. It is set up like this in the bind function:

$('.selector .description').bind('click', this.description);
scroll

Simple logic that scrolls the image left and right in selector. It takes a direction (left or right) and an event. We set it up like so:

$('.selector .left').bind('click', _.bind(this.scroll, {}, 'left'));
$('.selector .right').bind('click', _.bind(this.scroll, {}, 'right'));
nothumb

Logic that tells the form NOT to use a thumbnail when rendering a preview. bind calls it like so:

$('.selector .nothumb').bind('click', this.nothumb);
clear
Clears the selector, hides it and all the hidden inputs.
update

Update can be set to an input field to also update the value in the selector. This is useful if you want to have a different input field for title and selector. We use this from the Preview object like so:

$('#id_title').bind('keyup', function(e){
  $.preview.selector.update(e);
});

The element must have a name attribute of the title or description.

bind
Sets the listeners for the above functions. Don't overwrite this function unless you know what you are doing.
render
Uses Mustache to render the template chosen by the developer. Don't overwrite this function unless you know what you are doing.

Display

Create's a Feed item for a given object.

Attributes

type

There are 3 different built-in types that a developer can choose from

Each allows for a different type of feel. We suggest using one of them to get started and customizing from there. The status type is the same as small, but takes an additional field status and displays that in the item as well.

template

The Mustache template that you would like to use to render the obj. The default one looks like this:

<div class="item">
  <div class="thumbnail">
    <a href="{{original_url}}">
      <img title="{{title}}" src="{{thumbnail_url}}"/>
      <span class="overlay"></span>
    </a>
  </div>
  <div class="attributes">
    <a class="title" href="{{original_url}}">{{title}}</a>
    <p class="description">{{description}}</p>
    <span class="meta">
      <img class="favicon" src="{{favicon_url}}"/>
      <a class="provider" href="{{provider_url}}">{{provider_display}}</a>
    </span>
  </div>
</div>

By default Preview passes the following attributes to the template

  • type
  • original_url
  • url
  • title
  • description
  • favicon_url
  • provider_url
  • provider_display
  • safe
  • html
  • thumbnail_url
  • object_type
  • image_url

All these responses are defined here except for the following:

object_type
The oEmbed of the preview response. Will be either video, rich, photo or link. We use this to decide weather to embed the html attribute.
image_url
If the type is image or the object_type is photo an image_url will be the full sized image URL.
thumbnail_url
The URL that the user selected as the thumbnail for the embed.

template can also be a dictionary if you want to use different templates for different ``object_type``s. For instance:

template : {
  'video' : 'Video Template',
  'rich' : 'Rich Template',
  'photo' : 'Photo Template',
  'link' : 'Link Template'
}
selector
Tells create where to prepend the Feed item html to. The default value is #feed.

Functions

create
Uses Mustache to render the template chosen by the developer. Don't overwrite this function unless you know what you are doing.

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://scripts.embed.ly/p/0.2/jquery.preview.min.js
http://scripts.embed.ly/p/0.2/jquery.preview.full.min.js
http://scripts.embed.ly/p/0.2/css/preview.css

The most current version of jQuery Preview will be available here:

http://scripts.embed.ly/p/jquery.preview.min.js
http://scripts.embed.ly/p/jquery.preview.full.min.js
http://scripts.embed.ly/p/css/preview.css

Development

The code is broken down into modules in the src folder and built by watch.py. If you want to modify anything in preview.jquery.js please find the code in the module and run python watch.py to build preview.jquery.js. preview.css is a sass generated file. Please modify preview.scss by running sass --watch preview.scss:preview.css

Changelog

0.2

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