2 # Opera Bookmark address file -to-> HTML converter.
3 # Tested with Opera Hotlist versions:
17 my $LastFRef = $RootFRef;
18 my ($FRef, $LastRef, $LastURef);
20 open INFILE
, '<', $ARGV[0] || $ENV{'HOME'}."/.opera/bookmarks.adr";
25 $FRef = {'isfolder'=>1};
26 push @
{$LastFRef->{'children'}}, $FRef;
33 push @
{$LastFRef->{'children'}}, $LastURef;
38 if(ref $LastFRef ne 'HASH') {
39 die "Malformed bookmark file.";
42 elsif(/^\s+([^=]+)=(.*)/) {
46 # debug # print STDERR Dumper $RootFRef;
60 s/%([[:xdigit:]]{2})/chr hex $1/eg;
65 return "<DIV CLASS='toolbar'>" . (
67 map { sprintf "<A HREF='#b%s'>%s</A>", $_->{'UNIQUEID'}, $_->{'NAME'} }
68 sort { $a->{'PERSONALBAR_POS'} <=> $b->{'PERSONALBAR_POS'} }
75 my $Indent = $_[1] || 0;
76 my ($out, $parent, $ico, $liattr, $url, $spanattr, @liclass);
79 # Populate PersonalBar list
80 if(uc $H->{'ON PERSONALBAR'} eq 'YES') {
83 $out .= "<A NAME='b" . $H->{'UNIQUEID'} . "'></A>";
87 map { $liattr .= sprintf q{ %s="%s"}, $_, $H->{$_} } grep {/^ID|CREATED|VISITED$/} keys %$H;
89 # Is it a parent (folder) ?
90 if(ref $H->{'children'} eq 'ARRAY') {
91 push @liclass, "parent";
92 $spanattr .= " onClick=\"toggle('" . $H->{'UNIQUEID'} . "');\"";
94 push @liclass, (uc $H->{'EXPANDED'} eq 'YES' ? "expanded" : "collapsed");
96 if($H->{'isfolder'}) {
97 push @liclass, "childless";
102 if($H->{'ICONFILE'}) {
103 $ico = $H->{'ICONFILE'};
105 my ($host) = ( $H->{'URL'} =~ m{//([a-z0-9\._-]+)}i );
106 if( open my $idx, '<', $ENV{'HOME'}."/.opera/icons/$host.idx" ) {
110 $ico = urldecode($ico);
115 $liattr .= " STYLE=\"list-style: none;\"";
116 $out .= "<IMG CLASS=\"favicon\" SRC=\"$ico\" onError=\"icoNotFound(this, '".$H->{'ID'}."');\" />";
119 $liattr .= " CLASS=\"".join(' ', @liclass)."\"";
120 $out .= "<LI$liattr>";
123 if(defined $H->{'URL'}) {
124 $url = urldecode($H->{'URL'});
127 $out .= "<A HREF=\"#\" ID=\"replace$replaceid\">";
128 $replaces{$replaceid} = $url;
130 $out .= "<A HREF=\"$url\">";
133 $out .= "<SPAN$spanattr>" . htmlentities($H->{'NAME'}) . "</SPAN>";
134 if(defined $H->{'URL'}) {
139 if(defined $H->{'DESCRIPTION'}) {
140 $out .= "<DIV CLASS=\"description\">" . htmlentities($H->{'DESCRIPTION'}) . "</DIV>";
143 # Descendant items...
145 $out .= "<UL ID=\"" . $H->{'UNIQUEID'} . "\">";
146 for my $child ( @{$H->{'children'}} ) {
147 $out .= "\n".' 'x$Indent;
148 $out .= Node( $child, $Indent+4 );
150 $out .= "\n".' 'x$Indent."</UL>";
159 <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8" />
162 border: solid 1px black;
173 li.parent.expanded { list-style-image: url('/static/img/icon/folder_opened.gif'); }
174 li.parent.collapsed, li.childless { list-style-image: url('/static/img/icon/folder_closed.gif'); }
175 li.parent.collapsed > ul {
178 div.description, footer {
197 $BMTree = Node
( Parse
() );
200 print PersonalBar
(\
@PB);
202 print "<UL>" . $BMTree . "</UL>";
205 print "<HR><FOOTER>Made by <A HREF=\"https://github.com/bAndie91/tools/blob/master/user-tools/adr2html\">adr2html</A>.</FOOTER>";
207 # Script - Restore expanded/collapsed state of nodes
208 print "<SCRIPT TYPE='text/javascript'>\n";
210 function toggle(id, yesclass) {
211 var cl = document.getElementById(id).parentNode.classList;
212 if(typeof yesclass == 'undefined') yesclass = cl.contains('expanded') ? 'collapsed' : 'expanded';
213 var noclass = (yesclass == 'expanded') ? 'collapsed' : 'expanded';
214 document.cookie = 'FOLDER'+id+'='+yesclass;
218 var as = document.cookie.match(/FOLDER[^=]+=[^;]*/g);
219 for(var ai=0; ai<as.length; ai++) {
220 bs = as[ai].match(/FOLDER([^=]+)=([^;]*)/);
221 toggle(bs[1], bs[2]);
223 function icoNotFound(img, li) {
224 document.getElementById(li).style.listStyle='disc';
225 img.parentNode.removeChild(img);
229 # Script - Fill up HREF attriutes where it couldn't be (due to html escaping)
230 for my $replaceid (keys %replaces) {
231 my $url = $replaces{$replaceid};
232 $url =~ s/['']/\\$&/g;
233 print "document.getElementById('replace$replaceid').setAttribute('HREF', '$url');\n"
243 adr2html - Convert Opera Hostlist 2.0 bookmarks to HTML