← Back to team overview

launchpad-dev team mailing list archive

New link rendering functionality

 

Hi

I completed some new functionality to harvest and render branch link
aliases in a better way. I'll share what I have done because I think the
general concept is useful and I wrote the implementation to be
extensible. The original brief just pertained to branch links but we
could, for example, use the functionality to extend the rendering of
bugs links.

I had meant to send this email earlier but has issues getting the last
piece of code merged. This has just happened to you will have the new
code when you next update.

If this functionality doesn't interest you, stop reading now and hit
delete. Or if you are having trouble sleeping, consider reading further.

So what happens with the current implementation is that branch link
aliases (eg lp:foo, lp:~fred/foo/bar etc) are harvested in the page
onload event and sent via an ajax call to the server side. Any links
found to be invalid are:
- given an "invalid-link" class and rendered greyed out according the
the newly added css style
- have their title attribute updated to reflect the error lifted from
the relevant server side exception eg "No such branch lp:foo"
- have their onclick redirected to show an alert with the error message

When a page is rendered, text linkification process adds a class
"branch-short-link" to any +branch links (see FormattersAPI class). The
onload event adds processing to harvest the links with that known class
and send them via a json payload to the +check-links endpoint using a POST.

The +check-links endpoint is implemented by the LinkCheckerAPI class in
lp/app/browser/linkchecker.py. This class will process/validate the
links and send a json response. The response contains the links to
update and the message to set as the link title.

So how to extend it? You need to:

1. Tag links to be processed by extending FormattersAPI (in
lp/app/browser/stringformatter.py)
2. Extend the javascript to send a json packet to +check-links when the
page loads
3. Plug in a new handler for the link type in LinkCheckerAPI
4. Extend the javascript to process the json response from the ajax call

The javascript lives in lib/lp/app/javascript/lp-links.js

1. Tag required link types in FormattersAPI.

Existing code snippet example:
<snip>
return '<a href="%s" class="my-link-class">%s</a>%s'
</snip>

2. Harvest link types to check

Add a line like the following to lp-links.js
  harvest_links(links_to_check, 'my-link-class', 'my_links');

Note the current implementation is this:
  harvest_links(links_to_check, 'branch-short-link', 'branch_links');

3. Add new link handler

Add to link_checkers dict in LinkCheckerAPI
(lib/lp/app/browser/linkchecker.py)
eg
    # Each link type has it's own validation method.
    self.link_checkers = dict(
        branch_links=self.check_branch_links,
        my_links=self.check_my_links
    )

Note that 'my_links' corresponds to the link_type parameter value used
with the harvest_links() call.

See the existing check_branch_links(self, links) implementation. The
business logic is quite trivial. It processes each passed in link and
returns those which require a new class/title to be updated in the DOM.

4. Process the json response from the ajax call to update any links

process_invalid_links(link_info, 'my-link-class', 'my_links');

The above api just extracts links with the key "invalid_my_links" from
the json response and updates their class and title.

It's really up to the implementation what processing is done. The link
handler in step 3 may choose to add links to process to the response
object using a different key prefix for a different purpose.

The whole implementation is quite simple (just like me). There's more
lines in this email than lines of code (well close to). To recap, the
core files to look at are:

lib/lp/app/javascript/lp-links.js for client side javascript
lib/lp/app/browser/linkchecker.py for server side logic
lp/app/browser/stringformatter.py to tag the links to process







Follow ups