Html({
title => 'browser compatibility cheat sheet',
- version => '1.4',
+ version => '1.6',
description => [
"Compatibility table of new web features (HTML5, CSS3, SVG, Javascript)",
"comparing support and usage share for all popular browser versions.",
html html5 css css3 svg javascript js dom mobile
ie internet explorer firefox chrome safari webkit opera
'],
- stylesheet => [qw'circus dark mono red light'],
data => ['data/browser/support.inc.pl'],
});
say "<h1>Browser compatibility</h1>\n";
-my $caniuse = do 'data/browser/support.inc.pl' or die $@ || $!;
-$_->{verrelease} = {
- # mark last three (future) versions as unreleased, ensure current isn't
- map {
- $_->[-1] => 0, $_->[-2] => 0, $_->[-3] => 0,
- $_->[-4] => undef,
- } $_->{versions}
-} for values %{ $caniuse->{agents} };
+my $caniuse = Data('data/browser/support');
my %CSTATS = (
'n' => 'l1',
'p d' => 'l2',
'a d' => 'l2',
'y' => 'l5',
+ 'y #' => 'l4',
'y x' => 'l5 ex',
+ 'y x #' => 'l4 ex',
'a' => 'l3',
'a x' => 'l3 ex',
'p' => 'l2',
'u' => 'l0',
+ 'u d' => 'l2',
);
my %DSTATS = (
u => 'unknown',
join(' ',
'with prefix',
map {"-$_-"}
- ($caniuse->{agents}->{$_[0]}->{prefix_exceptions} // {})->{$_[1]}
+ $caniuse->{agents}->{$_[0]}->{version_list}->{$_[1]}->{prefix}
// $caniuse->{agents}->{$_[0]}->{prefix} // (),
);
},
);
my %versions;
while (my ($browser, $row) = each %{ $caniuse->{agents} }) {
- $versions{$browser} = [
- sort { paddedver($a) cmp paddedver($b) } grep { defined }
- @{ $row->{versions} }
- ];
+ $versions{$browser} = [@{ $row->{versions} }];
}
-print <<'';
-<p id="intro">Alternate rendition of Fyrd's <a href="http://caniuse.com/">when can I use...</a> page
+my $ref = showlink('Can I use', 'https://caniuse.com/');
+$ref =~ s/(?=>)/ title="updated $_"/
+ for map { s/[\sT].*//r } $caniuse->{-date} || ();
+$ref = "Fyrd's $ref page";
+say '<p id="intro">Alternate rendition of '.$ref;
my ($canihas, $usage);
my $minusage = $get{threshold} // 1;
'Identifier must be alphanumeric name or <q>0</q>.',
]);
}
- $canihas = do "data/browser/usage-$_.inc.pl" or do {
- Alert('Browser usage data not found', $@ || $!);
+ $canihas = eval { Data("data/browser/usage-$_") } or do {
+ Alert('Browser usage data not found', $@);
break;
};
$usage = $_;
my $ref = $canihas->{-title} || 'unknown';
$ref = showlink($ref, $_)
for $canihas->{-site} || $canihas->{-source} || ();
- $ref .= " $_" for $canihas->{-date} || ();
+ $ref =~ s/(?=>)/ title="updated $_"/ for $canihas->{-date} || ();
print "\nwith $ref browser usage statistics";
}
} @browsers
}; # fallback hash based on release semantics
-my $usagepct = 1; # score multiplier for 0..100 result
-# normalise usage percentage to only include shown browsers
-$usagepct = 100.01 / featurescore({ # yes for every possible version
- map { $_ => { map {$_ => 'y'} map { @{$_} } @{$versions{$_}} } } keys %versions
-});
+# score multiplier for percentage of all browser versions
+my $usagepct = 99.99 / sum(
+ map { $_->{-total} // values %{$_} }
+ map { $canihas->{$_} }
+ grep { !/^-/ }
+ keys %{$canihas}
+);
+
$_->{usage} = featurescore($_->{stats}) * $usagepct
for values %{ $caniuse->{data} };
# preceding row without any colspan to work around gecko bug
print "\n<tr>";
for my $browser (@browsers) {
- for (@{ $versions{$browser} }) {
+ for my $span (@{ $versions{$browser} }) {
my $lastver = first {
- !defined $caniuse->{agents}->{$browser}->{verrelease}->{$_} # stable
- } reverse @{$_};
+ $caniuse->{agents}->{$browser}->{version_list}->{$_}->{release_date} # stable
+ } reverse @{$span};
printf('<td title="%s"%s>%s',
join(' ',
- sprintf('%.1f%%', sum(@{ $canihas->{$browser} }{@$_}) * $usagepct),
- 'version ' . showversions(@{$_}, undef),
- $_->[-1] eq $lastver ? () : '(development)',
+ sprintf('%.1f%%', sum(@{ $canihas->{$browser} }{ @{$span} }) * $usagepct),
+ 'version ' . showversions(@{$span}, undef),
+ (map {
+ $_ ? sprintf('(released %d)', $_/3600/24/365.25 + 1970) : '(development)'
+ } $caniuse->{agents}->{$browser}->{version_list}->{$lastver}->{release_date}),
),
!defined $lastver && ' class="ex"',
- showversions($lastver),
+ showversions($lastver // $span->[0]),
);
}
}
if ($canihas) {
while (my ($browser, $versions) = each %$row) {
ref $versions eq 'HASH' or next;
- while (my ($version, $status) = each %$versions) {
+ my $prev;
+ for my $version (@{ $caniuse->{agents}->{$browser}->{versions} }) {
+ my $status = $versions->{$version} // $prev;
$status =~ s/\h\#\d+//g;
$rank += ($canihas->{$browser}->{$version} || .001) * $PSTATS{$status};
+ $prev = $status;
}
}
return $rank;
s/(?<= [^.\n]) $/./gmx; # consistently end each line by a period
Entity($_);
s{ ` ([^`]*) ` }{<code>$1</code>}gx;
+ s{ \(\K (?: \Qhttps://caniuse.com\E )? (?: /? \#feat= | / ) }{#}gx;
s{ \[ ([^]]*) \] \( ([^)]*) \) }{<a href="$2">$1</a>}gx;
}
return @html;
my $data = $feature->{stats}->{$browser};
if (ref $data eq 'ARRAY') {
# special case for unsupported
- my $release = $caniuse->{agents}->{$browser}->{verrelease};
$data = {
- map { $_ => defined $release->{$_} ? 'u' : 'n' } keys %$release
+ map { $_ => 'n' }
+ keys %{ $caniuse->{agents}->{$browser}->{version_list} }
};
}
my $compare = (
!defined $ver ? undef : # last column if nameless
ref $data ne 'HASH' ? '' : # unclassified if no support hash
- $data->{ $ver->[-1] } // $prev # known or inherit from predecessor
- // (grep { defined } @{$data}{ map { $_->[0] } @{ $versions{$browser} } })[0]
- ~~ 'n' && 'n' # first known version is unsupported
+ (first { defined } @{$data}{ reverse @{$ver} }) # last known version
+ // $prev # inherit from predecessor
|| 'u' # unsure
);
- unless (!defined $prev or $prev ~~ $compare) {
- my @vercover = (map { @{$_} } @span);
+ if (defined $prev and not $prev ~~ $compare) {
+ # different columns
+ my @vercover = (map { @{$_} } @span); # accumulated conforming versions
+ for ($ver ? @{$ver} : ()) {
+ last if defined $data->{$_}; # until different
+ push @vercover, $_; # matches from next span start
+ }
my $usage = sum(@{ $canihas->{$browser} }{@vercover});
# strip #\d note references from support class
));
$title .= "\n$_" for notestotitle(@notes);
+ $prev .= ' #' if @notes and $prev =~ /^y/;
printf('<td class="%s" colspan="%d" title="%s">%s',
join(' ',
X => $CSTATS{$prev},
),
scalar @span,
$title,
- showversions($span[0]->[0], @span > 1 ? $span[-1]->[-1] : ()),
+ showversions($span[0]->[0], @span > 1 && defined $ver ? $span[-1]->[-1] : ()),
);
undef $prev;
@span = ();
}
- push @span, $ver && [ grep { $data->{ $_ } eq $data->{ $ver->[-1] } } @{$ver} ];
+ if ($ver) {
+ my $startversion = first { defined $data->{ $ver->[$_] } }
+ reverse 0 .. $#{$ver}; # compare index
+ push @span, [ @{$ver}[ $startversion .. $#{$ver} ] ];
+ }
$prev = $compare;
}
}
sub paddedver {
# normalised version number comparable as string (cmp)
- shift =~ /(?:.*-|^)(\d*)(.*)/;
+ $_[0] =~ m/(?:.*-|^)(\d*)(.*)/;
# matched (major)(.minor) of last value in range (a-B)
- return sprintf('%02d', $1 || 99) . $2;
+ return sprintf('%03d', length $1 ? $1 : 999) . $2;
}
sub showversions {
<div class="legend">
<table class="glyphs"><tr>
<td class="X l5">supported
+ <td class="X l4">annotated
<td class="X l3">partial
<td class="X l2">optional
<td class="X l1">missing
</div>
<script type="text/javascript" src="/searchlocal.js"></script>
-<script type="text/javascript"> prependsearch(document.getElementById('intro')) </script>
+<script type="text/javascript"><!--
+ prependsearch(document.getElementById('intro'));
+//--></script>