File Coverage

blib/lib/NNexus/Annotate.pm
Criterion Covered Total %
statement 75 78 96.1
branch 20 24 83.3
condition 10 12 83.3
subroutine 9 9 100.0
pod 1 2 50.0
total 115 125 92.0


line stmt bran cond sub pod time code
1             # /=====================================================================\ #
2             # | NNexus Autolinker | #
3             # | Annotation Module | #
4             # |=====================================================================| #
5             # | Part of the Planetary project: http://trac.mathweb.org/planetary | #
6             # | Research software, produced as part of work done by: | #
7             # | the KWARC group at Jacobs University | #
8             # | Copyright (c) 2012 | #
9             # | Released under the MIT License (MIT) | #
10             # |---------------------------------------------------------------------| #
11             # | Adapted from the original NNexus code by | #
12             # | James Gardner and Aaron Krowne | #
13             # |---------------------------------------------------------------------| #
14             # | Deyan Ginev #_# | #
15             # | http://kwarc.info/people/dginev (o o) | #
16             # \=========================================================ooo==U==ooo=/ #
17             package NNexus::Annotate;
18 6     6   13423 use strict;
  6         8  
  6         221  
19 6     6   24 use warnings;
  6         6  
  6         183  
20              
21 6     6   20 use Exporter;
  6         8  
  6         341  
22             our @ISA = qw(Exporter);
23             our @EXPORT_OK = qw(serialize_concepts);
24              
25 6     6   479 use List::MoreUtils;
  6         7383  
  6         48  
26 6     6   2116 use Data::Dumper;
  6         6156  
  6         343  
27             $Data::Dumper::Sortkeys =1;
28 6     6   319 use NNexus::Concepts qw(links_from_concept);
  6         8  
  6         292  
29 6     6   1307 use Mojo::JSON qw(decode_json encode_json);
  6         36653  
  6         4045  
30              
31             sub serialize_concepts {
32 12     12 1 78 my (%options) = @_;
33             # Annotation Format:
34             # HTML - fully linked html
35             # HTML+RDFa - fully linked html with RDFa annotations
36             # xml - the matches hash in XML format.
37             # json - the matches in JSON format
38             # perl - Dump the datastructrure as-is
39 12         23 my ($annotation,$concepts,$domain) = map {$options{$_}} qw/annotation concepts domain/;
  36         59  
40 12         25 $concepts = [@$concepts]; # Clone top-level array
41 12         22 $annotation = lc($annotation);
42 12 100 100     64 if ($domain && (lc($domain) ne 'all')) {
43             # Filter by domain:
44 6         13 @$concepts = grep {$_->{domain} eq $domain} @$concepts; }
  7         24  
45             # Add the http:// prefix to all links and multilinks:
46 12         24 foreach my $concept(@$concepts) {
47 17         24 my $link = $concept->{link};
48 17         16 my $multilinks = $concept->{multilinks};
49 17 100 100     102 $concept->{link} = 'http://'.$link if ($link && $link !~ /^http/);
50 17 100       36 @{$concept->{multilinks}} = map {$_ !~ /^http/ ? 'http://'.$_ : $_} @$multilinks if defined $multilinks;
  4 100       10  
  8         18  
51             }
52 12         21 my $total_concepts = 0;
53 12 100       27 if ($options{embed}) {
54 10         17 my $body = $options{body};
55 10 50 33     79 if ((!$annotation) || ($annotation =~ /^html/)) {
56             # embed HTML links
57             # Enhance the text between the offset with a link pointing to the URL
58             # TODO: Multi-link cases need special treatment
59 10         32 while (@$concepts) {
60 10         12 my $concept = pop @$concepts; # Need to traverse right-to-left to keep the offsets accurate.
61             #print STDERR Dumper($concept);
62 10         15 my $from = $concept->{offset_begin};
63 10         14 my $to = $concept->{offset_end};
64 10         15 my $domain = $concept->{domain};
65 10         15 my $length = $to-$from;
66 10         23 my $text = substr($body,$from,$length);
67 10         8 my $rdfa_annotation = '';
68 10 100       24 if ($annotation eq 'html+rdfa') {
69 2         3 $rdfa_annotation = 'property="http://purl.org/dc/terms/relation" '; }
70 10         45 my @links = map {[$_ , $domain ]} (links_from_concept($concept));
  13         25  
71 10   100     37 while (@$concepts && ($$concepts[-1]->{offset_begin} == $from)) {
72 3         3 $concept = pop @$concepts;
73 3         4 $domain = $concept->{domain};
74 3         4 my @next_links = map {[$_ , $domain ]} (links_from_concept($concept));
  3         5  
75 3         5 while (@next_links) {
76 3         3 my $next_link = shift @next_links;
77 3 50       3 next if (grep {$_->[0] eq $next_link->[0]} @links);
  6         8  
78 3         13 push @links, $next_link;
79             }
80             }
81 10         11 $total_concepts += scalar(@links);
82 10 50       22 if ($options{verbosity}) {
83 0         0 print STDERR "Linking \"$text\" with: ",$_->[0],"\n" foreach @links; }
84 10 100       33 if (@links == 1) {
85             # Single link, normal anchor
86 7         134 substr($body,$from,$length) = ''.$text.'';
87             } else {
88             # Multi-link, menu anchor
89 9         30 substr($body,$from,$length) =
90             # Trigger menu on click
91             ''
92             . $text
93             . ''
94             . '' # Hidden container for the link menu
95 3         7 . join('',map {''.domain_tooltip($_->[1]).''} @links)
96             .'';
97             }
98             }
99 10 50       59 if ($options{verbosity}) {
100 0         0 print STDERR "Final Annotation contains ",$total_concepts," concepts.\n"; }
101 10         109 return $body;
102             } else {
103 0         0 return $body; # Fallback, just return what was given
104             }
105             } else {
106             # stand-off case:
107 2 100       5 if ($annotation eq 'json') {
108            
109 1         6 return encode_json($concepts); }
110             # when ('perl') { return Dumper($concepts); } #TODO: Why is this relevant? Testing?
111             # TODO: Think of Markdown annotations
112             # TODO: Stand-off HTML links
113             # TODO: Embedded JSON and RDFa
114 1         5 else { return $concepts; }
115             }
116             }
117              
118             our $tooltip_images = {
119             Planetmath=>'http://planetmath.org/sites/default/files/fab-favicon.ico',
120             Wikipedia=>'http://bits.wikimedia.org/favicon/wikipedia.ico',
121             Dlmf=>'http://dlmf.nist.gov/style/DLMF-16.png',
122             Mathworld=>'http://mathworld.wolfram.com/favicon_mathworld.png',
123             Mathhub=>'http://kwarc.info/kohlhase/varia/mathHubLogo.png',
124             Encyclopediaofmath=>'http://www.euro-math-soc.eu/sites/all/themes/custom/ems/images/ems_logo.png',
125             Nlab=>'http://nnexus.mathweb.org/nlab_logo.png'
126             };
127             sub domain_tooltip {
128 9     9 0 5 my ($domain_name) = @_;
129 9         40 ''.$domain_name.'';
130             }
131              
132             # TODO: Given a list of internally represented annotations, serialize them to
133             # the desired format (html, xml, json)
134              
135             1;
136             __END__