file-manager.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. /* global window, XMLHttpRequest */
  2. module.exports = function(options, logger) {
  3. var AbstractFileManager = require('../less/environment/abstract-file-manager.js');
  4. var fileCache = {};
  5. // TODOS - move log somewhere. pathDiff and doing something similar in node. use pathDiff in the other browser file for the initial load
  6. var FileManager = function() {
  7. };
  8. FileManager.prototype = new AbstractFileManager();
  9. FileManager.prototype.alwaysMakePathsAbsolute = function alwaysMakePathsAbsolute() {
  10. return true;
  11. };
  12. FileManager.prototype.join = function join(basePath, laterPath) {
  13. if (!basePath) {
  14. return laterPath;
  15. }
  16. return this.extractUrlParts(laterPath, basePath).path;
  17. };
  18. FileManager.prototype.doXHR = function doXHR(url, type, callback, errback) {
  19. var xhr = new XMLHttpRequest();
  20. var async = options.isFileProtocol ? options.fileAsync : true;
  21. if (typeof xhr.overrideMimeType === 'function') {
  22. xhr.overrideMimeType('text/css');
  23. }
  24. logger.debug('XHR: Getting \'' + url + '\'');
  25. xhr.open('GET', url, async);
  26. xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5');
  27. xhr.send(null);
  28. function handleResponse(xhr, callback, errback) {
  29. if (xhr.status >= 200 && xhr.status < 300) {
  30. callback(xhr.responseText,
  31. xhr.getResponseHeader('Last-Modified'));
  32. } else if (typeof errback === 'function') {
  33. errback(xhr.status, url);
  34. }
  35. }
  36. if (options.isFileProtocol && !options.fileAsync) {
  37. if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) {
  38. callback(xhr.responseText);
  39. } else {
  40. errback(xhr.status, url);
  41. }
  42. } else if (async) {
  43. xhr.onreadystatechange = function () {
  44. if (xhr.readyState == 4) {
  45. handleResponse(xhr, callback, errback);
  46. }
  47. };
  48. } else {
  49. handleResponse(xhr, callback, errback);
  50. }
  51. };
  52. FileManager.prototype.supports = function(filename, currentDirectory, options, environment) {
  53. return true;
  54. };
  55. FileManager.prototype.clearFileCache = function() {
  56. fileCache = {};
  57. };
  58. FileManager.prototype.loadFile = function loadFile(filename, currentDirectory, options, environment) {
  59. // TODO: Add prefix support like less-node?
  60. // What about multiple paths?
  61. if (currentDirectory && !this.isPathAbsolute(filename)) {
  62. filename = currentDirectory + filename;
  63. }
  64. filename = options.ext ? this.tryAppendExtension(filename, options.ext) : filename;
  65. options = options || {};
  66. // sheet may be set to the stylesheet for the initial load or a collection of properties including
  67. // some context variables for imports
  68. var hrefParts = this.extractUrlParts(filename, window.location.href);
  69. var href = hrefParts.url;
  70. var self = this;
  71. return new Promise(function(resolve, reject) {
  72. if (options.useFileCache && fileCache[href]) {
  73. try {
  74. var lessText = fileCache[href];
  75. return resolve({ contents: lessText, filename: href, webInfo: { lastModified: new Date() }});
  76. } catch (e) {
  77. return reject({ filename: href, message: 'Error loading file ' + href + ' error was ' + e.message });
  78. }
  79. }
  80. self.doXHR(href, options.mime, function doXHRCallback(data, lastModified) {
  81. // per file cache
  82. fileCache[href] = data;
  83. // Use remote copy (re-parse)
  84. resolve({ contents: data, filename: href, webInfo: { lastModified: lastModified }});
  85. }, function doXHRError(status, url) {
  86. reject({ type: 'File', message: '\'' + url + '\' wasn\'t found (' + status + ')', href: href });
  87. });
  88. });
  89. };
  90. return FileManager;
  91. };