summaryrefslogtreecommitdiffstats
path: root/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.js
blob: ef8c1122789196c8f372bf0aef5c824776fec386 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/**
 * @license
 * Copyright (C) 2016 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.
 */
(function() {
  'use strict';

  const HLJS_PATH = 'bower_components/highlightjs/highlight.min.js';
  const DARK_THEME_PATH = 'styles/themes/dark-theme.html';

  Polymer({
    is: 'gr-lib-loader',

    properties: {
      _hljsState: {
        type: Object,

        // NOTE: intended singleton.
        value: {
          configured: false,
          loading: false,
          callbacks: [],
        },
      },
    },

    /**
     * Get the HLJS library. Returns a promise that resolves with a reference to
     * the library after it's been loaded. The promise resolves immediately if
     * it's already been loaded.
     * @return {!Promise<Object>}
     */
    getHLJS() {
      return new Promise((resolve, reject) => {
        // If the lib is totally loaded, resolve immediately.
        if (this._getHighlightLib()) {
          resolve(this._getHighlightLib());
          return;
        }

        // If the library is not currently being loaded, then start loading it.
        if (!this._hljsState.loading) {
          this._hljsState.loading = true;
          this._loadScript(this._getHLJSUrl())
              .then(this._onHLJSLibLoaded.bind(this)).catch(reject);
        }

        this._hljsState.callbacks.push(resolve);
      });
    },

    /**
     * Loads the dark theme document. Returns a promise that resolves with a
     * custom-style DOM element.
     * @return {!Promise<Element>}
     */
    getDarkTheme() {
      return new Promise((resolve, reject) => {
        this.importHref(this._getLibRoot() + DARK_THEME_PATH, () => {
          const module = document.createElement('style', 'custom-style');
          module.setAttribute('include', 'dark-theme');
          resolve(module);
        });
      });
    },

    /**
     * Execute callbacks awaiting the HLJS lib load.
     */
    _onHLJSLibLoaded() {
      const lib = this._getHighlightLib();
      this._hljsState.loading = false;
      for (const cb of this._hljsState.callbacks) {
        cb(lib);
      }
      this._hljsState.callbacks = [];
    },

    /**
     * Get the HLJS library, assuming it has been loaded. Configure the library
     * if it hasn't already been configured.
     * @return {!Object}
     */
    _getHighlightLib() {
      const lib = window.hljs;
      if (lib && !this._hljsState.configured) {
        this._hljsState.configured = true;

        lib.configure({classPrefix: 'gr-diff gr-syntax gr-syntax-'});
      }
      return lib;
    },

    /**
     * Get the resource path used to load the application. If the application
     * was loaded through a CDN, then this will be the path to CDN resources.
     * @return {string}
     */
    _getLibRoot() {
      if (window.STATIC_RESOURCE_PATH) {
        return window.STATIC_RESOURCE_PATH + '/';
      }
      return '/';
    },

    /**
     * Load and execute a JS file from the lib root.
     * @param {string} src The path to the JS file without the lib root.
     * @return {Promise} a promise that resolves when the script's onload
     *     executes.
     */
    _loadScript(src) {
      return new Promise((resolve, reject) => {
        const script = document.createElement('script');

        if (!src) {
          reject(new Error('Unable to load blank script url.'));
          return;
        }

        script.src = src;
        script.onload = resolve;
        script.onerror = reject;
        Polymer.dom(document.head).appendChild(script);
      });
    },

    _getHLJSUrl() {
      const root = this._getLibRoot();
      if (!root) { return null; }
      return root + HLJS_PATH;
    },
  });
})();