3 * Bookmarklet to add annotation tools to AustLII cases. Invoke with:
4 * javascript:var d=document;var s=d.createElement("script");s.src="http://splintax.ucc.asn.au/austlii/austlii.js";s.type="text/javascript";d.getElementsByTagName('head').item(0).appendChild(s); */
6 // create a namespace for this tool
9 load: function(url, cb) {
10 // Load an arbitrary JavaScript file and fire cb.
11 var s = document.createElement("script");
12 s.src = url; s.type = "text/javascript"; s.onload = cb;
13 document.getElementsByTagName('head').item(0).appendChild(s); return;
15 style: function(url) {
16 // dynamically add a new stylesheet
17 var s = document.createElement("link");
18 s.rel = "stylesheet"; s.type = "text/css"; s.href = url;
19 document.getElementsByTagName('head').item(0).appendChild(s); return;
21 url: function(relative_path) {
22 // return url relative to the source of this file, eg. http://splintax.ucc.asn.au/austlii/
23 var prefix = $('script[src$="austlii.js"]').attr('src').replace(/austlii\.js/, "");
24 return prefix + relative_path;
28 // Initialises once jQuery is loaded.
29 austlii.main = function() {
30 austlii.style(austlii.url("austlii.css")); // inject css
31 // set viewport width so iPad doesn't zoom out
32 $("head").append('<meta name="viewport" content="initial-scale=1.0" />');
33 $("a").slice(10,16).css({"margin-right": "1em"}); // space out "Database Search", ... links
37 $(window).scroll(austlii.scrollHandler).scroll();
39 // enable smooth scrolling on anchors
40 // TODO: doing this synchronously makes for slow injection on mobile browsers
41 austlii.load(austlii.url("jquery.scrollTo-1.4.2-min.js"), function() {
42 austlii.load(austlii.url("jquery.localscroll-1.2.7-min.js"), function() {
43 $.localScroll({duration: '200'});
47 // TODO: user annotations
48 $("#trigger-highlight").click(austlii.highlight);
51 // Cleans up page and adds semantic markup.
52 austlii.markup = function() {
55 $('img[alt="AustLII"]').detach().prependTo("body");
58 $("h1").wrap('<a class="section" name="top">'); // add back-to-top
59 $('a[name="fn1"]').addClass("section"); // mark beginning of footnotes
61 // find and markup judges
62 var judgeExp = /([A-Zc]{3})((?:[A-Z\s,]| )+C?J?J\.)/g
63 /* This regex is confusing and I keep breaking it. Remember:
64 * [A-Zc] is used to match McHUGH J.
65 * Since we're matching innerHTML is not part of \s.
66 * The first 3 characters are captured, hopefully because they are ASCII non-whitespace
67 * suitable for use in the <a name>. */
68 var replacementText = document.body.innerHTML.replace(judgeExp, '<a class="section" name="$1">$1$2</a>');
69 document.body.innerHTML = replacementText;
72 // Updates responsive menu whenever the page is scrolled.
73 austlii.scrollHandler = function() {
74 var currentPosition = $(window).scrollTop() + $(window).height()/2;
76 var $anchors = $("#container a.section");
77 var $links = $("#menu ol li a");
78 var $pars = $("#container ol li").not("ol ol li");
80 // remove existing section highlight and citation
81 $links.removeClass("current");
82 $("#menu .pinpoint").remove();
84 // find the current document section
85 var $anchor = $anchors.filter(function(){
86 // is this anchor above the fold?
87 return currentPosition > $(this).offset().top;
88 }).last(); // current section = last anchor above fold
89 // highlight the link to the current document section
90 $links.filter('[href="#' + $anchor.attr("name") + '"]').addClass("current");
92 // check whether we're in the judgment body
93 if ( currentPosition > $pars.first().offset().top &&
94 currentPosition < $pars.last().offset().top ) {
95 // we are, so find the current paragraph and add a pinpoint citation
96 var $par = $pars.filter(function(){
97 // is this paragraph above the fold?
98 return currentPosition > $(this).offset().top;
99 }).last(); // current paragraph = last paragraph above fold
100 if ( $par.val() != 0 ) { // don't add unofficial paragraph citations on old cases
101 // TODO: make it work anyway, but add a warning?
102 var $pinpoint = $('<span class="pinpoint"> at ['+ $par.val() +']</span>');
103 $("#menu a.current").after($pinpoint); // add citation
108 // Create the responsive menu.
109 austlii.menu = function() {
110 // wrap the source body content in a container
111 $("body").children().wrapAll('<div id="container" />');
113 // create and prepend menu to the page
114 var $menu = $('<div id="menu"></div>');
115 $('<h2>'+ $("h2").first().html() +'</h2>').prependTo($menu); // add header
116 $('img[alt="AustLII"]').detach().prependTo($menu);
117 $menu.prependTo("body");
119 // create and insert links in the menu
120 var $links = $('<ol />');
122 $links.append('<li><a href="#top">Headnote</a><span class="spacer">·</span></li>')
124 var $judges = $("a.section").slice(1,-1);
125 $judges.each(function(i){
126 var li = '<li><a href="#' + this.name + '">' + $(this).html().slice(0,-1) + '</a>';
127 if ( i < $judges.length )
128 li += '<span class="spacer">·</span>'
133 $links.append('<li><a href="#fn1">Footnotes</a></li>');
134 $menu.append($links);
136 // add annotation features
137 //$menu.append($('<a id="trigger-highlight" href="#">Highlight</a>'));
140 // FIXME Highlight the current selection.
141 austlii.highlight = function(event) {
142 event.preventDefault();
143 var sel = document.getSelection();
144 if (sel.type == "Range") {
146 var range = sel.getRangeAt(0);
147 var $note = $('<span style="background-color: yellow;" />');
148 range.surroundContents($note[0]);
151 var $menu = $('<div style="position: absolute;" />');
152 var $removeLink = $('<a href="#">Remove</a>');
154 $menu.append($removeLink);
155 $removeLink.click((function($hilite) {
156 var text = $hilite.text();
157 $hilite.after(text).remove();
160 else {console.log("You haven't highlighted anything.")}
163 // don't run on other sites
164 if (window.location.host.slice(-14) != "austlii.edu.au" ||
165 window.location.pathname.slice(0,10) != "/au/cases/" ||
166 window.location.pathname.slice(-5) != ".html")
167 console.error("You're not looking at a case on AustLII.");
169 else if (document.getElementsByTagName("script").length > 1)
170 console.error("austlii.js will not run when there are other scripts on the page.");
173 console.log("Loaded austlii.js.");
174 // load jQuery and initialise the bookmarklet
175 austlii.load('http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js', austlii.main);