-
Notifications
You must be signed in to change notification settings - Fork 73
Building content services
While all the software architecture is really nice and all that, it's all pointless without engaging, interesting, useful and fun content to be printed.
(If you haven't already looked at the general system architecture, please take a look; it will make some of this make more sense.)
The beauty of this software is that it's very simple to turn content into printouts; you just need to produce some HTML, and the printer system will take care of the rest. But even with that said, there are a few things to be aware of that will make your life easier.
The simplest possible content service isn't even an application -- it's just a static HTML page that includes some Javascript from the printer backend.
The backend provides one such page, called sample.html
<!doctype html>
<html class="no-js" lang="en">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<!-- 1. --> <link rel="stylesheet" href="http://printer.exciting.io/stylesheets/print.css" type="text/css" media="screen" title="no title" charset="utf-8">
<!-- 2. --> <script src="http://printer.exciting.io/javascripts/printer.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
$(function() {
$("#previewPage").click(Printer.previewPage);
$("#printPage").click(function() {
var printerID = prompt("Enter the ID of the printer to target");
Printer.printPage(printerUrl, function(result) {
if (result.response == "ok") {
alert("Page successfully sent for printing");
} else {
alert("There was a problem sending this content");
console.log("Error response", result);
}
});
});
})
</script>
</head>
<body class="preview"> <!-- 3. -->
<div class="controls">
<a id="previewPage" href="#">Preview</a>
<a id="printPage" href="#">Print</a>
</div>
<div class="paper"> <!-- 4. -->
<div class="content">
<h1>Your content</h1>
<p>(Put it here, yo.)</p>
</div>
</div>
</body>
</html>
There are a few key features:
- including the print.css
- the printer.js javascript
- the
preview
class on thebody
element - the
paper
andcontent
divs.
Little receipt printers have a very small page width -- normally 384 pixels. The backend server tries as hard as it can to constrain the width of the content for printing to fit in this space, but at the moment it's still possible for a page to accidentally grow to a greater width, which will cause printing to fail.
The print.css stylesheet provides a few small styles to help constrain your content to 384px. All you need to do is wrap your content in an element with the content
class, and this will be set to the correct width.
I strongly recommend that you don't put any other content on your page outside of the content
element (with the preview
caveat I'll explain below.
Designing inside a plain white div
isn't very inspiring, and also doesn't communicate anything about the margins which will be present on the final printout.
To help give a more realistic preview, print.css also includes a style for a paper
element, which is intended to wrap around the content
element described above, like so:
<div class="paper">
<div class="content">
<h1>Your content</h1>
</div>
</div>
If you give the body
element of your page the preview
class, your content will then appear centered and with approximate margins, making it much easier to design. When the backend server performs its rasterisation, it removes this preview
class, reverting the page back to its plain, unadorned version.
You can also use this preview
class to show elements while designing (such as the Javascript print controls which we'll discuss below), but hide those elements when preview
is not present.
Since there's no way for the printer backend to request your local HTML page, we can send the content to it using the javascript in printer.js. This provides two functions -- Printer.previewPage
and Printer.printPage
-- which you can connect to links or buttons on your page.
(If you are running your own print backend, or a local one, you can also change the value of Printer.backendUrl
to point to your server. The default is http://printer.exciting.io
.)
The Printer.previewPage
function simply posts the entire content of the current page to the backend server, and then redirects you to the preview page (which will reload until the preview is ready). This is a good way of checking how fonts will appear during the rasterisation process.
The Printer.printPage
expects a printer URL (e.g. http://printer.exciting.io/print/<your printer id>
) and a callback, which is passed through to jQuery's ajax mechanism. It also posts the page content to the server at Printer.backendURL
.
In this way, you can design, preview and test-print HTML without needing to deploy any content to publicly-accessible servers.
Printing from a static HTML page is great, but it's not exactly interesting. Much better would be to have an application that other people could interact with to produce printouts!
The printer-mail application is a very simple example of such an application. It lets people send 'messages' to other people's printers.
The README on github gives a reasonable overview of how the software works, but in a nutshell there are two distingushing features from our simple page above:
- The application stores print URLs
- The application posts a url to the backend, rather than HTML content
In order to use the application, printer owners must "register", which in this case means finding out your print URL (if you have a printer connected to the printer.exciting.io
backend, you can find your URL by visiting http://printer.exciting.io/my-printer), and then using a form to store this along with a "nickname" in a small database. This nickname is used to retrieve the print URL when friends visit the application.
For example, if I people to send messages to "lazyatom", and my print URL was http://printer.backend.server/print/abc123
, then I'd use both those values in the registration.
When the friend of a printer owner sends them a message, the content of that message is saved by the application, and associated with the nickname/print URL record. Immediately after saving this data, the application sends a request to the print URL in roughly the following form:
POST http://printer.backend.server/print/abc123
url=http://printer-mail.server/message/457345
The url
parameter corresponds to a page in the mail application which will display the sent message in a suitable manner (width, styling, as described above) to be printed.
The backend printer will then request that URL, download the content and get busy with preparing it for the printer connecting to it with the ID abc123
.
That's pretty much the whole application, in a nutshell. The printer-paint application follows almost exactly the same pattern (much of it was entirely copied).
It's really a trivial demonstration, and if you were really interested in producing something similar you would probably want to add things like robust validation, checking for duplicate registrations, removing your printer, restricting who could send you a message, and so on.
Printing when someone presses a button is a bit more interesting than a static page, but it also doesn't quite reach the promise of waking up to a nice bundle of interesting and relevant content that's been automatically prepared for us.
Thankfully, it's only slightly more work to remove our friends from the printing procedure entirely and have the content be prepared and sent to the printer entirely automatically.
The printer-weather application is a very simple demonstration of exactly this. For every printer than is registered with it, a custom weather forecast is prepared and downloaded by the printer at 8am sharp, every day.
You can view the source to find out more about how it's put together, but there is only one significant difference between it and the mail and paint examples above:
- automatic scheduling of print URL posting
As with printer-mail, the application requires you to "register" your print URL (although no nickname is required), and this is stored in a database. In order to give you an accurate weather forecast, the application needs to know where in the world you are, and so the simplest possible way to do that is to use geocoding to estimate your location from your IP. This is also stored against the print URL, and the record is given a unique ID.
Nothing else happens until the scheduler (which could be "cron", but in this case is the Heroku scheduler addon) wakes up at 8am GMT.
When the scheduler wakes up, for every record in the database, it sends a request:
POST http://whatever.printer.backend/print/:printer-id
url=http://weather.service.host/jobs/:job-id
When a backend server requests http://weather.service.host/jobs/:job-id
, the appropriate record is loaded from the database, and the IP is used by the (extremely hacky) weather code to ultimately produce some weather data, which is finally rendered in HTML (with icons drawn in HTML5 canvas tags -- fancy).
The backend then dutifully consumes the content and hands it off the appropriate printer as before.
Were this a more robust application, it would ask you for your location as part of the registration, validate it and store that against the print URL, rather than the IP. It could also store your name and use that in the printout to be friendly.
The point is simply that an application could store whatever data it wants with a print URL, and use that to produce interesting and useful content. A very similar service could as easily be loading todo lists by obtaining a Google data token on behalf of the user, or printing out the latest twitter mentions by storing a twitter OAuth token.
The only limit is your imagination and creativity, and your ability to turn that into HTML.
Now get to it!