From c96501e440a5da1f196232cf0e722708c2426447 Mon Sep 17 00:00:00 2001 From: Paul Cody Johnston Date: Mon, 20 Apr 2020 20:42:21 -0600 Subject: [PATCH 1/3] Refactor into core cycle-free module --- js/ui/BUILD | 38 +- js/ui/app.js | 38 +- js/ui/body.js | 8 +- js/ui/component.js | 35 +- js/ui/core.js | 880 +++++++++++++++++++++++++++++++++++++++++++ js/ui/history.js | 35 +- js/ui/markdown.js | 11 +- js/ui/menushield.js | 24 +- js/ui/route.js | 58 ++- js/ui/route/event.js | 28 -- js/ui/router.js | 21 +- js/ui/select.js | 31 +- js/ui/syntax.js | 6 +- js/ui/tab.js | 8 +- js/ui/tabevent.js | 14 +- js/ui/template.js | 5 +- 16 files changed, 1060 insertions(+), 180 deletions(-) create mode 100644 js/ui/core.js diff --git a/js/ui/BUILD b/js/ui/BUILD index 9a24bd9..9943851 100644 --- a/js/ui/BUILD +++ b/js/ui/BUILD @@ -3,13 +3,9 @@ package(default_visibility = ["//visibility:public"]) load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_binary", "closure_js_library", "closure_js_test") closure_js_library( - name = "component", + name = "core", srcs = [ - "app.js", - "component.js", - "route.js", - "route/event.js", - "router.js", + "core.js", ], deps = [ ":history", @@ -17,14 +13,16 @@ closure_js_library( ":injector", "@io_bazel_rules_closure//closure/library/asserts", "@io_bazel_rules_closure//closure/library/dom", - "@io_bazel_rules_closure//closure/library/events:event", + "@io_bazel_rules_closure//closure/library/events", "@io_bazel_rules_closure//closure/library/events:eventhandler", "@io_bazel_rules_closure//closure/library/events:eventtarget", "@io_bazel_rules_closure//closure/library/fx:dom", "@io_bazel_rules_closure//closure/library/fx:easing", + "@io_bazel_rules_closure//closure/library/history:event", "@io_bazel_rules_closure//closure/library/history:eventtype", "@io_bazel_rules_closure//closure/library/object", "@io_bazel_rules_closure//closure/library/promise", + "@io_bazel_rules_closure//closure/library/promise:resolver", "@io_bazel_rules_closure//closure/library/string", "@io_bazel_rules_closure//closure/library/style", "@io_bazel_rules_closure//closure/library/ui:component", @@ -46,6 +44,7 @@ closure_js_library( "@io_bazel_rules_closure//closure/library/events:event", "@io_bazel_rules_closure//closure/library/events:eventtarget", "@io_bazel_rules_closure//closure/library/events:eventtype", + "@io_bazel_rules_closure//closure/library/history:event", "@io_bazel_rules_closure//closure/library/history:eventtype", "@io_bazel_rules_closure//closure/library/history:html5history", "@io_bazel_rules_closure//closure/library/string", @@ -71,8 +70,9 @@ closure_js_library( "template.js", ], deps = [ - ":component", + ":core", "@io_bazel_rules_closure//closure/library/soy", + "@io_bazel_rules_closure//closure/library/dom", ], ) @@ -85,7 +85,7 @@ closure_js_library( "tabs.js", ], deps = [ - ":component", + ":core", "@io_bazel_rules_closure//closure/library/asserts", "@io_bazel_rules_closure//closure/library/dom", "@io_bazel_rules_closure//closure/library/dom:classlist", @@ -105,7 +105,9 @@ closure_js_library( "@io_bazel_rules_closure//closure/library/dom", "@io_bazel_rules_closure//closure/library/math:coordinate", "@io_bazel_rules_closure//closure/library/style", + "@io_bazel_rules_closure//closure/library/events", "@io_bazel_rules_closure//closure/library/ui:component", + "@io_bazel_rules_closure//closure/library/ui:container", "@io_bazel_rules_closure//closure/library/ui:menu", "@io_bazel_rules_closure//closure/library/ui:menubutton", "@io_bazel_rules_closure//closure/library/ui:submenu", @@ -119,20 +121,12 @@ closure_js_library( "syntax.js", ], deps = [ - ":component", + ":core", "@io_bazel_rules_closure//closure/library/asserts", "@io_bazel_rules_closure//closure/library/dom", ], ) -# closure_js_library( -# name = "app", -# srcs = [ -# ], -# deps = [ -# ":component", -# ], -# ) closure_js_library( name = "injector", @@ -140,17 +134,15 @@ closure_js_library( "injector.js", ], deps = [ - # ":component", + # ":core", ], ) closure_js_library( name = "ui", - # srcs = [ - # ], exports = [ ":injector", - ":component", + ":core", ":history", ":keyboard", ":menushield", @@ -185,7 +177,7 @@ closure_js_test( ], entry_points = ["goog:stack.ui.RouteTest"], deps = [ - ":component", + ":core", ":select", ":app", # "@io_bazel_rules_closure//closure/library", diff --git a/js/ui/app.js b/js/ui/app.js index d0599c4..126b33c 100644 --- a/js/ui/app.js +++ b/js/ui/app.js @@ -2,14 +2,16 @@ goog.module('stack.ui.App'); const BzlHistory = goog.require('stack.ui.History'); const Component = goog.require('stack.ui.Component'); -const HEventType = goog.require('goog.history.EventType'); -const Injector = goog.require('stack.ui.Injector'); +const HistoryEvent = goog.require('goog.history.Event'); +const HistoryEventType = goog.require('goog.history.EventType'); +const Injector = goog.require('stack.ui.Injector'); const Keyboard = goog.require('stack.ui.Keyboard'); -const Promise_ = goog.require('goog.Promise'); -const Router = goog.require('stack.ui.Router'); -const asserts = goog.require('goog.asserts'); -const dom = goog.require('goog.dom'); -const objects = goog.require('goog.object'); +const Promise_ = goog.require('goog.Promise'); +const Route = goog.require('stack.ui.Route'); +const Router = goog.require('stack.ui.Router'); +const asserts = goog.require('goog.asserts'); +const dom = goog.require('goog.dom'); +const objects = goog.require('goog.object'); class App extends Component { @@ -25,7 +27,7 @@ class App extends Component { * @type {!Injector} */ this.injector_ = new Injector(); - + /** * A registry of components that can be accessed by a common name. * @const @private @@ -35,7 +37,7 @@ class App extends Component { /** @const @private @type {!BzlHistory} */ this.history_ = new BzlHistory(); - this.getHandler().listen(this.history_, HEventType.NAVIGATE, this.handleHistoryNavigate); + this.getHandler().listen(this.history_, HistoryEventType.NAVIGATE, this.handleHistoryNavigate); this.registerDisposable(this.history_); /** @const @private @type {!Keyboard} */ @@ -50,16 +52,16 @@ class App extends Component { start() { this.history_.setEnabled(true); } - + /** - * @param {!goog.history.Event} e + * @param {!HistoryEvent} e */ handleHistoryNavigate(e) { this.router_.go(e.token).thenCatch(err => { console.warn(`Routing failure while nagivating to ${e.token}`); }); } - + /** * @param {!Component} c * @param {!boolean} b @@ -71,14 +73,14 @@ class App extends Component { console.warn("Stop Loaded " + c.getPathUrl()); } } - + /** * @return {!Keyboard} */ getKbd() { return this.kbd_; } - + /** * @return {!Router} */ @@ -92,7 +94,7 @@ class App extends Component { getInjector() { return this.injector_; } - + /** * @param {string} msg */ @@ -138,8 +140,8 @@ class App extends Component { //route.touch(this); super.go(route); } - - /** @param {!stack.ui.Route} route */ + + /** @param {!Route} route */ handle404(route) { this.notifyError("404 (Not Found): " + route.getPath()); } @@ -157,7 +159,7 @@ class App extends Component { * will loopback on this object to the go() method. * * @param {string} path - * @return {!Promise_} + * @return {!Promise_} */ route(path) { return this.router_.go(path).thenCatch(err => { diff --git a/js/ui/body.js b/js/ui/body.js index a142c77..ea09eee 100644 --- a/js/ui/body.js +++ b/js/ui/body.js @@ -10,14 +10,14 @@ const soy = goog.require('goog.soy'); class Body extends Select { /** - * @param {?goog.dom.DomHelper=} opt_domHelper + * @param {?dom.DomHelper=} opt_domHelper */ constructor(opt_domHelper) { super(opt_domHelper); this.addTab('home', new Home()); this.addTab('search', new List()); } - + /** * Modifies behavior to use touch rather than progress to * not advance the path pointer. @@ -38,7 +38,7 @@ class Body extends Select { goHere(route) { this.select('home', route.add('home')); } - + /** * @override */ @@ -55,7 +55,7 @@ class Body extends Select { super.enterDocument(); this.addChild(new Menu(this.getTabStrict('search'), this.getDomHelper()), true); } - + } exports = Body; diff --git a/js/ui/component.js b/js/ui/component.js index 31c8edf..b84aaa4 100644 --- a/js/ui/component.js +++ b/js/ui/component.js @@ -6,7 +6,8 @@ goog.module('stack.ui.Component'); const BgColorTransform = goog.require('goog.fx.dom.BgColorTransform'); const ComponentEventType = goog.require('goog.ui.Component.EventType'); const GoogUiComponent = goog.require('goog.ui.Component'); -const Route = goog.require('stack.ui.Route'); +const GoogUiControl = goog.require('goog.ui.Control'); +// const Route = goog.require('stack.ui.Route'); const asserts = goog.require('goog.asserts'); const easing = goog.require('goog.fx.easing'); const strings = goog.require('goog.string'); @@ -18,7 +19,7 @@ const style = goog.require('goog.style'); class Component extends GoogUiComponent { /** - * @param {?goog.dom.DomHelper=} opt_domHelper + * @param {?dom.DomHelper=} opt_domHelper */ constructor(opt_domHelper) { super(opt_domHelper); @@ -65,8 +66,8 @@ class Component extends GoogUiComponent { var name = current.getName(); if (name) { path.push(name); - // } else { - // console.log('path: no name', current); + // } else { + // console.log('path: no name', current); } current = current.parent(); } @@ -111,10 +112,10 @@ class Component extends GoogUiComponent { } /** - * @return {?stack.ui.Component} + * @return {?Component} */ parent() { - return /** @type {?stack.ui.Component} */ ( + return /** @type {?Component} */ ( this.getParent() ); } @@ -165,30 +166,30 @@ class Component extends GoogUiComponent { /** * @param {string} id - * @return {?stack.ui.Component} + * @return {?Component} */ child(id) { - return /** @type {?stack.ui.Component} */ ( + return /** @type {?Component} */ ( this.getChild(id) ); } /** * @param {number} index - * @return {!stack.ui.Component} + * @return {!Component} */ childAt(index) { - return /** @type {!stack.ui.Component} */ ( + return /** @type {!Component} */ ( asserts.assertObject(this.getChildAt(index)) ); } /** * @param {string} id - * @return {!stack.ui.Component} + * @return {!Component} */ strictchild(id) { - return /** @type {!stack.ui.Component} */ ( + return /** @type {!Component} */ ( asserts.assertObject(this.getChild(id)) ); } @@ -196,10 +197,10 @@ class Component extends GoogUiComponent { /** * Return the root component. * - * @return {!stack.ui.Component} + * @return {!Component} */ getRoot() { - /** @type {?stack.ui.Component} */ + /** @type {?Component} */ let current = this; while (current) { if (!current.parent()) { @@ -217,7 +218,7 @@ class Component extends GoogUiComponent { return /** @type {!stack.ui.App} */ (this.getRoot()); } - + /** * Default is no-op. */ @@ -260,7 +261,7 @@ class Component extends GoogUiComponent { * @param {number=} opt_time Length of animation in milliseconds. * @param {?Function=} opt_accel Acceleration function, returns 0-1 for inputs 0-1. * @param {?Element=} opt_element Dom Node to be used in the animation. - * @param {?goog.events.EventHandler=} opt_eventHandler Optional event handler + * @param {?events.EventHandler=} opt_eventHandler Optional event handler * to use when listening for events. */ bgColorFadeIn(opt_start, opt_end, opt_time, opt_accel, opt_element, opt_eventHandler) { @@ -296,7 +297,7 @@ class Component extends GoogUiComponent { } /** - * @return {?Array} + * @return {?Array} */ getMenuItems() { return null; diff --git a/js/ui/core.js b/js/ui/core.js new file mode 100644 index 0000000..e3007d0 --- /dev/null +++ b/js/ui/core.js @@ -0,0 +1,880 @@ +/** + * @fileoverview + */ +goog.module('stack.ui'); + +const BgColorTransform = goog.require('goog.fx.dom.BgColorTransform'); +const ComponentEventType = goog.require('goog.ui.Component.EventType'); +const EventHandler = goog.require('goog.events.EventHandler'); +const EventTarget = goog.require('goog.events.EventTarget'); +const GoogPromise = goog.require('goog.Promise'); +const GoogUiComponent = goog.require('goog.ui.Component'); +const GoogUiControl = goog.require('goog.ui.Control'); +const HistoryEvent = goog.require('goog.history.Event'); +const HistoryEventType = goog.require('goog.history.EventType'); +const History_ = goog.require('stack.ui.History'); +const Injector = goog.require('stack.ui.Injector'); +const Keyboard = goog.require('stack.ui.Keyboard'); +const Resolver = goog.require('goog.promise.Resolver'); +const asserts = goog.require('goog.asserts'); +const dom = goog.require('goog.dom'); +const easing = goog.require('goog.fx.easing'); +const events = goog.require('goog.events'); +const objects = goog.require('goog.object'); +const strings = goog.require('goog.string'); +const style = goog.require('goog.style'); + + +/** + * A route is a segment of paths and a collection of a components that + * have traversed along it. + */ +class Route extends EventTarget { + + /** + * @param {!Array} path + */ + constructor(path) { + super(); + + /** @const @private @type {!Array} */ + this.path_ = asserts.assertArray(path); + + /** @private @type {number} */ + this.index_ = 0; + + /** @private @type {!Array} */ + this.progress_ = []; + + /** @private @type {string} */ + this.state_ = RouteEventType.PROGRESS; + + /** @private @type {string|undefined} */ + this.failReason_ = undefined; + + /** @const @private @type {!Resolver} */ + this.resolver_ = GoogPromise.withResolver(); + + } + + /** + * @return {!GoogPromise} + */ + getPromise() { + return this.resolver_.promise; + } + + /** + * @return {number} + */ + size() { + return this.path_.length; + } + + /** + * @return {number} + */ + index() { + return this.index_; + } + + /** + * @return {!Array} + */ + path() { + return this.path_; + } + + /** + * Get the path segment at the given index. + * + * @param {number} index + * @return {?string} + */ + at(index) { + return this.path_[index] || null; + } + + /** + * Get the path segment at the given index. + * + * @param {number} n + * @return {!Route} + */ + advance(n) { + this.index_ += n; + return this; + } + + /** + * Add a path segment to the end of the route. + * + * @param {string} segment + * @return {!Route} + */ + add(segment) { + this.path_.push(segment); + return this; + } + + /** + * Get the indexed progress component or the last one if not set. + * + * @param {?number=} index + * @return {?Component} + */ + get(index) { + index = typeof index === "number" ? index : this.index_ - 1; + return this.progress_[index] || null; + } + + /** + * @return {string} + */ + getPath() { + return this.path_.join('/'); + } + + /** + * @param {?number=} opt_max + * @return {!Array} + */ + unmatchedPath(opt_max) { + const size = this.size(); + const end = typeof opt_max === "number" ? this.index_ + opt_max : size; + return this.path_.slice(this.index_, end); + } + + /** + * Return a slice of the original array corresponding to the + * segments that matched (as determined by progress). + * + * @return {!Array} + */ + matchedPath() { + return this.path_.slice(0, this.index_); + } + + /** Get the current path segment. + * @return {string} + */ + peek() { + return this.path_[this.index_]; + } + + /** + * @return {boolean} + */ + atEnd() { + return this.index_ >= this.path_.length; + } + + /** + * @return {boolean} + */ + inProgress() { + return this.state_ == RouteEventType.PROGRESS; + } + + /** + * @return {boolean} + */ + didFail() { + return this.state_ === RouteEventType.FAIL || this.state_ === RouteEventType.TIMEOUT; + } + + /** + * @return {string|undefined} + */ + getFailReason() { + return this.failReason_; + } + + /** + * @throws {Error} + */ + assertInProgress() { + asserts.assert(this.inProgress(), 'Expected in-progress, but the route state was: ' + this.state_); + } + + /** + * Record a non-contributing hop along the path, used mainly + * for debugging. + * @param {!Component} component + */ + touch(component) { + this.notifyEvent(RouteEventType.TOUCH, component); + } + + /** + * Trigger a timeout on the route. + */ + timeout() { + this.state_ = RouteEventType.TIMEOUT; + this.failReason_ = 'Timeout while navigating to ' + this.getPath(); + this.notifyEvent(RouteEventType.TIMEOUT, this.progress_[this.progress_.length - 1]); + this.resolver_.reject(this); + } + + /** + * @param {!Component} component + */ + progress(component) { + this.assertInProgress(); + var index = this.index_++; + this.progress_[index] = component; + component.show(); + this.notifyEvent(RouteEventType.PROGRESS, component); + } + + /** + * @param {!Component} component + */ + done(component) { + this.state_ = RouteEventType.DONE; + this.notifyEvent(RouteEventType.DONE, component); + this.resolver_.resolve(this); + } + + /** + * @param {!Component} component + * @param {string=} opt_reason + */ + fail(component, opt_reason) { + this.state_ = RouteEventType.FAIL; + this.failReason_ = opt_reason || 'No route to ' + this.getPath(); + this.notifyEvent(RouteEventType.FAIL, component); + this.resolver_.reject(this); + } + + /** + * @param {string} type + * @param {?Component} component + */ + notifyEvent(type, component) { + this.dispatchEvent(new RouteEvent(type, this, component)); + } + + /** @override */ + disposeInternal() { + super.disposeInternal(); + delete this.progress_; + } + +} + +exports.Route = Route; + +/** + * @enum {string} + */ +const RouteEventType = { + DONE: 'done', + FAIL: 'fail', + PROGRESS: 'progress', + TOUCH: 'touch', + TIMEOUT: 'timeout' +}; + +exports.RouteEventType = RouteEventType; + +/** + * Subclass of Event that holds a reference to the route in plays. + */ +class RouteEvent extends events.Event { + + /** + * Event class for routing. + * + * @param {string} type Event Type. + * @param {!Route} target Reference to the initiating route. + * @param {?Component=} component The component relevant to the event. + */ + constructor(type, target, component) { + super(type, target); + + /** + * @type {!Route} + */ + this.route = target; + + /** + * @type {?Component|undefined} + */ + this.component = component; + } + +} + +exports.RouteEvent = RouteEvent; + + +/** + * Manages a current route in-progress. Fires + * goog.ui.Component.EventType.ACTION when a now route is created. + */ +class Router extends EventTarget { + + /** + * @param {!Component} root + */ + constructor(root) { + super(); + + /** + * @const @private + * @type {!EventHandler} + */ + this.handler_ = new EventHandler(this); + + /** + * The root component to start. + * @const @private + * @type {!Component} + */ + this.root_ = root; + + /** + * A route in-progress. + * @private + * @type {?Route} + */ + this.route_ = null; + + /** + * Strict mode means that an existing route that hasn't finished yet will fail a new attempt. + * @private + * @type {boolean} + */ + this.strict_ = true; + } + + /** + * Get the current route if it exists. + * + * @return {?Route} + */ + getCurrentRoute() { + return this.route_; + } + + /** + * Set the strict mode + * @param {boolean} b + */ + setStrict(b) { + this.strict_ = b; + } + + /** + * Get a component if registered. + *i + * @param {string} path + * @return {!GoogPromise} + */ + go(path) { + //console.log('go: ' + path); + asserts.assertString(path, 'Routing path must be a string'); + if (this.strict_ && this.route_) { + console.warn(`cannot route to ${path} due to existing route "${this.route_.matchedPath()}" --> "${this.route_.unmatchedPath()}"`); + return GoogPromise.reject( + 'Already routing to ' + this.route_.getPath() + ); + } + + // Remove empty path segments + const list = path.split('/').filter(s => s.trim() !== ''); + list.unshift(''); // prepend empty segment for the root component to consume + var route = new Route(list); + this.listenRoute(route); + + this.dispatchEvent(new RouteEvent( + ComponentEventType.ACTION, + route + )); + + this.root_.go(route); + + // Set a backup timer to reset the route if not completed in time. + setTimeout(() => { + if (route.inProgress()) { + route.timeout(); + } + }, 100000); + + return route.getPromise(); + } + + /** @param {!RouteEvent} e */ + handleProgress(e) { + this.dispatchEvent(e); + } + + /** @param {!RouteEvent} e */ + handleDone(e) { + this.dispatchEvent(e); + this.unlistenRoute(); + } + + /** @param {!RouteEvent} e */ + handleFail(e) { + this.dispatchEvent(e); + const target = /** @type {!Route} */(e.target); + this.unlistenRoute(); + } + + /** @param {!RouteEvent} e */ + handleTimeout(e) { + this.unlistenRoute(); + } + + /** @param {!Route} route */ + listenRoute(route) { + var handler = this.handler_; + handler.listenWithScope(route, RouteEventType.PROGRESS, this.handleProgress, false, this); + handler.listenWithScope(route, RouteEventType.DONE, this.handleDone, false, this); + handler.listenWithScope(route, RouteEventType.FAIL, this.handleFail, false, this); + handler.listenWithScope(route, RouteEventType.TIMEOUT, this.handleTimeout, false, this); + this.route_ = route; + } + + unlistenRoute() { + var route = this.route_; + this.route_ = null; + var handler = this.handler_; + handler.unlisten(route, RouteEventType.PROGRESS, this.handleProgress, false, this); + handler.unlisten(route, RouteEventType.DONE, this.handleDone, false, this); + handler.unlisten(route, RouteEventType.FAIL, this.handleFail, false, this); + handler.unlisten(route, RouteEventType.TIMEOUT, this.handleTimeout, false, this); + } + + /** @override */ + disposeInternal() { + super.disposeInternal(); + delete this.route_; + } + +} + +exports.Router = Router; + + +/** + * A component that adds routing capabilities. + */ +class Component extends GoogUiComponent { + + /** + * @param {?dom.DomHelper=} opt_domHelper + */ + constructor(opt_domHelper) { + super(opt_domHelper); + + /** @private @type {?string} */ + this.name_ = null; + + /** @private @type {?BgColorTransform} */ + this.fx_ = null; + } + + /** + * @param {string} name + */ + setName(name) { + this.name_ = name; + } + + /** + * @return {?string} + */ + getName() { + return this.name_; + } + + /** + * @param {string} name + * @return {!Node} + */ + getComponentLabel(name) { + if (name) { + name = strings.capitalize(name); + } + return this.getDomHelper().createTextNode(name); + } + + /** + * @return {!Array} + */ + getPath() { + var current = this; + var path = []; + while (current) { + var name = current.getName(); + if (name) { + path.push(name); + } + current = current.parent(); + } + path.reverse(); + return path; + } + + /** + * @return {string} + */ + getPathUrl() { + return this.getPath().join('/'); + } + + /** + * @param {!Route} route + */ + go(route) { + route.progress(this); + if (route.atEnd()) { + this.goHere(route); + } else { + this.goDown(route); + } + } + + /** + * @param {!Route} route + */ + goHere(route) { + this.show(); + route.done(this); + } + + /** + * @param {!Route} route + */ + goDown(route) { + route.fail(this); + } + + /** + * @return {?Component} + */ + parent() { + return /** @type {?Component} */ ( + this.getParent() + ); + } + + /** + * Callback function that bubbles up the active component along the component + * hairarachy. + * @param {!Component} target + */ + handleComponentActive(target) { + const parent = this.parent(); + if (parent) { + parent.handleComponentActive(target); + } + } + + /** + * @param {string} id + * @return {?Component} + */ + child(id) { + return /** @type {?Component} */ ( + this.getChild(id) + ); + } + + /** + * @param {number} index + * @return {!Component} + */ + childAt(index) { + return /** @type {!Component} */ ( + asserts.assertObject(this.getChildAt(index)) + ); + } + + /** + * @param {string} id + * @return {!Component} + */ + strictchild(id) { + return /** @type {!Component} */ ( + asserts.assertObject(this.getChild(id)) + ); + } + + /** + * Return the root component. + * + * @return {!Component} + */ + getRoot() { + /** @type {?Component} */ + let current = this; + while (current) { + if (!current.parent()) { + return current; + } + current = current.parent(); + } + throw new ReferenceError('Root reference not available'); + } + + /** + * @return {!stack.ui.App} + */ + getApp() { + return /** @type {!stack.ui.App} */ (this.getRoot()); + } + + /** + * Default is no-op. + */ + focus() { + } + + /** + * Show this component. + */ + show() { + style.setElementShown(this.getShowHideElement(), true); + this.dispatchEvent(ComponentEventType.SHOW); + } + + /** + * Flash this component. + */ + flash() { + style.setElementShown(this.getShowHideElement(), true); + } + + /** + * Hide this component. + */ + hide() { + style.setElementShown(this.getShowHideElement(), false); + this.dispatchEvent(ComponentEventType.HIDE); + } + + /** + * @return {!Element} + */ + getShowHideElement() { + return this.getElementStrict(); + } + + /** + * @param {!Array=} opt_start 3D Array for RGB of start color. + * @param {!Array=} opt_end 3D Array for RGB of end color. + * @param {number=} opt_time Length of animation in milliseconds. + * @param {?Function=} opt_accel Acceleration function, returns 0-1 for inputs 0-1. + * @param {?Element=} opt_element Dom Node to be used in the animation. + * @param {?events.EventHandler=} opt_eventHandler Optional event handler + * to use when listening for events. + */ + bgColorFadeIn(opt_start, opt_end, opt_time, opt_accel, opt_element, opt_eventHandler) { + var fx = this.fx_; + if (fx) { + fx.stop(); + fx.dispose(); + } + + var start = opt_start || [128, 128, 128]; + var end = opt_end || [256, 256, 256]; + var time = opt_time || 250; + var accel = opt_accel || easing.easeOutLong; + var element = opt_element || asserts.assertElement(this.getContentElement()); + + fx = this.fx_ = + new BgColorTransform(element, start, end, time, accel); + + fx.play(); + } + + /** + * @param {string} src + */ + setBackgroundImage(src) { + var style = this.getContentElement().style; + var url = `url(${src})`; + style.backgroundImage = url; + style.backgroundSize = 'cover'; + style.backgroundPosition = 'center center'; + style.height = '100%'; + } + + /** + * @return {?Array} + */ + getMenuItems() { + return null; + } + +} + +exports.Component = Component; + +class App extends Component { + + /** + * @param {?dom.DomHelper=} opt_domHelper + */ + constructor(opt_domHelper) { + super(opt_domHelper); + + /** + * @const @private + * @type {!Injector} + */ + this.injector_ = new Injector(); + + /** + * A registry of components that can be accessed by a common name. + * @const @private + * @type {!Object} + */ + this.components_ = {}; + + /** @const @private @type {!History_} */ + this.history_ = new History_(); + this.getHandler().listen(this.history_, HistoryEventType.NAVIGATE, this.handleHistoryNavigate); + this.registerDisposable(this.history_); + + /** @const @private @type {!Keyboard} */ + this.kbd_ = new Keyboard(); + this.registerDisposable(this.kbd_); + + /** @const @private @type {!Router} */ + var router = this.router_ = new Router(this, this.history_); + this.registerDisposable(router); + } + + start() { + this.history_.setEnabled(true); + } + + /** + * @param {!HistoryEvent} e + */ + handleHistoryNavigate(e) { + this.router_.go(e.token).thenCatch(err => { + console.warn(`Routing failure while nagivating to ${e.token}`); + }); + } + + /** + * @param {!Component} c + * @param {!boolean} b + */ + setLoading(c, b) { + if (b) { + console.warn("Starting Loading " + c.getPathUrl()); + } else { + console.warn("Stop Loaded " + c.getPathUrl()); + } + } + + /** + * @return {!Keyboard} + */ + getKbd() { + return this.kbd_; + } + + /** + * @return {!Router} + */ + getRouter() { + return this.router_; + } + + /** + * @return {!Injector} + */ + getInjector() { + return this.injector_; + } + + /** + * @param {string} msg + */ + notifyError(msg) { + console.error(msg); + } + + /** + * Register a component, only required if it wants to expose itself + * via the main app registry. + * + * @param {string} name + * @param {!Component} c + */ + registerComponent(name, c) { + var map = this.components_; + if (map[name]) { + throw new Error('Duplicate component registration: ' + name); + } + map[name] = c; + } + + /** + * Get a component if registered. + * + * @param {string} name + * @return {!Component} + */ + getComponent(name) { + return asserts.assertObject(this.components_[name]); + } + + /** @override */ + go(route) { + //route.touch(this); + super.go(route); + } + + /** @param {!Route} route */ + handle404(route) { + this.notifyError("404 (Not Found): " + route.getPath()); + } + + /** + * Get the header component. + * @return {!Component} + */ + getHeader() { + return this.getComponent('header'); + } + + /** + * Route to the given path. This is delegated to the router, which + * will loopback on this object to the go() method. + * + * @param {string} path + * @return {!GoogPromise} + */ + route(path) { + return this.router_.go(path).thenCatch(err => { + console.log(`Routing failure while routing to ${path}`); + }); + } + + /** + * @param {!Array} path + */ + setLocation(path) { + //console.log('setLocation', path); + this.history_.setLocation(path.join('/')); + } + + /** @override */ + disposeInternal() { + super.disposeInternal(); + objects.clear(this.components_); + } + +} + +exports.App = App; + diff --git a/js/ui/history.js b/js/ui/history.js index 6cc047b..462dd08 100644 --- a/js/ui/history.js +++ b/js/ui/history.js @@ -3,16 +3,17 @@ */ goog.module('stack.ui.History'); -const EventTarget = goog.require('goog.events.EventTarget'); -const EventType = goog.require('goog.events.EventType'); -//const HEvent = goog.require('stack.ui.history.Event'); -const HEventType = goog.require('goog.history.EventType'); -const Html5History = goog.require('goog.history.Html5History'); -const TagName = goog.require('goog.dom.TagName'); -const asserts = goog.require('goog.asserts'); -const dom = goog.require('goog.dom'); -const events = goog.require('goog.events'); -const strings = goog.require('goog.string'); +const EventTarget = goog.require('goog.events.EventTarget'); +const EventType = goog.require('goog.events.EventType'); +// const HEvent = goog.require('stack.ui.history.Event'); +const HistoryEvent = goog.require('goog.history.Event'); +const HistoryEventType = goog.require('goog.history.EventType'); +const Html5History = goog.require('goog.history.Html5History'); +const TagName = goog.require('goog.dom.TagName'); +const asserts = goog.require('goog.asserts'); +const dom = goog.require('goog.dom'); +const events = goog.require('goog.events'); +const strings = goog.require('goog.string'); /** * Maintains the history and listens for click events. Fires a @@ -33,7 +34,7 @@ class History extends EventTarget { var history = this.history_ = new Html5History(); history.setUseFragment(false); - events.listen(history, HEventType.NAVIGATE, this.handleNavigate.bind(this)); + events.listen(history, HistoryEventType.NAVIGATE, this.handleNavigate.bind(this)); events.listen(goog.global.document, EventType.CLICK, this.handleDocumentClick.bind(this)); } @@ -43,7 +44,7 @@ class History extends EventTarget { setEnabled(b) { this.history_.setEnabled(b); } - + /** * @param {!events.BrowserEvent} e */ @@ -54,8 +55,8 @@ class History extends EventTarget { // look up through the ancestry chain. let anchor = /** @type {?HTMLAnchorElement} */ ( dom.getAncestor(asserts.assertElement(e.target), - el => el instanceof HTMLElement && el.tagName === TagName.A.toString(), - true) + el => el instanceof HTMLElement && el.tagName === TagName.A.toString(), + true) ); if (!anchor) { return; @@ -74,7 +75,7 @@ class History extends EventTarget { const href = anchor.href.replace("/#/", "/"); window.open(href, "_blank"); return; - } + } hash = hash.substring(2); //this.history_.replaceToken(hash); //this.replaceToken(hash); @@ -93,7 +94,7 @@ class History extends EventTarget { console.log('Replace token', token); this.history_.replaceToken(token); } - + /** * @param {string} token */ @@ -102,7 +103,7 @@ class History extends EventTarget { } /** - * @param {!goog.history.Event} e + * @param {!HistoryEvent} e */ handleNavigate(e) { var target = this.history_.getToken(); diff --git a/js/ui/markdown.js b/js/ui/markdown.js index 08d8cc4..18d718d 100644 --- a/js/ui/markdown.js +++ b/js/ui/markdown.js @@ -3,8 +3,9 @@ */ goog.module('stack.ui.Markdown'); -const Component = goog.require('stack.ui.Component'); const dom = goog.require('goog.dom'); +const { Component } = goog.require('stack.ui'); + /** * A template that does marked rendering from a soy template. @@ -28,7 +29,7 @@ class Markdown extends Component { createDom() { this.setElementInternal(this.getDomHelper().createDom(dom.TagName.DIV, 'markdown-body')); } - + /** * @override */ @@ -46,8 +47,8 @@ class Markdown extends Component { this.renderMarkdown(); } } - - + + /** * Convert text to markdown and set as innerHTML * @suppress {reportUnknownTypes} @@ -65,7 +66,7 @@ class Markdown extends Component { console.warn('markdown error', err); } } - + } exports = Markdown; diff --git a/js/ui/menushield.js b/js/ui/menushield.js index 45cf5c2..8ce3808 100644 --- a/js/ui/menushield.js +++ b/js/ui/menushield.js @@ -1,18 +1,20 @@ goog.module('stack.ui.MenuShield'); const Component = goog.require('goog.ui.Component'); +const Container = goog.require('goog.ui.Container'); const Coordinate = goog.require('goog.math.Coordinate'); const Menu = goog.require('goog.ui.Menu'); const MenuButton = goog.require('goog.ui.MenuButton'); const SubMenu = goog.require('goog.ui.SubMenu'); const asserts = goog.require('goog.asserts'); const dom = goog.require('goog.dom'); +const events = goog.require('goog.events'); const style = goog.require('goog.style'); class MenuShield extends Component { - + /** - * @param {!goog.ui.Container} menuBar + * @param {!Container} menuBar * @param {?Map=} opt_menuButtons * @param {?dom.DomHelper=} opt_domHelper */ @@ -21,8 +23,8 @@ class MenuShield extends Component { /** * @const @private - * @type {!goog.ui.Container} - */ + * @type {!Container} + */ this.menuBar_ = menuBar; /** @@ -30,7 +32,7 @@ class MenuShield extends Component { * * @const @private * @type {!Map} - */ + */ this.menuButtons_ = opt_menuButtons || new Map(); } @@ -66,21 +68,21 @@ class MenuShield extends Component { Component.EventType.HIDE ], this.handleMenuEvent); } - + /** - * @param {!goog.events.Event} e + * @param {!events.Event} e */ handleMenuEvent(e) { // this.dir(e.target, e.type + ': ' + goog.getUid(e.target)); if (e.target instanceof Menu && !(e.target.getParent() instanceof SubMenu)) { // should only ever be SHOW or HIDE this.setShown(e.type === Component.EventType.SHOW); - this.move(/** @type {!Menu} */ (e.target)); + this.move(/** @type {!Menu} */(e.target)); } } - + /** * @param {!Menu} menu */ @@ -103,14 +105,14 @@ class MenuShield extends Component { style.setPosition(shield, new Coordinate(x, y)); } - + /** * @param {boolean} b */ setShown(b) { style.setElementShown(this.getElement(), b); } - + } exports = MenuShield; diff --git a/js/ui/route.js b/js/ui/route.js index 23a44ca..facb8c6 100644 --- a/js/ui/route.js +++ b/js/ui/route.js @@ -1,10 +1,13 @@ goog.module('stack.ui.Route'); -const Event = goog.require('stack.ui.route.Event'); +const Component = goog.require('stack.ui.Component'); +const GEvent = goog.require('goog.events.Event'); const EventTarget = goog.require('goog.events.EventTarget'); const Promise_ = goog.require('goog.Promise'); +const Resolver = goog.require('goog.promise.Resolver'); const asserts = goog.require('goog.asserts'); + /** * A route is a segment of paths and a collection of a components that * have traversed along it. @@ -23,7 +26,7 @@ class Route extends EventTarget { /** @private @type {number} */ this.index_ = 0; - /** @private @type {!Array} */ + /** @private @type {!Array} */ this.progress_ = []; /** @private @type {string} */ @@ -32,7 +35,7 @@ class Route extends EventTarget { /** @private @type {string|undefined} */ this.failReason_ = undefined; - /** @const @private @type {!goog.promise.Resolver} */ + /** @const @private @type {!Resolver} */ this.resolver_ = Promise_.withResolver(); } @@ -86,7 +89,7 @@ class Route extends EventTarget { this.index_ += n; return this; } - + /** * Add a path segment to the end of the route. * @@ -97,19 +100,19 @@ class Route extends EventTarget { // console.info(`Adding segment ${segment}`); this.path_.push(segment); return this; - } - + } + /** * Get the indexed progress component or the last one if not set. * * @param {?number=} index - * @return {?stack.ui.Component} + * @return {?Component} */ get(index) { index = goog.isNumber(index) ? index : this.index_ - 1; return this.progress_[index] || null; } - + /** * @return {string} */ @@ -191,7 +194,7 @@ class Route extends EventTarget { /** * Record a non-contributing hop along the path, used mainly * for debugging. - * @param {!stack.ui.Component} component + * @param {!Component} component */ touch(component) { //console.log('touch:', component); @@ -210,7 +213,7 @@ class Route extends EventTarget { } /** - * @param {!stack.ui.Component} component + * @param {!Component} component */ progress(component) { //console.log('progress: in progress?', this.inProgress()); @@ -223,7 +226,7 @@ class Route extends EventTarget { } /** - * @param {!stack.ui.Component} component + * @param {!Component} component */ done(component) { // this.assertInProgress(); @@ -234,7 +237,7 @@ class Route extends EventTarget { } /** - * @param {!stack.ui.Component} component + * @param {!Component} component * @param {string=} opt_reason */ fail(component, opt_reason) { @@ -248,10 +251,10 @@ class Route extends EventTarget { /** * @param {string} type - * @param {?stack.ui.Component} component + * @param {?Component} component */ notifyEvent(type, component) { - this.dispatchEvent(new Event(type, this, component)); + this.dispatchEvent(new RouteEvent(type, this, component)); } /** @override */ @@ -274,3 +277,30 @@ Route.EventType = { }; exports = Route; + +class RouteEvent extends GEvent { + + /** + * Event class for routing. + * + * @param {string} type Event Type. + * @param {!Route} target Reference to the initiating route. + * @param {?Component=} component The component relevant to the event. + */ + constructor(type, target, component) { + super(type, target); + + /** + * @type {!Route} + */ + this.route = target; + + /** + * @type {?Component|undefined} + */ + this.component = component; + } + +} + +Route.Event = RouteEvent; \ No newline at end of file diff --git a/js/ui/route/event.js b/js/ui/route/event.js index b32088c..1fa2cc7 100644 --- a/js/ui/route/event.js +++ b/js/ui/route/event.js @@ -1,30 +1,2 @@ goog.module('stack.ui.route.Event'); -const GEvent = goog.require('goog.events.Event'); - -class Event extends GEvent { - - /** - * Event class for routing. - * - * @param {string} type Event Type. - * @param {!stack.ui.Route} target Reference to the initiating route. - * @param {?stack.ui.Component=} component The component relevant to the event. - */ - constructor(type, target, component) { - super(type, target); - - /** - * @type {!stack.ui.Route} - */ - this.route = target; - - /** - * @type {?stack.ui.Component|undefined} - */ - this.component = component; - } - -} - -exports = Event; diff --git a/js/ui/router.js b/js/ui/router.js index 0a0e9c2..7e12125 100644 --- a/js/ui/router.js +++ b/js/ui/router.js @@ -3,15 +3,12 @@ */ goog.module('stack.ui.Router'); -const Component = goog.require('stack.ui.Component'); const ComponentEventType = goog.require('goog.ui.Component.EventType'); const EventHandler = goog.require('goog.events.EventHandler'); const EventTarget = goog.require('goog.events.EventTarget'); -const History_ = goog.require('stack.ui.History'); -const Promise_ = goog.require('goog.Promise'); -const Route = goog.require('stack.ui.Route'); -const RouteEvent = goog.require('stack.ui.route.Event'); -const asserts = goog.require('goog.asserts'); +const History_ = goog.require('stack.ui.History'); +const Promise_ = goog.require('goog.Promise'); +const asserts = goog.require('goog.asserts'); /** * Manages a current route in-progress. Fires @@ -52,7 +49,7 @@ class Router extends EventTarget { * @type {boolean} */ this.strict_ = true; - + } /** @@ -94,7 +91,7 @@ class Router extends EventTarget { var route = new Route(list); this.listenRoute(route); - this.dispatchEvent(new RouteEvent( + this.dispatchEvent(new Route.Event( ComponentEventType.ACTION, route )); @@ -112,20 +109,20 @@ class Router extends EventTarget { return route.getPromise(); } - /** @param {!RouteEvent} e */ + /** @param {!Route.Event} e */ handleProgress(e) { this.dispatchEvent(e); //console.log(e.target.index() + '. Progress ' + e.target.pathMatched(), e.component); } - /** @param {!RouteEvent} e */ + /** @param {!Route.Event} e */ handleDone(e) { this.dispatchEvent(e); //console.log('Done! ' + e.target.matchedPath(), e.component); this.unlistenRoute(); } - /** @param {!RouteEvent} e */ + /** @param {!Route.Event} e */ handleFail(e) { this.dispatchEvent(e); const target = /** @type {!Route} */(e.target); @@ -133,7 +130,7 @@ class Router extends EventTarget { this.unlistenRoute(); } - /** @param {!RouteEvent} e */ + /** @param {!Route.Event} e */ handleTimeout(e) { console.warn('Route Timeout', e); this.unlistenRoute(); diff --git a/js/ui/select.js b/js/ui/select.js index 190521a..6424adc 100644 --- a/js/ui/select.js +++ b/js/ui/select.js @@ -3,9 +3,10 @@ */ goog.module('stack.ui.Select'); -const Component = goog.require('stack.ui.Component'); -const TabEvent = goog.require('stack.ui.TabEvent'); -const asserts = goog.require('goog.asserts'); +const TabEvent = goog.require('stack.ui.TabEvent'); +const asserts = goog.require('goog.asserts'); +const dom = goog.require('goog.dom'); +const { Component, Route } = goog.require('stack.ui'); /** * Component with routing capability such that only one named child @@ -14,7 +15,7 @@ const asserts = goog.require('goog.asserts'); class Select extends Component { /** - * @param {?goog.dom.DomHelper=} opt_domHelper + * @param {?dom.DomHelper=} opt_domHelper */ constructor(opt_domHelper) { super(opt_domHelper); @@ -46,7 +47,7 @@ class Select extends Component { getCurrentTabName() { return this.current_; } - + /** * @param {string} name * @param {!Component} c @@ -145,11 +146,11 @@ class Select extends Component { } /** - * @param {!stack.ui.Route} route + * @param {!Route} route */ selectHere(route) { super.goHere(route); - } + } /** * @override @@ -168,10 +169,10 @@ class Select extends Component { } } - + /** * @param {string} name - * @param {!stack.ui.Route} route + * @param {!Route} route */ select(name, route) { asserts.assertString(name); @@ -183,16 +184,16 @@ class Select extends Component { } } - + /** * @param {string} name - * @param {!stack.ui.Route} route + * @param {!Route} route */ selectFail(name, route) { route.fail(this, 'No tab for ' + name + ' in ' + JSON.stringify(this.name2id_)); // this.getApp().handle404(route); } - + /** * Get the current tab. * @@ -201,11 +202,11 @@ class Select extends Component { getCurrent() { if (this.current_) { return this.getTab(this.current_); - } + } return null; } - + /** * Hide the current tab and make it the previous. * @return {?Component} @@ -222,7 +223,7 @@ class Select extends Component { this.current_ = null; return prev; } - + } exports = Select; diff --git a/js/ui/syntax.js b/js/ui/syntax.js index db7301f..9f60f1b 100644 --- a/js/ui/syntax.js +++ b/js/ui/syntax.js @@ -3,9 +3,9 @@ */ goog.module('stack.ui.Syntax'); -const Component = goog.require('stack.ui.Component'); const asserts = goog.require('goog.asserts'); const dom = goog.require('goog.dom'); +const { Component } = goog.require('stack.ui'); /** * A component that does prism.js syntax highlighting. @@ -50,7 +50,7 @@ class Syntax extends Component { ) ); } - + /** * @override */ @@ -61,7 +61,7 @@ class Syntax extends Component { } } - + /** * @param {?Element} el */ diff --git a/js/ui/tab.js b/js/ui/tab.js index 59242c3..99edf12 100644 --- a/js/ui/tab.js +++ b/js/ui/tab.js @@ -3,7 +3,7 @@ */ goog.module('stack.ui.Tab'); -const Select = goog.require('stack.ui.Select'); +const Select = goog.require('stack.ui.Select'); /** * Select implemntation that takes a function for the @@ -13,7 +13,7 @@ class Tab extends Select { /** * @param {function(string,!stack.ui.Route)} failHandler - * @param {?goog.dom.DomHelper=} opt_domHelper + * @param {?dom.DomHelper=} opt_domHelper */ constructor(failHandler, opt_domHelper) { super(opt_domHelper); @@ -26,14 +26,14 @@ class Tab extends Select { this.failHandler_ = failHandler; } - + /** * @override */ selectFail(name, route) { this.failHandler_(name, route); } - + } exports = Tab; diff --git a/js/ui/tabevent.js b/js/ui/tabevent.js index c94ba71..b753fe3 100644 --- a/js/ui/tabevent.js +++ b/js/ui/tabevent.js @@ -3,8 +3,8 @@ */ goog.module('stack.ui.TabEvent'); -const Component = goog.require('stack.ui.Component'); -const GoogEvent = goog.require('goog.events.Event'); +const GoogEvent = goog.require('goog.events.Event'); +const { Component } = goog.require('stack.ui'); /** * Custom event that signals a new tab child. @@ -18,13 +18,13 @@ class TabEvent extends GoogEvent { * @param {!Component} child The child added */ constructor(eventName, name, child) { - super(eventName); + super(eventName); - /** @public @const */ - this.name = name; + /** @public @const */ + this.name = name; - /** @public @const */ - this.child = child; + /** @public @const */ + this.child = child; } } diff --git a/js/ui/template.js b/js/ui/template.js index 0f85d4a..e27d78e 100644 --- a/js/ui/template.js +++ b/js/ui/template.js @@ -3,8 +3,9 @@ */ goog.module('stack.ui.Template'); -const Component = goog.require('stack.ui.Component'); +const dom = goog.require('goog.dom'); const soy = goog.require('goog.soy'); +const { Component } = goog.require('stack.ui'); /** * A component that takes a soy template and optional args. @@ -15,7 +16,7 @@ class Template extends Component { * @param {!Function} template * @param {!Object} args * @param {?Object=} opt_inject - * @param {?goog.dom.DomHelper=} opt_domHelper + * @param {?dom.DomHelper=} opt_domHelper */ constructor(template, args, opt_inject, opt_domHelper) { super(opt_domHelper); From 082ee053b3b715a75ae145ed67ab98c832ad8056 Mon Sep 17 00:00:00 2001 From: Paul Cody Johnston Date: Mon, 20 Apr 2020 20:44:42 -0600 Subject: [PATCH 2/3] Apply buildifier --- css/BUILD.bazel | 1 - js/ui/BUILD | 11 +++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/css/BUILD.bazel b/css/BUILD.bazel index 078b4df..5f719a9 100644 --- a/css/BUILD.bazel +++ b/css/BUILD.bazel @@ -2,7 +2,6 @@ package(default_visibility = ["//visibility:public"]) load("@io_bazel_rules_closure//closure:defs.bzl", "closure_css_library", "closure_css_binary") - closure_css_library( name = "style", srcs = [ diff --git a/js/ui/BUILD b/js/ui/BUILD index 9943851..b5137fb 100644 --- a/js/ui/BUILD +++ b/js/ui/BUILD @@ -9,8 +9,8 @@ closure_js_library( ], deps = [ ":history", - ":keyboard", ":injector", + ":keyboard", "@io_bazel_rules_closure//closure/library/asserts", "@io_bazel_rules_closure//closure/library/dom", "@io_bazel_rules_closure//closure/library/events", @@ -71,8 +71,8 @@ closure_js_library( ], deps = [ ":core", - "@io_bazel_rules_closure//closure/library/soy", "@io_bazel_rules_closure//closure/library/dom", + "@io_bazel_rules_closure//closure/library/soy", ], ) @@ -103,9 +103,9 @@ closure_js_library( deps = [ "@io_bazel_rules_closure//closure/library/asserts", "@io_bazel_rules_closure//closure/library/dom", + "@io_bazel_rules_closure//closure/library/events", "@io_bazel_rules_closure//closure/library/math:coordinate", "@io_bazel_rules_closure//closure/library/style", - "@io_bazel_rules_closure//closure/library/events", "@io_bazel_rules_closure//closure/library/ui:component", "@io_bazel_rules_closure//closure/library/ui:container", "@io_bazel_rules_closure//closure/library/ui:menu", @@ -127,7 +127,6 @@ closure_js_library( ], ) - closure_js_library( name = "injector", srcs = [ @@ -141,9 +140,9 @@ closure_js_library( closure_js_library( name = "ui", exports = [ - ":injector", ":core", ":history", + ":injector", ":keyboard", ":menushield", ":select", @@ -193,10 +192,10 @@ closure_js_test( entry_points = ["goog:stack.ui.HistoryTest"], deps = [ ":history", + "@io_bazel_rules_closure//closure/library:testing", "@io_bazel_rules_closure//closure/library/dom", "@io_bazel_rules_closure//closure/library/dom:tagname", "@io_bazel_rules_closure//closure/library/events", "@io_bazel_rules_closure//closure/library/string", - "@io_bazel_rules_closure//closure/library:testing", ], ) From 2cde9eb063489f9f27ef4cc7418b95cdb8e40826 Mon Sep 17 00:00:00 2001 From: Paul Cody Johnston Date: Mon, 20 Apr 2020 20:45:07 -0600 Subject: [PATCH 3/3] Use more specific build file name --- js/ui/{BUILD => BUILD.bazel} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename js/ui/{BUILD => BUILD.bazel} (100%) diff --git a/js/ui/BUILD b/js/ui/BUILD.bazel similarity index 100% rename from js/ui/BUILD rename to js/ui/BUILD.bazel