1
0
mirror of https://github.com/golang/go synced 2024-11-19 12:34:47 -07:00
go/cmd/heapview/client/main.ts

196 lines
5.5 KiB
TypeScript
Raw Normal View History

x/tools/cmd/heapview: add basic client serving This change primarily exists to import Typescript and the ES6 module loader polyfill as dependencies for this project. Both dependencies are relatively lightweight and can be easily removed if we decide we don't need them. The module loader polyfill implements support for an upcoming browser feature in ES6 (the next version of JavaScript). This feature helps modularize Javascript code and conveniently split it into multiple files. It should be supported by the stable versions of the four major browsers (Chrome, Firefox, Safari and Edge) by the end of the year. Once that happens, we can remove the polyfill. The Typescript compiler provides two things: First, it compiles new, but not-yet-supported ES6 Javascript features into ES5. It also provides a typechecker similar to what Closure does, but types are indicated in syntax rather than JSDoc comments. If we decide we don't want this dependency, we can compile the Typescript code into human-readable JavaScript code. (The compiler basically strips out types and replaces ES6 language features with more well-supported JavaScript equivalents). The Typescript compiler is not required for development. typescript.js and a feature in the module loader will be used to compile Typescript into JavaScript at serving time. (We might want to do something different for the production version, but we can get to that later). The change also adds code to serve the HTML and Javascript files. Updates golang/go#16410 Change-Id: I42c669d1de636d8b221fc03ed22aa7ac60554610 Reviewed-on: https://go-review.googlesource.com/25240 Reviewed-by: Austin Clements <austin@google.com>
2016-07-26 08:27:44 -06:00
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/**
* An enum of types of actions that might be requested
* by the app.
*/
enum Action {
TOGGLE_SIDEBAR, // Toggle the sidebar.
NAVIGATE_ABOUT, // Go to the about page.
}
const TITLE = 'Go Heap Viewer';
/**
* A type of event that signals to the AppElement controller
* that something shoud be done. For the most part, the structure
* of the app will be that elements' state will mostly be controlled
* by parent elements. Elements will issue actions that the AppElement
* will handle, and the app will be re-rendered down the DOM
* hierarchy.
*/
class ActionEvent extends Event {
static readonly EVENT_TYPE = 'action-event'
constructor(public readonly action: Action) { super(ActionEvent.EVENT_TYPE); }
}
/**
* A hamburger menu element. Triggers a TOGGLE_SIDE action to toggle the
* sidebar.
*/
export class HamburgerElement extends HTMLElement {
static readonly NAME = 'heap-hamburger';
createdCallback() {
this.appendChild(document.createTextNode('☰'));
this.onclick =
() => { this.dispatchEvent(new ActionEvent(Action.TOGGLE_SIDEBAR)) };
}
}
document.registerElement(HamburgerElement.NAME, HamburgerElement);
/**
* A heading for the page with a hamburger menu and a title.
*/
export class HeadingElement extends HTMLElement {
static readonly NAME = 'heap-heading';
createdCallback() {
this.style.display = 'block';
this.style.backgroundColor = '#2196F3';
this.style.webkitUserSelect = 'none';
this.style.cursor = 'default';
this.style.color = '#FFFFFF';
this.style.padding = '10px';
const div = document.createElement('div');
div.style.margin = '0px';
div.style.fontSize = '2em';
div.appendChild(document.createElement(HamburgerElement.NAME));
div.appendChild(document.createTextNode(' ' + TITLE));
this.appendChild(div);
}
}
document.registerElement(HeadingElement.NAME, HeadingElement);
/**
* A sidebar that has navigation for the app.
*/
export class SidebarElement extends HTMLElement {
static readonly NAME = 'heap-sidebar';
createdCallback() {
this.style.display = 'none';
this.style.backgroundColor = '#9E9E9E';
this.style.width = '15em';
const aboutButton = document.createElement('button');
aboutButton.innerText = 'about';
aboutButton.onclick =
() => { this.dispatchEvent(new ActionEvent(Action.NAVIGATE_ABOUT)) };
this.appendChild(aboutButton);
}
toggle() {
this.style.display = this.style.display === 'none' ? 'block' : 'none';
}
}
document.registerElement(SidebarElement.NAME, SidebarElement);
/**
* A Container for the main content in the app.
* TODO(matloob): Implement main content.
*/
export class MainContentElement extends HTMLElement {
static readonly NAME = 'heap-container';
attachedCallback() {
this.style.backgroundColor = '#E0E0E0';
this.style.height = '100%';
this.style.flex = '1';
}
}
document.registerElement(MainContentElement.NAME, MainContentElement);
/**
* A container and controller for the whole app.
* Contains the heading, side drawer and main panel.
*/
class AppElement extends HTMLElement {
static readonly NAME = 'heap-app';
private sidebar: SidebarElement;
private mainContent: MainContentElement;
attachedCallback() {
document.title = TITLE;
this.addEventListener(
ActionEvent.EVENT_TYPE, e => this.handleAction(e as ActionEvent),
/* capture */ true);
this.render();
}
render() {
this.style.display = 'block';
this.style.height = '100vh';
this.style.width = '100vw';
this.appendChild(document.createElement(HeadingElement.NAME));
const bodyDiv = document.createElement('div');
bodyDiv.style.height = '100%';
bodyDiv.style.display = 'flex';
this.sidebar =
document.createElement(SidebarElement.NAME) as SidebarElement;
bodyDiv.appendChild(this.sidebar);
this.mainContent =
document.createElement(MainContentElement.NAME) as MainContentElement;
bodyDiv.appendChild(this.mainContent);
this.appendChild(bodyDiv);
this.renderRoute();
}
renderRoute() {
this.mainContent.innerHTML = ''
switch (window.location.pathname) {
case '/about':
this.mainContent.appendChild(
document.createElement(AboutPageElement.NAME));
break;
}
}
handleAction(event: ActionEvent) {
switch (event.action) {
case Action.TOGGLE_SIDEBAR:
this.sidebar.toggle();
break;
case Action.NAVIGATE_ABOUT:
window.history.pushState({}, '', '/about');
this.renderRoute();
break;
}
}
}
document.registerElement(AppElement.NAME, AppElement);
/**
* An about page.
*/
class AboutPageElement extends HTMLElement {
static readonly NAME = 'heap-about';
createdCallback() { this.textContent = TITLE; }
}
document.registerElement(AboutPageElement.NAME, AboutPageElement);
/**
* Resets body's margin and padding, and sets font.
*/
function clearStyle(document: Document) {
const styleElement = document.createElement('style') as HTMLStyleElement;
document.head.appendChild(styleElement);
const styleSheet = styleElement.sheet as CSSStyleSheet;
styleSheet.insertRule(
'* {font-family: Roboto,Helvetica; box-sizing: border-box}', 0);
styleSheet.insertRule('body {margin: 0px; padding:0px}', 0);
}
x/tools/cmd/heapview: add basic client serving This change primarily exists to import Typescript and the ES6 module loader polyfill as dependencies for this project. Both dependencies are relatively lightweight and can be easily removed if we decide we don't need them. The module loader polyfill implements support for an upcoming browser feature in ES6 (the next version of JavaScript). This feature helps modularize Javascript code and conveniently split it into multiple files. It should be supported by the stable versions of the four major browsers (Chrome, Firefox, Safari and Edge) by the end of the year. Once that happens, we can remove the polyfill. The Typescript compiler provides two things: First, it compiles new, but not-yet-supported ES6 Javascript features into ES5. It also provides a typechecker similar to what Closure does, but types are indicated in syntax rather than JSDoc comments. If we decide we don't want this dependency, we can compile the Typescript code into human-readable JavaScript code. (The compiler basically strips out types and replaces ES6 language features with more well-supported JavaScript equivalents). The Typescript compiler is not required for development. typescript.js and a feature in the module loader will be used to compile Typescript into JavaScript at serving time. (We might want to do something different for the production version, but we can get to that later). The change also adds code to serve the HTML and Javascript files. Updates golang/go#16410 Change-Id: I42c669d1de636d8b221fc03ed22aa7ac60554610 Reviewed-on: https://go-review.googlesource.com/25240 Reviewed-by: Austin Clements <austin@google.com>
2016-07-26 08:27:44 -06:00
export function main() {
clearStyle(document);
document.body.appendChild(document.createElement(AppElement.NAME));
}