DuckDuckGO Spice Plugins
See DuckDuckHack for an overview of the DuckDuckGo plugin system.
Spice plugins are in beta and both the interface and testing procedure will improve over time. However, you can work away without worrying about what any changes might do to your plugins -- we'll take care of all that.
First off, thank you!
Pick a spice project (or add one) and comment that you're working on it.
Develop your plugin using the Structure below in a fork.
Test your plugin via Testing procedure below.
Submit a pull request.
Feel free to ask questions!
Each spice plugin currently produces three files. The first file is described in the DuckDuckHack plugin tutorial and you should start there.
When finished you will have made your plugin triggers file within the lib/DDG/Spice directory.
The other two files should be placed in a project directory within share/spice.
Each directory has a structure like this:
# Main file, which gets called by the client at the appropriate time. # This file defines the callback function and any helper functions you need # to process data that gets returned from the JSONP APIs. plugin/spice.js # Nginx conf to call the relevant external API. # To prevent search leakage (and for caching), we run # all calls through nginx. # Start with the xkcd conf and try modifying it appropriately. # In a future iteration this will be produced automatically. plugin/nginx.conf
In a future iteration we'll give you a Web server testing facility that you an query.
For now, however, you should be able to test your spice plugin in your browser locally. To do so make an HTML file with a script tag that calls the external JSONP api. Then put your callback function in the same file. The API will return the JSON object to your callback function.
The overall flow is as follows:
An external API is called with a callback function.
That callback function is defined by you, and takes the JSON object from the external API and parses out the information needed for display.
Your callback function calls the nra function with the appropriate variables. That is the internal function we use to display the Zero-click Info box for spice plugins. You pass nra a object that takes the following parameters. We are in the process of cleaning up this interface to be way more intuitive :)
// Requried snippet (abstract). It can be pure HTML in which case it is set via innerHTML, but better is it is an object, in which case onclick and other event handlers won't be destroyed. items['a'] = snippet; // Optional header. If there is a relevant (and relatively short) title, then set it here. items['h'] = title; // Required source name and url. // These are used to make the More at X link in all Zero-click Info boxes. // 's' should be the main name. items['s'] = 'XKCD'; items['u'] = url // Optional force of a bigger box. Usually the box is auto-resized smaller with an expansion UI if needed. Generally you shouldn't force it to be bigger, but in the XKCD case you don't want the big image to be cutoff. items['f'] = 1 // Optional image. If there is a thumbnail image, we will display it on the right. items['i'] = image_url */
Look at existing plugins for some examples.
If you use internal variables you should put a var statement at the top of the function so they don't leak scope.
If you make html, e.g. by createElement, note d is a global shortcut for document, i.e. d.createElement. (In future versions of the interface we will be backing off from creating display elements directly.)
Any functions should exist in your namespace. For example, for twitter the namespace is tr, so the main callback would named nrtr and a helper function would be nrtr_helper_function.
The image is automatically right-floated by default. To avoid looking bad, use and(if you need line breaks) instead of
. Also it is good to end with a so the More at X line is on the same line. See the twitter plugin for an example.
Don't use jQuery. We use YUI2 internally. To set styles you can do:
If the whole Zero-click Info is an image (like in the XKCD case) you can use this class on the img: