Convert GrLibLoader from Polymer element to class

Change-Id: I1d1d1aadec4c53ab3c2597bf4cf65cf79ba6fe70
diff --git a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.ts b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.ts
index f85667c..04bb3d2 100644
--- a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.ts
+++ b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer.ts
@@ -14,12 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import '../../shared/gr-lib-loader/gr-lib-loader';
 import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
 import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
+import {html} from '@polymer/polymer/lib/utils/html-tag';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {htmlTemplate} from './gr-syntax-layer_html';
 import {FILE, GrDiffLine, GrDiffLineType} from '../gr-diff/gr-diff-line';
 import {CancelablePromise, util} from '../../../scripts/util';
 import {customElement, property} from '@polymer/decorators';
@@ -159,18 +158,12 @@
   lastNotify: {left: number; right: number};
 }
 
-export interface GrSyntaxLayer {
-  $: {
-    libLoader: GrLibLoader;
-  };
-}
-
 @customElement('gr-syntax-layer')
 export class GrSyntaxLayer
   extends GestureEventListeners(LegacyElementMixin(PolymerElement))
   implements DiffLayer {
   static get template() {
-    return htmlTemplate;
+    return html``;
   }
 
   @property({type: Object, observer: '_diffChanged'})
@@ -203,6 +196,8 @@
   @property({type: Object})
   _hljs?: HighlightJS;
 
+  private readonly libLoader = new GrLibLoader();
+
   addListener(listener: DiffLayerListener) {
     this.push('_listeners', listener);
   }
@@ -598,7 +593,7 @@
   }
 
   _loadHLJS() {
-    return this.$.libLoader.getHLJS().then(hljs => {
+    return this.libLoader.getHLJS().then(hljs => {
       this._hljs = hljs;
     });
   }
diff --git a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_html.ts b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_html.ts
deleted file mode 100644
index ac59f4f..0000000
--- a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_html.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {html} from '@polymer/polymer/lib/utils/html-tag';
-
-export const htmlTemplate = html`
-  <gr-lib-loader id="libLoader"></gr-lib-loader>
-`;
diff --git a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.js b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.js
index 6a2bbca..20106d8 100644
--- a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.js
@@ -173,7 +173,7 @@
 
     const mockHLJS = getMockHLJS();
     const highlightSpy = sinon.spy(mockHLJS, 'highlight');
-    sinon.stub(element.$.libLoader, 'getHLJS').callsFake(
+    sinon.stub(element.libLoader, 'getHLJS').callsFake(
         () => Promise.resolve(mockHLJS));
     const processNextSpy = sinon.spy(element, '_processNextLine');
     const processPromise = element.process();
diff --git a/polygerrit-ui/app/elements/gr-app-element.ts b/polygerrit-ui/app/elements/gr-app-element.ts
index 830b7c3..72e24f7 100644
--- a/polygerrit-ui/app/elements/gr-app-element.ts
+++ b/polygerrit-ui/app/elements/gr-app-element.ts
@@ -37,7 +37,6 @@
 import './settings/gr-cla-view/gr-cla-view';
 import './settings/gr-registration-dialog/gr-registration-dialog';
 import './settings/gr-settings-view/gr-settings-view';
-import './shared/gr-lib-loader/gr-lib-loader';
 import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
diff --git a/polygerrit-ui/app/elements/gr-app-element_html.ts b/polygerrit-ui/app/elements/gr-app-element_html.ts
index 55dfe27..81a9988 100644
--- a/polygerrit-ui/app/elements/gr-app-element_html.ts
+++ b/polygerrit-ui/app/elements/gr-app-element_html.ts
@@ -230,7 +230,6 @@
   ></gr-error-manager>
   <gr-router id="router"></gr-router>
   <gr-plugin-host id="plugins" config="[[_serverConfig]]"> </gr-plugin-host>
-  <gr-lib-loader id="libLoader"></gr-lib-loader>
   <gr-external-style
     id="externalStyleForAll"
     name="app-theme"
diff --git a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.ts b/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.ts
index ad97d02..ea0ad4e 100644
--- a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.ts
+++ b/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.ts
@@ -15,14 +15,9 @@
  * limitations under the License.
  */
 import '../gr-js-api-interface/gr-js-api-interface';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
-import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {htmlTemplate} from './gr-lib-loader_html';
 import {EventType} from '../../plugins/gr-plugin-types';
-import {customElement, property} from '@polymer/decorators';
-import {JsApiService} from '../gr-js-api-interface/gr-js-api-types';
 import {HighlightJS} from '../../../types/types';
+import {GrJsApiInterface} from '../gr-js-api-interface/gr-js-api-interface-element';
 
 // preloaded in PolyGerritIndexHtml.soy
 const HLJS_PATH = 'bower_components/highlightjs/highlight.min.js';
@@ -35,21 +30,9 @@
   callbacks: HljsCallback[];
 }
 
-export interface GrLibLoader {
-  $: {
-    jsAPI: JsApiService & Element;
-  };
-}
-@customElement('gr-lib-loader')
-export class GrLibLoader extends GestureEventListeners(
-  LegacyElementMixin(PolymerElement)
-) {
-  static get template() {
-    return htmlTemplate;
-  }
+export class GrLibLoader {
+  private readonly jsAPI = new GrJsApiInterface();
 
-  // NOTE: intended singleton.
-  @property({type: Object})
   _hljsState: HljsState = {
     configured: false,
     loading: false,
@@ -87,7 +70,7 @@
   _onHLJSLibLoaded() {
     const lib = this._getHighlightLib();
     this._hljsState.loading = false;
-    this.$.jsAPI.handleEvent(EventType.HIGHLIGHTJS_LOADED, {
+    this.jsAPI.handleEvent(EventType.HIGHLIGHTJS_LOADED, {
       hljs: lib,
     });
     for (const cb of this._hljsState.callbacks) {
@@ -152,9 +135,3 @@
     return root + HLJS_PATH;
   }
 }
-
-declare global {
-  interface HTMLElementTagNameMap {
-    'gr-lib-loader': GrLibLoader;
-  }
-}
diff --git a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader_html.ts b/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader_html.ts
deleted file mode 100644
index f34f99e..0000000
--- a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader_html.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {html} from '@polymer/polymer/lib/utils/html-tag';
-
-export const htmlTemplate = html`
-  <gr-js-api-interface id="jsAPI"></gr-js-api-interface>
-`;
diff --git a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader_test.js b/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader_test.js
index 1ce175f..c89ff8e 100644
--- a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader_test.js
@@ -17,23 +17,22 @@
 
 import '../../../test/common-test-setup-karma.js';
 import './gr-lib-loader.js';
-
-const basicFixture = fixtureFromElement('gr-lib-loader');
+import {GrLibLoader} from './gr-lib-loader.js';
 
 suite('gr-lib-loader tests', () => {
-  let element;
+  let grLibLoader;
   let resolveLoad;
   let loadStub;
 
   setup(() => {
-    element = basicFixture.instantiate();
+    grLibLoader = new GrLibLoader();
 
-    loadStub = sinon.stub(element, '_loadScript').callsFake(() =>
+    loadStub = sinon.stub(grLibLoader, '_loadScript').callsFake(() =>
       new Promise(resolve => resolveLoad = resolve)
     );
 
     // Assert preconditions:
-    assert.isFalse(element._hljsState.loading);
+    assert.isFalse(grLibLoader._hljsState.loading);
   });
 
   teardown(() => {
@@ -42,26 +41,26 @@
     }
 
     // Because the element state is a singleton, clean it up.
-    element._hljsState.configured = false;
-    element._hljsState.loading = false;
-    element._hljsState.callbacks = [];
+    grLibLoader._hljsState.configured = false;
+    grLibLoader._hljsState.loading = false;
+    grLibLoader._hljsState.callbacks = [];
   });
 
   test('only load once', async () => {
-    sinon.stub(element, '_getHLJSUrl').returns('');
+    sinon.stub(grLibLoader, '_getHLJSUrl').returns('');
     const firstCallHandler = sinon.stub();
-    element.getHLJS().then(firstCallHandler);
+    grLibLoader.getHLJS().then(firstCallHandler);
 
     // It should now be in the loading state.
     assert.isTrue(loadStub.called);
-    assert.isTrue(element._hljsState.loading);
+    assert.isTrue(grLibLoader._hljsState.loading);
     assert.isFalse(firstCallHandler.called);
 
     const secondCallHandler = sinon.stub();
-    element.getHLJS().then(secondCallHandler);
+    grLibLoader.getHLJS().then(secondCallHandler);
 
     // No change in state.
-    assert.isTrue(element._hljsState.loading);
+    assert.isTrue(grLibLoader._hljsState.loading);
     assert.isFalse(firstCallHandler.called);
     assert.isFalse(secondCallHandler.called);
 
@@ -69,7 +68,7 @@
     resolveLoad();
     await flush();
     // The state should be loaded and both handlers called.
-    assert.isFalse(element._hljsState.loading);
+    assert.isFalse(grLibLoader._hljsState.loading);
     assert.isTrue(firstCallHandler.called);
     assert.isTrue(secondCallHandler.called);
   });
@@ -90,13 +89,13 @@
 
     test('returns hljs', async () => {
       const firstCallHandler = sinon.stub();
-      element.getHLJS().then(firstCallHandler);
+      grLibLoader.getHLJS().then(firstCallHandler);
       await flush();
       assert.isTrue(firstCallHandler.called);
       assert.isTrue(firstCallHandler.calledWith(hljsStub));
     });
 
-    test('configures hljs', () => element.getHLJS().then(() => {
+    test('configures hljs', () => grLibLoader.getHLJS().then(() => {
       assert.isTrue(window.hljs.configure.calledOnce);
     }));
   });
@@ -106,16 +105,16 @@
       let root;
 
       setup(() => {
-        sinon.stub(element, '_getLibRoot').callsFake(() => root);
+        sinon.stub(grLibLoader, '_getLibRoot').callsFake(() => root);
       });
 
       test('with no root', () => {
-        assert.isNull(element._getHLJSUrl());
+        assert.isNull(grLibLoader._getHLJSUrl());
       });
 
       test('with root', () => {
         root = 'test-root.com/';
-        assert.equal(element._getHLJSUrl(),
+        assert.equal(grLibLoader._getHLJSUrl(),
             'test-root.com/bower_components/highlightjs/highlight.min.js');
       });
     });