css.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. /*!-----------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Version: 0.5.2(d49899a916fd99840f6f9178f2dd06e0e7013646)
  4. * Released under the MIT license
  5. * https://github.com/Microsoft/vscode/blob/master/LICENSE.txt
  6. *-----------------------------------------------------------*/
  7. /*---------------------------------------------------------------------------------------------
  8. * Copyright (c) Microsoft Corporation. All rights reserved.
  9. * Licensed under the MIT License. See License.txt in the project root for license information.
  10. *--------------------------------------------------------------------------------------------*/
  11. /*---------------------------------------------------------------------------------------------
  12. *---------------------------------------------------------------------------------------------
  13. *---------------------------------------------------------------------------------------------
  14. *---------------------------------------------------------------------------------------------
  15. *---------------------------------------------------------------------------------------------
  16. * Please make sure to make edits in the .ts file at https://github.com/Microsoft/vscode-loader/
  17. *---------------------------------------------------------------------------------------------
  18. *---------------------------------------------------------------------------------------------
  19. *---------------------------------------------------------------------------------------------
  20. *---------------------------------------------------------------------------------------------
  21. *--------------------------------------------------------------------------------------------*/
  22. 'use strict';
  23. var __extends = (this && this.__extends) || function (d, b) {
  24. for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
  25. function __() { this.constructor = d; }
  26. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  27. };
  28. var _cssPluginGlobal = this;
  29. var CSSLoaderPlugin;
  30. (function (CSSLoaderPlugin) {
  31. var global = _cssPluginGlobal;
  32. /**
  33. * Known issue:
  34. * - In IE there is no way to know if the CSS file loaded successfully or not.
  35. */
  36. var BrowserCSSLoader = (function () {
  37. function BrowserCSSLoader() {
  38. this._pendingLoads = 0;
  39. }
  40. BrowserCSSLoader.prototype.attachListeners = function (name, linkNode, callback, errorback) {
  41. var unbind = function () {
  42. linkNode.removeEventListener('load', loadEventListener);
  43. linkNode.removeEventListener('error', errorEventListener);
  44. };
  45. var loadEventListener = function (e) {
  46. unbind();
  47. callback();
  48. };
  49. var errorEventListener = function (e) {
  50. unbind();
  51. errorback(e);
  52. };
  53. linkNode.addEventListener('load', loadEventListener);
  54. linkNode.addEventListener('error', errorEventListener);
  55. };
  56. BrowserCSSLoader.prototype._onLoad = function (name, callback) {
  57. this._pendingLoads--;
  58. callback();
  59. };
  60. BrowserCSSLoader.prototype._onLoadError = function (name, errorback, err) {
  61. this._pendingLoads--;
  62. errorback(err);
  63. };
  64. BrowserCSSLoader.prototype._insertLinkNode = function (linkNode) {
  65. this._pendingLoads++;
  66. var head = document.head || document.getElementsByTagName('head')[0];
  67. var other = head.getElementsByTagName('link') || document.head.getElementsByTagName('script');
  68. if (other.length > 0) {
  69. head.insertBefore(linkNode, other[other.length - 1]);
  70. }
  71. else {
  72. head.appendChild(linkNode);
  73. }
  74. };
  75. BrowserCSSLoader.prototype.createLinkTag = function (name, cssUrl, externalCallback, externalErrorback) {
  76. var _this = this;
  77. var linkNode = document.createElement('link');
  78. linkNode.setAttribute('rel', 'stylesheet');
  79. linkNode.setAttribute('type', 'text/css');
  80. linkNode.setAttribute('data-name', name);
  81. var callback = function () { return _this._onLoad(name, externalCallback); };
  82. var errorback = function (err) { return _this._onLoadError(name, externalErrorback, err); };
  83. this.attachListeners(name, linkNode, callback, errorback);
  84. linkNode.setAttribute('href', cssUrl);
  85. return linkNode;
  86. };
  87. BrowserCSSLoader.prototype._linkTagExists = function (name, cssUrl) {
  88. var i, len, nameAttr, hrefAttr, links = document.getElementsByTagName('link');
  89. for (i = 0, len = links.length; i < len; i++) {
  90. nameAttr = links[i].getAttribute('data-name');
  91. hrefAttr = links[i].getAttribute('href');
  92. if (nameAttr === name || hrefAttr === cssUrl) {
  93. return true;
  94. }
  95. }
  96. return false;
  97. };
  98. BrowserCSSLoader.prototype.load = function (name, cssUrl, externalCallback, externalErrorback) {
  99. if (this._linkTagExists(name, cssUrl)) {
  100. externalCallback();
  101. return;
  102. }
  103. var linkNode = this.createLinkTag(name, cssUrl, externalCallback, externalErrorback);
  104. this._insertLinkNode(linkNode);
  105. };
  106. return BrowserCSSLoader;
  107. }());
  108. /**
  109. * Prior to IE10, IE could not go above 31 stylesheets in a page
  110. * http://blogs.msdn.com/b/ieinternals/archive/2011/05/14/internet-explorer-stylesheet-rule-selector-import-sheet-limit-maximum.aspx
  111. *
  112. * The general strategy here is to not write more than 31 link nodes to the page at the same time
  113. * When stylesheets get loaded, they will get merged one into another to free up
  114. * some positions for new link nodes.
  115. */
  116. var IE9CSSLoader = (function (_super) {
  117. __extends(IE9CSSLoader, _super);
  118. function IE9CSSLoader() {
  119. _super.call(this);
  120. this._blockedLoads = [];
  121. this._mergeStyleSheetsTimeout = -1;
  122. }
  123. IE9CSSLoader.prototype.load = function (name, cssUrl, externalCallback, externalErrorback) {
  124. if (this._linkTagExists(name, cssUrl)) {
  125. externalCallback();
  126. return;
  127. }
  128. var linkNode = this.createLinkTag(name, cssUrl, externalCallback, externalErrorback);
  129. if (this._styleSheetCount() < 31) {
  130. this._insertLinkNode(linkNode);
  131. }
  132. else {
  133. this._blockedLoads.push(linkNode);
  134. this._handleBlocked();
  135. }
  136. };
  137. IE9CSSLoader.prototype._styleSheetCount = function () {
  138. var linkCount = document.getElementsByTagName('link').length;
  139. var styleCount = document.getElementsByTagName('style').length;
  140. return linkCount + styleCount;
  141. };
  142. IE9CSSLoader.prototype._onLoad = function (name, callback) {
  143. _super.prototype._onLoad.call(this, name, callback);
  144. this._handleBlocked();
  145. };
  146. IE9CSSLoader.prototype._onLoadError = function (name, errorback, err) {
  147. _super.prototype._onLoadError.call(this, name, errorback, err);
  148. this._handleBlocked();
  149. };
  150. IE9CSSLoader.prototype._handleBlocked = function () {
  151. var _this = this;
  152. var blockedLoadsCount = this._blockedLoads.length;
  153. if (blockedLoadsCount > 0 && this._mergeStyleSheetsTimeout === -1) {
  154. this._mergeStyleSheetsTimeout = window.setTimeout(function () { return _this._mergeStyleSheets(); }, 0);
  155. }
  156. };
  157. IE9CSSLoader.prototype._mergeStyleSheet = function (dstPath, dst, srcPath, src) {
  158. for (var i = src.rules.length - 1; i >= 0; i--) {
  159. dst.insertRule(Utilities.rewriteUrls(srcPath, dstPath, src.rules[i].cssText), 0);
  160. }
  161. };
  162. IE9CSSLoader.prototype._asIE9HTMLLinkElement = function (linkElement) {
  163. return linkElement;
  164. };
  165. IE9CSSLoader.prototype._mergeStyleSheets = function () {
  166. this._mergeStyleSheetsTimeout = -1;
  167. var blockedLoadsCount = this._blockedLoads.length;
  168. var i, linkDomNodes = document.getElementsByTagName('link');
  169. var linkDomNodesCount = linkDomNodes.length;
  170. var mergeCandidates = [];
  171. for (i = 0; i < linkDomNodesCount; i++) {
  172. if (linkDomNodes[i].readyState === 'loaded' || linkDomNodes[i].readyState === 'complete') {
  173. mergeCandidates.push({
  174. linkNode: linkDomNodes[i],
  175. rulesLength: this._asIE9HTMLLinkElement(linkDomNodes[i]).styleSheet.rules.length
  176. });
  177. }
  178. }
  179. var mergeCandidatesCount = mergeCandidates.length;
  180. // Just a little legend here :)
  181. // - linkDomNodesCount: total number of link nodes in the DOM (this should be kept <= 31)
  182. // - mergeCandidatesCount: loaded (finished) link nodes in the DOM (only these can be merged)
  183. // - blockedLoadsCount: remaining number of load requests that did not fit in before (because of the <= 31 constraint)
  184. // Now comes the heuristic part, we don't want to do too much work with the merging of styles,
  185. // but we do need to merge stylesheets to free up loading slots.
  186. var mergeCount = Math.min(Math.floor(mergeCandidatesCount / 2), blockedLoadsCount);
  187. // Sort the merge candidates descending (least rules last)
  188. mergeCandidates.sort(function (a, b) {
  189. return b.rulesLength - a.rulesLength;
  190. });
  191. var srcIndex, dstIndex;
  192. for (i = 0; i < mergeCount; i++) {
  193. srcIndex = mergeCandidates.length - 1 - i;
  194. dstIndex = i % (mergeCandidates.length - mergeCount);
  195. // Merge rules of src into dst
  196. this._mergeStyleSheet(mergeCandidates[dstIndex].linkNode.href, this._asIE9HTMLLinkElement(mergeCandidates[dstIndex].linkNode).styleSheet, mergeCandidates[srcIndex].linkNode.href, this._asIE9HTMLLinkElement(mergeCandidates[srcIndex].linkNode).styleSheet);
  197. // Remove dom node of src
  198. mergeCandidates[srcIndex].linkNode.parentNode.removeChild(mergeCandidates[srcIndex].linkNode);
  199. linkDomNodesCount--;
  200. }
  201. var styleSheetCount = this._styleSheetCount();
  202. while (styleSheetCount < 31 && this._blockedLoads.length > 0) {
  203. this._insertLinkNode(this._blockedLoads.shift());
  204. styleSheetCount++;
  205. }
  206. };
  207. return IE9CSSLoader;
  208. }(BrowserCSSLoader));
  209. var IE8CSSLoader = (function (_super) {
  210. __extends(IE8CSSLoader, _super);
  211. function IE8CSSLoader() {
  212. _super.call(this);
  213. }
  214. IE8CSSLoader.prototype.attachListeners = function (name, linkNode, callback, errorback) {
  215. linkNode.onload = function () {
  216. linkNode.onload = null;
  217. callback();
  218. };
  219. };
  220. return IE8CSSLoader;
  221. }(IE9CSSLoader));
  222. var NodeCSSLoader = (function () {
  223. function NodeCSSLoader() {
  224. this.fs = require.nodeRequire('fs');
  225. }
  226. NodeCSSLoader.prototype.load = function (name, cssUrl, externalCallback, externalErrorback) {
  227. var contents = this.fs.readFileSync(cssUrl, 'utf8');
  228. // Remove BOM
  229. if (contents.charCodeAt(0) === NodeCSSLoader.BOM_CHAR_CODE) {
  230. contents = contents.substring(1);
  231. }
  232. externalCallback(contents);
  233. };
  234. NodeCSSLoader.BOM_CHAR_CODE = 65279;
  235. return NodeCSSLoader;
  236. }());
  237. // ------------------------------ Finally, the plugin
  238. var CSSPlugin = (function () {
  239. function CSSPlugin(cssLoader) {
  240. this.cssLoader = cssLoader;
  241. }
  242. CSSPlugin.prototype.load = function (name, req, load, config) {
  243. config = config || {};
  244. var myConfig = config['vs/css'] || {};
  245. if (myConfig.inlineResources) {
  246. global.inlineResources = true;
  247. }
  248. var cssUrl = req.toUrl(name + '.css');
  249. this.cssLoader.load(name, cssUrl, function (contents) {
  250. // Contents has the CSS file contents if we are in a build
  251. if (config.isBuild) {
  252. CSSPlugin.BUILD_MAP[name] = contents;
  253. CSSPlugin.BUILD_PATH_MAP[name] = cssUrl;
  254. }
  255. load({});
  256. }, function (err) {
  257. if (typeof load.error === 'function') {
  258. load.error('Could not find ' + cssUrl + ' or it was empty');
  259. }
  260. });
  261. };
  262. CSSPlugin.prototype.write = function (pluginName, moduleName, write) {
  263. // getEntryPoint is a Monaco extension to r.js
  264. var entryPoint = write.getEntryPoint();
  265. // r.js destroys the context of this plugin between calling 'write' and 'writeFile'
  266. // so the only option at this point is to leak the data to a global
  267. global.cssPluginEntryPoints = global.cssPluginEntryPoints || {};
  268. global.cssPluginEntryPoints[entryPoint] = global.cssPluginEntryPoints[entryPoint] || [];
  269. global.cssPluginEntryPoints[entryPoint].push({
  270. moduleName: moduleName,
  271. contents: CSSPlugin.BUILD_MAP[moduleName],
  272. fsPath: CSSPlugin.BUILD_PATH_MAP[moduleName],
  273. });
  274. write.asModule(pluginName + '!' + moduleName, 'define([\'vs/css!' + entryPoint + '\'], {});');
  275. };
  276. CSSPlugin.prototype.writeFile = function (pluginName, moduleName, req, write, config) {
  277. if (global.cssPluginEntryPoints && global.cssPluginEntryPoints.hasOwnProperty(moduleName)) {
  278. var fileName = req.toUrl(moduleName + '.css');
  279. var contents = [
  280. '/*---------------------------------------------------------',
  281. ' * Copyright (c) Microsoft Corporation. All rights reserved.',
  282. ' *--------------------------------------------------------*/'
  283. ], entries = global.cssPluginEntryPoints[moduleName];
  284. for (var i = 0; i < entries.length; i++) {
  285. if (global.inlineResources) {
  286. contents.push(Utilities.rewriteOrInlineUrls(entries[i].fsPath, entries[i].moduleName, moduleName, entries[i].contents));
  287. }
  288. else {
  289. contents.push(Utilities.rewriteUrls(entries[i].moduleName, moduleName, entries[i].contents));
  290. }
  291. }
  292. write(fileName, contents.join('\r\n'));
  293. }
  294. };
  295. CSSPlugin.prototype.getInlinedResources = function () {
  296. return global.cssInlinedResources || [];
  297. };
  298. CSSPlugin.BUILD_MAP = {};
  299. CSSPlugin.BUILD_PATH_MAP = {};
  300. return CSSPlugin;
  301. }());
  302. CSSLoaderPlugin.CSSPlugin = CSSPlugin;
  303. var Utilities = (function () {
  304. function Utilities() {
  305. }
  306. Utilities.startsWith = function (haystack, needle) {
  307. return haystack.length >= needle.length && haystack.substr(0, needle.length) === needle;
  308. };
  309. /**
  310. * Find the path of a file.
  311. */
  312. Utilities.pathOf = function (filename) {
  313. var lastSlash = filename.lastIndexOf('/');
  314. if (lastSlash !== -1) {
  315. return filename.substr(0, lastSlash + 1);
  316. }
  317. else {
  318. return '';
  319. }
  320. };
  321. /**
  322. * A conceptual a + b for paths.
  323. * Takes into account if `a` contains a protocol.
  324. * Also normalizes the result: e.g.: a/b/ + ../c => a/c
  325. */
  326. Utilities.joinPaths = function (a, b) {
  327. function findSlashIndexAfterPrefix(haystack, prefix) {
  328. if (Utilities.startsWith(haystack, prefix)) {
  329. return Math.max(prefix.length, haystack.indexOf('/', prefix.length));
  330. }
  331. return 0;
  332. }
  333. var aPathStartIndex = 0;
  334. aPathStartIndex = aPathStartIndex || findSlashIndexAfterPrefix(a, '//');
  335. aPathStartIndex = aPathStartIndex || findSlashIndexAfterPrefix(a, 'http://');
  336. aPathStartIndex = aPathStartIndex || findSlashIndexAfterPrefix(a, 'https://');
  337. function pushPiece(pieces, piece) {
  338. if (piece === './') {
  339. // Ignore
  340. return;
  341. }
  342. if (piece === '../') {
  343. var prevPiece = (pieces.length > 0 ? pieces[pieces.length - 1] : null);
  344. if (prevPiece && prevPiece === '/') {
  345. // Ignore
  346. return;
  347. }
  348. if (prevPiece && prevPiece !== '../') {
  349. // Pop
  350. pieces.pop();
  351. return;
  352. }
  353. }
  354. // Push
  355. pieces.push(piece);
  356. }
  357. function push(pieces, path) {
  358. while (path.length > 0) {
  359. var slashIndex = path.indexOf('/');
  360. var piece = (slashIndex >= 0 ? path.substring(0, slashIndex + 1) : path);
  361. path = (slashIndex >= 0 ? path.substring(slashIndex + 1) : '');
  362. pushPiece(pieces, piece);
  363. }
  364. }
  365. var pieces = [];
  366. push(pieces, a.substr(aPathStartIndex));
  367. if (b.length > 0 && b.charAt(0) === '/') {
  368. pieces = [];
  369. }
  370. push(pieces, b);
  371. return a.substring(0, aPathStartIndex) + pieces.join('');
  372. };
  373. Utilities.commonPrefix = function (str1, str2) {
  374. var len = Math.min(str1.length, str2.length);
  375. for (var i = 0; i < len; i++) {
  376. if (str1.charCodeAt(i) !== str2.charCodeAt(i)) {
  377. break;
  378. }
  379. }
  380. return str1.substring(0, i);
  381. };
  382. Utilities.commonFolderPrefix = function (fromPath, toPath) {
  383. var prefix = Utilities.commonPrefix(fromPath, toPath);
  384. var slashIndex = prefix.lastIndexOf('/');
  385. if (slashIndex === -1) {
  386. return '';
  387. }
  388. return prefix.substring(0, slashIndex + 1);
  389. };
  390. Utilities.relativePath = function (fromPath, toPath) {
  391. if (Utilities.startsWith(toPath, '/') || Utilities.startsWith(toPath, 'http://') || Utilities.startsWith(toPath, 'https://')) {
  392. return toPath;
  393. }
  394. // Ignore common folder prefix
  395. var prefix = Utilities.commonFolderPrefix(fromPath, toPath);
  396. fromPath = fromPath.substr(prefix.length);
  397. toPath = toPath.substr(prefix.length);
  398. var upCount = fromPath.split('/').length;
  399. var result = '';
  400. for (var i = 1; i < upCount; i++) {
  401. result += '../';
  402. }
  403. return result + toPath;
  404. };
  405. Utilities._replaceURL = function (contents, replacer) {
  406. // Use ")" as the terminator as quotes are oftentimes not used at all
  407. return contents.replace(/url\(\s*([^\)]+)\s*\)?/g, function (_) {
  408. var matches = [];
  409. for (var _i = 1; _i < arguments.length; _i++) {
  410. matches[_i - 1] = arguments[_i];
  411. }
  412. var url = matches[0];
  413. // Eliminate starting quotes (the initial whitespace is not captured)
  414. if (url.charAt(0) === '"' || url.charAt(0) === '\'') {
  415. url = url.substring(1);
  416. }
  417. // The ending whitespace is captured
  418. while (url.length > 0 && (url.charAt(url.length - 1) === ' ' || url.charAt(url.length - 1) === '\t')) {
  419. url = url.substring(0, url.length - 1);
  420. }
  421. // Eliminate ending quotes
  422. if (url.charAt(url.length - 1) === '"' || url.charAt(url.length - 1) === '\'') {
  423. url = url.substring(0, url.length - 1);
  424. }
  425. if (!Utilities.startsWith(url, 'data:') && !Utilities.startsWith(url, 'http://') && !Utilities.startsWith(url, 'https://')) {
  426. url = replacer(url);
  427. }
  428. return 'url(' + url + ')';
  429. });
  430. };
  431. Utilities.rewriteUrls = function (originalFile, newFile, contents) {
  432. return this._replaceURL(contents, function (url) {
  433. var absoluteUrl = Utilities.joinPaths(Utilities.pathOf(originalFile), url);
  434. return Utilities.relativePath(newFile, absoluteUrl);
  435. });
  436. };
  437. Utilities.rewriteOrInlineUrls = function (originalFileFSPath, originalFile, newFile, contents) {
  438. var fs = require.nodeRequire('fs');
  439. var path = require.nodeRequire('path');
  440. return this._replaceURL(contents, function (url) {
  441. if (/\.(svg|png)$/.test(url)) {
  442. var fsPath = path.join(path.dirname(originalFileFSPath), url);
  443. var fileContents = fs.readFileSync(fsPath);
  444. if (fileContents.length < 3000) {
  445. global.cssInlinedResources = global.cssInlinedResources || [];
  446. var normalizedFSPath = fsPath.replace(/\\/g, '/');
  447. if (global.cssInlinedResources.indexOf(normalizedFSPath) >= 0) {
  448. console.warn('CSS INLINING IMAGE AT ' + fsPath + ' MORE THAN ONCE. CONSIDER CONSOLIDATING CSS RULES');
  449. }
  450. global.cssInlinedResources.push(normalizedFSPath);
  451. var MIME = /\.svg$/.test(url) ? 'image/svg+xml' : 'image/png';
  452. var DATA = ';base64,' + fileContents.toString('base64');
  453. if (/\.svg$/.test(url)) {
  454. // .svg => url encode as explained at https://codepen.io/tigt/post/optimizing-svgs-in-data-uris
  455. var newText = fileContents.toString()
  456. .replace(/"/g, '\'')
  457. .replace(/</g, '%3C')
  458. .replace(/>/g, '%3E')
  459. .replace(/&/g, '%26')
  460. .replace(/#/g, '%23')
  461. .replace(/\s+/g, ' ');
  462. var encodedData = ',' + newText;
  463. if (encodedData.length < DATA.length) {
  464. DATA = encodedData;
  465. }
  466. }
  467. return '"data:' + MIME + DATA + '"';
  468. }
  469. }
  470. var absoluteUrl = Utilities.joinPaths(Utilities.pathOf(originalFile), url);
  471. return Utilities.relativePath(newFile, absoluteUrl);
  472. });
  473. };
  474. return Utilities;
  475. }());
  476. CSSLoaderPlugin.Utilities = Utilities;
  477. (function () {
  478. var cssLoader = null;
  479. var isElectron = (typeof process !== 'undefined' && typeof process.versions !== 'undefined' && typeof process.versions['electron'] !== 'undefined');
  480. if (typeof process !== 'undefined' && process.versions && !!process.versions.node && !isElectron) {
  481. cssLoader = new NodeCSSLoader();
  482. }
  483. else if (typeof navigator !== 'undefined' && navigator.userAgent.indexOf('MSIE 9') >= 0) {
  484. cssLoader = new IE9CSSLoader();
  485. }
  486. else if (typeof navigator !== 'undefined' && navigator.userAgent.indexOf('MSIE 8') >= 0) {
  487. cssLoader = new IE8CSSLoader();
  488. }
  489. else {
  490. cssLoader = new BrowserCSSLoader();
  491. }
  492. define('vs/css', new CSSPlugin(cssLoader));
  493. })();
  494. })(CSSLoaderPlugin || (CSSLoaderPlugin = {}));
  495. //# sourceMappingURL=css.js.map