+HEAD
+
+warn "came up with URL to treeview-min.js: @{[ $extras->('yui/build/treeview/treeview-min.js') ]}";
+
+ my $accumulated_asset_info = []; # record the stack frames from when we find an asset on the call stack
+
+ $trace->next_frame; # ignore the head
+ my $i = 0;
+ while (my $frame = $trace->next_frame) {
+
+ $i++;
+ $out .= join(
+ '',
+ '
',
+ $frame->subroutine ? encode_html("in " . $frame->subroutine) : '',
+ ' at ',
+ $frame->filename ? encode_html($frame->filename) : '',
+ ' line ',
+ $frame->line,
+ _build_asset_info($i, ($frame->args)[0], $accumulated_asset_info, $frame), # adds data to $accumulated_asset_info; this line added relative the stock Devel::StackTrace::AsHTML
+ q(
),
+ );
+ }
+ $out .= qq{};
+
+ # dump the asset tree
+
+ my $assets = WebGUI::Asset->getRoot($session)->getLineage(['descendants'], {returnObjects=>1});
+
+ my $tree = { type => 'text', label => 'root', children => [], };
+
+ for my $asset (@$assets) {
+ # create a tree structure of assets matching their lineage
+ # the format (arrays, hashes, fields) matches what YAHOO.treeview expects
+ # when we find an asset mentioned in one of the stack trace frames above, we add the saved file/line/etc info to the label
+ my $lineage = $asset->get('lineage');
+ my @parts = $lineage =~ m/(.{6})/g;
+ # warn "asset: $asset lineage: $lineage parts: @parts";
+ my $node = $tree;
+ while(@parts) {
+ my $part = shift @parts;
+ if((my $child_node) = grep $_->{lineage_chunk} eq $part, @{$node->{children}}) {
+ $node = $child_node;
+ } else {
+ my $label = $asset->get('title') . ': Id: ' . $asset->getId . ' Class: ' . ref($asset);
+ for my $message ( map $_->{message}, grep $_->{asset_id} eq $asset->getId, @$accumulated_asset_info ) {
+ $label .= " <----- $message";
+ }
+ my $child_node = {
+ type => 'text',
+ label => $label,
+ lineage_chunk => $part,
+ children => [ ],
+ };
+ push @{$node->{children}}, $child_node;
+ $node = $child_node;
+ }
+ }
+ }
+
+ use JSON::PP; # JSON::XS creates something that's mangled
+ my $json_tree = JSON::PP->new->ascii->pretty->encode( [ $tree ] );
+
+ # warn "json_tree: $json_tree";
+ # do { open my $fh, '>', 'json.debug2.js' or die $!; $fh->print($json_tree); };
+
+ $out .= qq{
+
+
+
+
+ };
+
+ $out .= "";
+
+ return $out;
+}
+
+sub _build_asset_info {
+ my($id, $asset, $accumulated_asset_info, $frame) = @_;
+
+ return '' unless $asset and Scalar::Util::blessed($asset) and $asset->isa('WebGUI::Asset');
+
+ my $asset_title = $asset->get('title');
+ my $asset_id = $asset->getId;
+ my $asset_class = ref $asset;
+
+ my $message = "Stack frame number: $id AssetID: $asset_id Class: $asset_class Title: ``$asset_title''";
+
+ push @$accumulated_asset_info, { asset_id => $asset_id, message => $message, };
+
+ return $message;
+}
+
+sub utf8_safe {
+ my $str = shift;
+
+ # NOTE: I know messing with utf8:: in the code is WRONG, but
+ # because we're running someone else's code that we can't
+ # guarnatee which encoding an exception is encoded, there's no
+ # better way than doing this. The latest Devel::StackTrace::AsHTML
+ # (0.08 or later) encodes high-bit chars as HTML entities, so this
+ # path won't be executed.
+ if (utf8::is_utf8($str)) {
+ utf8::encode($str);
+ }
+
+ $str;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Plack^HWebGUI::Middleware::StackTrace - Displays stack trace when your app dies
+
+=head1 SYNOPSIS
+
+ enable "+WebGUI::Middleware::StackTrace";
+
+=head1 DESCRIPTION
+
+This middleware is a copy and modification of L, a
+middleware which catches exceptions (run-time errors) happening in your
+application and displays nice stack trace screen.
+This copy has been extended to display additional WebGUI specific information.
+
+You're recommended to use this middleware during the development and
+use L in the deployment mode as a
+replacement, so that all the exceptions thrown from your application
+still get caught and rendered as a 500 error response, rather than
+crashing the web server.
+
+Catching errors in streaming response is not supported.
+
+=head1 CONFIGURATION
+
+=over 4
+
+=item force
+
+ enable "+WebGUI::Middleware::StackTrace", force => 1;
+
+Force display the stack trace when an error occurs within your
+application and the response code from your application is
+500. Defaults to off.
+
+The use case of this option is that when your framework catches all
+the exceptions in the main handler and returns all failures in your
+code as a normal 500 PSGI error response. In such cases, this
+middleware would never have a chance to display errors because it
+can't tell if it's an application error or just random C in your
+code. This option enforces the middleware to display stack trace even
+if it's not the direct error thrown by the application.
+
+=item no_print_errors
+
+ enable "+WebGUI::Middleware::StackTrace", no_print_errors => 1;
+
+Skips printing the text stacktrace to console
+(C). Defaults to 0, which means the text version of the
+stack trace error is printed to the errors handle, which usually is a
+standard error.
+
+=back
+
+=head1 AUTHOR
+
+Tokuhiro Matsuno
+
+Tatsuhiko Miyagawa
+
+Scott Walters
+
+With code taken from:
+
+Tatsuhiko Miyagawa Emiyagawa@bulknews.netE
+
+Shawn M Moore
+
+HTML generation code is ripped off from L written by Tokuhiro Matsuno and Kazuho Oku.
+
+=head1 SEE ALSO
+
+L
+
+L L L
+
+=cut
+