Ultralinks have immense flexibilty and extensibility. You can easily add your own custom link types and create Inline Panes that can perform any functionality you might need. This makes the Ultralink a robust development platform, capable of connecting the data you care about, regardless of where it resides or where it is referenced.
You can either pass your options object directly through the aforementioned methods, or you can make use of an option called remoteRoots. This option allows you to specify an array of one or more URLs that point to an Ultralink Root. This is a web-accessible directory where you can customize and develop Ultralink functionality for your own specific needs. Although this example will focus on the basics of link type creation, check out Ultralink Root documentation for a deeper dive into what they can do.
We will now walk through an example by creating a new link type that allows users to play any video game available through the Internet Archive right in an Ultralink! Feel free to follow along and construct it yourself or poke at the example source.
The first thing we do after creating an empty directory for our new Root somewhere is to add an options.json file to it. When you pass the URL to this directory through the remoteRoots option, this file is going to be retrieved by the Ultralink code in ultralink.js with a standard GET operation when it starts up. You may need to modify the server's Access-Control-Allow-Origin header through an .htaccess file or the like, to avoid browser security issues. Inside options.json is a JSON object containing all the configuration options that you would normally pass to Ultralink.start(). When this Root is loaded, all the settings inside options.json are passed through as if they had been passed in directly.
Now let's add our new link type to options.json. We do this by adding a customLinkTypes object. This object describes the new link types that we want to create and also allows us to override specific attributes of existing link types if we wish. On the top level of this object are the categories that our link types reside in. In this example we are creating a new link type category called Play. In this object we can configure how the category behaves with various options, but here we are only going to define a single new link type.
In the links object, we have an entry for our new link type which we will identify by the link type string iagame (Internet Archive Game). This string should be unique from any other existing link type. In the object describing the new link type, we have a name attribute which defines the human-readable label that will be displayed. We also have a pane attribute set to true which indicates that this link type has an Inline Pane available (these kinds of links are sometimes called black shadow because of the black drop shadow around the link when it is available).
Now we need to create a place to contain all the resources related to our new link type. We create a directory at the top level of our Root called linkTypes and inside that we create another directory named iagame.
The next thing we need to do is create an icon for our new link type. The source icon image should be of reasonably high resolution, square and should have no padding. If it does have padding that is not a deal breaker, it just means that you might need to add and play around with the iconShrinkage parameter which resizes your icon (default value 0.75) on top of a white link type icon background. If you do not want to use the default link type icon background, but would prefer to supply your own images that incorporate both icon and background, you can set the iconBackground parameter to false.
Once we have an icon the way we like it, we need to save 5 different copies at various resolutions. We save the icon as png files with resolutions of 256x256, 128x128, 64x64, 32x32 and 16x16 using the naming convention (resolution indication number).png. You can optionally use an Automator workflow we created (SquareToMultiple.workflow.zip) to convert that image into the 5 that are needed (saves them to your Desktop). The 5 image convention is mostly for compatability with browsers that don't resize images well but it can also potentially save bandwidth by only using the most efficient version of an icon.
However, if you have an svg or other single image file that you would prefer to use and scale at every resolution, you can specify that the Ultralink should use that instead of picking from the 5 images by adding the icon parameter with a value that is set to the name of the file (icon.svg for example). Finally, we create a directory inside linkTypes/iagame called icon and move our image files in there.
We now have some basic front-end support for our new link type. But to test this functionality out, we need to add a link of this type to an Ultralink. Normally this data comes from an Ultralink database, but for testing purposes we are going to create one on the fly using the Root Debugger tool.
This tool allows us to quickly check our Root for loading issues and test out our new link types. The first thing we do is enter the location where our Root resides and then hit the "Load" button or enter/command key. If the Root successfully loads, a list of the options set in the options.json file are displayed (in this example, only customLinkTypes is set) and an area with a "Test Ultralink".
Here we can add arbitrary links to the test Ultralink below where we can test out their behavior and debug things. We select the iagame link type from the drop down (custom link types are listed at the top) and then enter in our URL for the Prince of Persia page (https://archive.org/embed/msdos_Prince_of_Persia_1990) into the adjacent input box and hit the "+" button or the enter/command key.
And it works! We can see our new link type in action and bring up an iframe of the Internet Archive link when we click on it. For links that can simply be brought up in an iframe this is all we have to do. If we don't even need an Inline Pane, and just want the link type to simply be included in the Ultralink (a blue shadow link), then omit the pane attribute in options.json.
Although things seem to work pretty well, there are a couple of small issues. The first is that input to the game gets lost when the browser changes focus. This means that the game becomes unplayable if you click off elsewhere in the page.
The other issue is that we are using the Internet Archive's embed style of link which is appropriate for an iframe but there is actually a main details page for the games that include useful information, comments and other rich content. When the user wants to click on the blue shadow, link to actually visit the page, we actually would prefer that it go to the details version instead of the embed version.
It looks like a simple iframe might not be enough for this specific link type. We can actually solve both of these problems pretty easily by creating a View for this link type. Link type views give you a lot of power and flexibility to make things work just the way you want them to.
Inside view.js is where all the action takes place. It's here that we construct the contents of the Inline Pane and can implement whatever functionality we want. Now let's attack those pesky problems we came up against when we simply iframe'd the URL before.
First, want to be able to store the details version of the Internet Archive links for traditional hyperlinking purposes, but still use the embed version with an iframe inside our Inline Pane. So we change the constructed link on our iagameDemo.html page to be the full details page. When an Inline View page is loaded, the clicked URL gets passsed as a parameter and parsed into a variable called Ultralink.InlineView.URL. So in view.js we can simply modify that URL into the corresponding embed version and add an iframe with that URL to the Inline View's container div (Ultralink.InlineView.cDiv).
The other reason we wanted to create our own custom view is to make sure that the game can regain event focus after we click outside of the iframe. We can accomplish this by manually setting the focus on the iframe whenever our mouse cursor enters the view.
After we finish setting things up, it's very important to signal to the Ultralink that we are ready for display. That is why we call the method Ultralink.InlineView.kickoffViewLoad() at the end. Now we have an Inline Pane that works very similar to what we had before, but without those little issues.
You can explore the set of base functionality available to you in these files that reside in _common/
|common.js||This file finishes the bootstrapping process and loads convinience object that contains some useful globals and methods.|
|common.css||This file includes some basic formatting and common structures.|
|company.css||This contains styles for display of a company table.|
|connections.css||This contains styles for display of a connection table.|
|post.css||This contains some styles useful for displaying sequential posts.|
|profile.css||This file contains styles that can be used to display general profile information for something.|
|search.css||This file contains style useful for displaying search results.|
|This file finishes the bootstrapping process and loads convinience object that contains some useful globals and methods.|
|This file includes some basic formatting and common structures.|
|This contains styles for display of a company table.|
|This contains styles for display of a connection table.|
|This contains some styles useful for displaying sequential posts.|
|This file contains styles that can be used to display general profile information for something.|
|This file contains style useful for displaying search results.|