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
andpaste
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
andcallback
to the Preview object.