UNPKG

8.04 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
8
9var _jsModules = require('@jenkins-cd/js-modules');
10
11var _jsModules2 = _interopRequireDefault(_jsModules);
12
13var _ModuleSpec = require('@jenkins-cd/js-modules/js/ModuleSpec');
14
15var _ModuleSpec2 = _interopRequireDefault(_ModuleSpec);
16
17function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18
19function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
20
21/**
22 * CSS load tracker.
23 * <p/>
24 * Keeps track of page CSS, adding and removing CSS as ExtensionPoint components are
25 * mounted and unmounted.
26 */
27var ResourceLoadTracker = function () {
28 function ResourceLoadTracker() {
29 _classCallCheck(this, ResourceLoadTracker);
30
31 // The CSS resources to be added for each Extension point.
32 // Key: Extension point name.
33 // Value: An array of CSS adjunct URLs that need to be activated when the extension point is rendered.
34 this.pointCSSs = {};
35
36 // Active CSS.
37 // Key: CSS URL.
38 // Value: Counter of the number of mounted Extension Points that need the CSS to be active.
39 // The onMount and onUnmount functions increment and decrement the counter. When the
40 // counter gets back to zero, the CSS can be removed from the page.
41 this.activeCSSs = {};
42 }
43
44 /**
45 * Initialize the loader with the extension point information.
46 * @param extensionPointList The Extension point list. An array containing ExtensionPoint
47 * metadata for all plugins that define such. It's an aggregation of
48 * of the /jenkins-js-extension.json files found on the server classpath.
49 */
50
51
52 _createClass(ResourceLoadTracker, [{
53 key: 'setExtensionPointMetadata',
54 value: function setExtensionPointMetadata(extensionPointList) {
55 // Reset - for testing.
56 this.pointCSSs = {};
57 this.activeCSSs = {};
58
59 // Iterate through each plugin /jenkins-js-extension.json
60 for (var i1 = 0; i1 < extensionPointList.length; i1++) {
61 var pluginMetadata = extensionPointList[i1];
62 var extensions = pluginMetadata.extensions; // All the extensions defined on the plugin
63 var pluginCSS = pluginMetadata.extensionCSS; // The plugin CSS URL (adjunct URL).
64
65 // Iterate through the ExtensionPoints defined in each plugin
66 for (var i2 = 0; i2 < extensions.length; i2++) {
67 var extensionPoint = extensions[i2].extensionPoint; // The extension point name.
68 var pointCSS = this.pointCSSs[extensionPoint]; // The current list of CSS URLs for the named extension point.
69
70 if (!pointCSS) {
71 pointCSS = [];
72 this.pointCSSs[extensionPoint] = pointCSS;
73 }
74
75 // Add the plugin CSS if it's not already in the list.
76 if (pointCSS.filter(function (pluginCSSEntry) {
77 return pluginCSSEntry.url === pluginCSS;
78 }).length === 0) {
79 pointCSS.push({
80 url: pluginCSS,
81 hpiPluginId: pluginMetadata.hpiPluginId
82 });
83 }
84 }
85 }
86 }
87
88 /**
89 * Called when a Jenkins ExtensionPoint is mounted.
90 * <p/>
91 * If the extension point implementations use CSS (comes from plugins that define CSS)
92 * then this method will use requireCSS, and then addCSS, for each CSS. addCSS only
93 * gets called for a CSS by the first extension point to "require" that CSS.
94 *
95 * @param extensionPointName The extension point name.
96 */
97
98 }, {
99 key: 'onMount',
100 value: function onMount(extensionPointName) {
101 var pointCSS = this.pointCSSs[extensionPointName];
102 if (pointCSS) {
103 for (var i = 0; i < pointCSS.length; i++) {
104 this._requireCSS(pointCSS[i]);
105 }
106 }
107 }
108
109 /**
110 * Called when a Jenkins ExtensionPoint is unmounted.
111 * <p/>
112 * If the extension point implementations use CSS (comes from plugins that define CSS)
113 * then this method will use unrequireCSS, and then removeCSS, for each CSS. removeCSS only
114 * gets called for a CSS by the last extension point to "unrequire" that CSS.
115 *
116 * @param extensionPointName The extension point name.
117 */
118
119 }, {
120 key: 'onUnmount',
121 value: function onUnmount(extensionPointName) {
122 var pointCSS = this.pointCSSs[extensionPointName];
123 if (pointCSS) {
124 for (var i = 0; i < pointCSS.length; i++) {
125 this._unrequireCSS(pointCSS[i]);
126 }
127 }
128 }
129 }, {
130 key: '_requireCSS',
131 value: function _requireCSS(pluginCSS) {
132 if (!this.activeCSSs[pluginCSS.url]) {
133 this._addCSS(pluginCSS);
134 this.activeCSSs[pluginCSS.url] = true;
135 }
136 }
137 }, {
138 key: '_unrequireCSS',
139 value: function _unrequireCSS(pluginCSS) {
140 var activeCount = this.activeCSSs[pluginCSS.url];
141
142 if (!activeCount) {
143 // Huh?
144 console.warn('Unexpected call to deactivate an inactive Jenkins Extension Point CSS: ' + url);
145 // Does this mean that react calls unmount multiple times for a given component instance?
146 // That would sound like a bug, no?
147 } else {
148 activeCount--;
149 if (activeCount === 0) {
150 // All extension points using this CSS have been unmounted.
151 delete this.activeCSSs[pluginCSS.url];
152 this._removeCSS(pluginCSS);
153 } else {
154 this.activeCSSs[pluginCSS.url] = activeCount;
155 }
156 }
157 }
158 }, {
159 key: '_addCSS',
160 value: function _addCSS(pluginCSS) {
161 var cssURL = getPluginCSSURL(pluginCSS);
162 _jsModules2.default.addCSSToPage(cssURL);
163 }
164 }, {
165 key: '_removeCSS',
166 value: function _removeCSS(pluginCSS) {
167 var cssURL = getPluginCSSURL(pluginCSS);
168 var linkElId = _jsModules2.default.toCSSId(cssURL);
169 var linkEl = document.getElementById(linkElId);
170
171 if (linkEl) {
172 linkEl.parentNode.removeChild(linkEl);
173 }
174 }
175 }]);
176
177 return ResourceLoadTracker;
178}();
179
180exports.default = ResourceLoadTracker;
181
182
183function getPluginCSSURL(pluginCSS) {
184 var moduleSpec = new _ModuleSpec2.default(pluginCSS.hpiPluginId + ':jenkins-js-extension');
185 var resolver = void 0;
186
187 // Backward compatibility - in case of an older version of js-modules
188 if (typeof _jsModules2.default.getResourceLocationResolver === 'function') {
189 resolver = _jsModules2.default.getResourceLocationResolver(moduleSpec);
190 }
191
192 if (resolver) {
193 return resolver(pluginCSS.url);
194 } else {
195 var adjunctUrl = _jsModules2.default.getAdjunctURL();
196 return adjunctUrl + '/' + pluginCSS.url;
197 }
198}
\No newline at end of file