| Index: pkg/analysis_server/tool/instrumentation/page/page_writer.dart
|
| diff --git a/pkg/analysis_server/tool/instrumentation/page/page_writer.dart b/pkg/analysis_server/tool/instrumentation/page/page_writer.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..492f86ac328dbcd2911f309c253a98e0865318a8
|
| --- /dev/null
|
| +++ b/pkg/analysis_server/tool/instrumentation/page/page_writer.dart
|
| @@ -0,0 +1,307 @@
|
| +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +import 'dart:convert';
|
| +
|
| +import '../log/log.dart';
|
| +import '../server.dart';
|
| +
|
| +typedef void Writer(StringSink sink);
|
| +
|
| +/**
|
| + * A class used to write an HTML page.
|
| + */
|
| +abstract class PageWriter {
|
| + /**
|
| + * The object used to escape special HTML characters.
|
| + */
|
| + static final HtmlEscape htmlEscape = new HtmlEscape();
|
| +
|
| + /**
|
| + * Initialize a newly create page writer.
|
| + */
|
| + PageWriter();
|
| +
|
| + /**
|
| + * Return the length of the common prefix for time stamps associated with the
|
| + * given log [entries].
|
| + */
|
| + int computePrefixLength(List<LogEntry> entries) {
|
| + int length = entries.length;
|
| + if (length < 2) {
|
| + return 0;
|
| + }
|
| + String firstTime = entries[0].timeStamp.toString();
|
| + String lastTime = entries[length - 1].timeStamp.toString();
|
| + int prefixLength = 0;
|
| + int timeLength = firstTime.length;
|
| + while (prefixLength < timeLength &&
|
| + firstTime.codeUnitAt(prefixLength) ==
|
| + lastTime.codeUnitAt(prefixLength)) {
|
| + prefixLength++;
|
| + }
|
| + return prefixLength;
|
| + }
|
| +
|
| + /**
|
| + * Return an escaped version of the given [unsafe] text.
|
| + */
|
| + String escape(String unsafe) {
|
| + return htmlEscape.convert(unsafe);
|
| + }
|
| +
|
| + /**
|
| + * Write the body of the page (without the 'body' tag) to the given [sink].
|
| + */
|
| + void writeBody(StringSink sink);
|
| +
|
| + /**
|
| + * Write the given [date] to the given [sink].
|
| + */
|
| + void writeDate(StringSink sink, DateTime date) {
|
| + String isoString = date.toIso8601String();
|
| + int index = isoString.indexOf('T');
|
| + String dateString = isoString.substring(0, index);
|
| + String timeString = isoString.substring(index + 1);
|
| + sink.write(dateString);
|
| + sink.write(' at ');
|
| + sink.write(timeString);
|
| + }
|
| +
|
| + /**
|
| + * Write the body of the page (without the 'body' tag) to the given [sink].
|
| + */
|
| + void writeMenu(StringSink sink) {
|
| + sink.writeln('<div class="menu">');
|
| + sink.write('<a href="${WebServer.logPath}" class="menuItem">Log</a>');
|
| + sink.write(' • ');
|
| + sink.write('<a href="${WebServer.statsPath}" class="menuItem">Stats</a>');
|
| + sink.writeln('</div>');
|
| + }
|
| +
|
| + /**
|
| + * Write the contents of the instrumentation log to the given [sink].
|
| + */
|
| + void writePage(StringSink sink) {
|
| + sink.writeln('<!DOCTYPE html>');
|
| + sink.writeln('<html lang="en-US">');
|
| + sink.writeln('<head>');
|
| + sink.writeln('<meta charset="utf-8">');
|
| + sink.writeln(
|
| + '<meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0">');
|
| + sink.writeln('<title>Instrumentation Log</title>');
|
| + sink.writeln('<style>');
|
| + writeStyleSheet(sink);
|
| + sink.writeln('</style>');
|
| + sink.writeln('<script>');
|
| + writeScripts(sink);
|
| + sink.writeln('</script>');
|
| + sink.writeln('</head>');
|
| + sink.writeln('<body>');
|
| + writeBody(sink);
|
| + sink.writeln('</body>');
|
| + sink.writeln('</html>');
|
| + }
|
| +
|
| + /**
|
| + * Write the scripts for the page (without the 'script' tag) to the given
|
| + * [sink].
|
| + */
|
| + void writeScripts(StringSink sink) {
|
| + // No common scripts.
|
| + }
|
| +
|
| + /**
|
| + * Write the content of the style sheet (without the 'script' tag) for the
|
| + * page to the given [sink].
|
| + */
|
| + void writeStyleSheet(StringSink sink) {
|
| + sink.writeln('a {');
|
| + sink.writeln(' color: #000000;');
|
| + sink.writeln(' text-decoration: none;');
|
| + sink.writeln('}');
|
| + sink.writeln('a.menuItem {');
|
| + sink.writeln(' font-weight: bold;');
|
| + sink.writeln('}');
|
| + sink.writeln('body {');
|
| + sink.writeln(' font-family: sans-serif;');
|
| + sink.writeln(' height: 100%;');
|
| + sink.writeln(' margin: 0px;');
|
| + sink.writeln(' overflow: hidden;');
|
| + sink.writeln(' padding: 0px;');
|
| + sink.writeln(' width: 100%;');
|
| + sink.writeln('}');
|
| + sink.writeln('div.columnHeader {');
|
| + sink.writeln('}');
|
| + sink.writeln('div.button {');
|
| + sink.writeln(' display: inline-block;');
|
| + sink.writeln(' border-radius: 4px;');
|
| + sink.writeln(' border: 1px solid;');
|
| + sink.writeln(' height: 16px;');
|
| + sink.writeln(' text-align: center;');
|
| + sink.writeln(' vertical-align: middle;');
|
| + sink.writeln(' width: 16px;');
|
| + sink.writeln('}');
|
| + sink.writeln('div.inset {');
|
| + sink.writeln(' padding: 10px;');
|
| + sink.writeln('}');
|
| + sink.writeln('div.menu {');
|
| + sink.writeln(' background-color: #cce6ff;');
|
| + sink.writeln(' padding: 5px;');
|
| + sink.writeln('}');
|
| + sink.writeln('html {');
|
| + sink.writeln(' height: 100%;');
|
| + sink.writeln(' width: 100%;');
|
| + sink.writeln('}');
|
| + sink.writeln('span.button {');
|
| + sink.writeln(' border-radius: 5px;');
|
| + sink.writeln(' border: 1px solid;');
|
| + sink.writeln(' height: 16px;');
|
| + sink.writeln(' width: 16px;');
|
| + sink.writeln('}');
|
| + sink.writeln('span.error {');
|
| + sink.writeln(' color: #ff0000;');
|
| + sink.writeln('}');
|
| + sink.writeln('span.gray {');
|
| + sink.writeln(' color: #777777;');
|
| + sink.writeln('}');
|
| + sink.writeln('span.label {');
|
| + sink.writeln(' font-weight: bold;');
|
| + sink.writeln('}');
|
| + sink.writeln('table.fullWidth {');
|
| + sink.writeln(' border: 0px;');
|
| + sink.writeln(' width: 100%;');
|
| + sink.writeln('}');
|
| + sink.writeln('td.halfWidth {');
|
| + sink.writeln(' width: 50%;');
|
| + sink.writeln(' vertical-align: top;');
|
| + sink.writeln('}');
|
| + sink.writeln('td.int {');
|
| + sink.writeln(' text-align: right;');
|
| + sink.writeln('}');
|
| + sink.writeln('th {');
|
| + sink.writeln(' text-align: left;');
|
| + sink.writeln('}');
|
| + sink.writeln('th.narrow {');
|
| + sink.writeln(' width: 16px;');
|
| + sink.writeln('}');
|
| +
|
| + sink.writeln('#container {');
|
| + sink.writeln(' height: 100%;');
|
| + sink.writeln(' min-height: 100%;');
|
| + sink.writeln(' position: relative;');
|
| + sink.writeln(' width: 100%;');
|
| + sink.writeln('}');
|
| + sink.writeln('#content {');
|
| + sink.writeln(' height: 90%;');
|
| + sink.writeln(' width: 100%;');
|
| + sink.writeln('}');
|
| + }
|
| +
|
| + /**
|
| + * Write to the given [sink] the HTML required to display content in two
|
| + * columns. The content of the columns will be written by the functions
|
| + * [writeLeftColumn], [writeCenterColumn] and [writeRightColumn] and will be
|
| + * contained in 'div' elements with the id's [leftColumnId], [centerColumnId]
|
| + * and [rightColumnId].
|
| + */
|
| + void writeThreeColumns(
|
| + StringSink sink,
|
| + String leftColumnId,
|
| + Writer writeLeftColumn,
|
| + String centerColumnId,
|
| + Writer writeCenterColumn,
|
| + String rightColumnId,
|
| + Writer writeRightColumn) {
|
| + sink.writeln('<div>');
|
| + sink.writeln(' <div>');
|
| + sink.writeln(' <div id="$leftColumnId">');
|
| + sink.writeln(' <div class="inset">');
|
| + writeLeftColumn(sink);
|
| + sink.writeln(' </div>');
|
| + sink.writeln(' </div>');
|
| + sink.writeln(' <div id="$rightColumnId">');
|
| + sink.writeln(' <div class="inset">');
|
| + writeRightColumn(sink);
|
| + sink.writeln(' </div>');
|
| + sink.writeln(' </div>');
|
| + sink.writeln(' <div id="$centerColumnId">');
|
| + sink.writeln(' <div class="inset">');
|
| + writeCenterColumn(sink);
|
| + sink.writeln(' </div>');
|
| + sink.writeln(' </div>');
|
| + sink.writeln(' </div>');
|
| + sink.writeln('</div>');
|
| + }
|
| +
|
| + /**
|
| + * Writeto the given [sink] the styles needed by a three column section where
|
| + * the columns have the ids [leftColumnId], [centerColumnId] and
|
| + * [rightColumnId].
|
| + */
|
| + void writeThreeColumnStyles(StringSink sink, String leftColumnId,
|
| + String centerColumnId, String rightColumnId) {
|
| + sink.writeln('#$leftColumnId {');
|
| + sink.writeln(' float: left;');
|
| + sink.writeln(' height: 100%;');
|
| + sink.writeln(' overflow: auto;');
|
| + sink.writeln(' width: 33%;');
|
| + sink.writeln('}');
|
| + sink.writeln('#$centerColumnId {');
|
| + sink.writeln(' height: 100%;');
|
| + sink.writeln(' overflow: auto;');
|
| + sink.writeln(' width: 33%;');
|
| + sink.writeln('}');
|
| + sink.writeln('#$rightColumnId {');
|
| + sink.writeln(' float: right;');
|
| + sink.writeln(' height: 100%;');
|
| + sink.writeln(' overflow: auto;');
|
| + sink.writeln(' width: 33%;');
|
| + sink.writeln('}');
|
| + }
|
| +
|
| + /**
|
| + * Write to the given [sink] the HTML required to display content in two
|
| + * columns. The content of the columns will be written by the functions
|
| + * [writeLeftColumn] and [writeRightColumn] and will be contained in 'div'
|
| + * elements with the id's [leftColumnId] and [rightColumnId].
|
| + */
|
| + void writeTwoColumns(StringSink sink, String leftColumnId,
|
| + Writer writeLeftColumn, String rightColumnId, Writer writeRightColumn) {
|
| + sink.writeln('<div>');
|
| + sink.writeln(' <div>');
|
| + sink.writeln(' <div id="$leftColumnId">');
|
| + sink.writeln(' <div class="inset">');
|
| + writeLeftColumn(sink);
|
| + sink.writeln(' </div>');
|
| + sink.writeln(' </div>');
|
| + sink.writeln(' <div id="$rightColumnId">');
|
| + sink.writeln(' <div class="inset">');
|
| + writeRightColumn(sink);
|
| + sink.writeln(' </div>');
|
| + sink.writeln(' </div>');
|
| + sink.writeln(' </div>');
|
| + sink.writeln('</div>');
|
| + }
|
| +
|
| + /**
|
| + * Writeto the given [sink] the styles needed by a two column section where
|
| + * the columns have the ids [leftColumnId] and [rightColumnId].
|
| + */
|
| + void writeTwoColumnStyles(
|
| + StringSink sink, String leftColumnId, String rightColumnId) {
|
| + sink.writeln('#$leftColumnId {');
|
| + sink.writeln(' float: left;');
|
| + sink.writeln(' height: 100%;');
|
| + sink.writeln(' overflow: auto;');
|
| + sink.writeln(' width: 50%;');
|
| + sink.writeln('}');
|
| + sink.writeln('#$rightColumnId {');
|
| + sink.writeln(' float: right;');
|
| + sink.writeln(' height: 100%;');
|
| + sink.writeln(' overflow: auto;');
|
| + sink.writeln(' width: 50%;');
|
| + sink.writeln('}');
|
| + }
|
| +}
|
|
|