123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- //
- // index.js
- // Should expose the additional browser functions on to the less object
- //
- var addDataAttr = require("./utils").addDataAttr,
- browser = require("./browser");
- module.exports = function(window, options) {
- var document = window.document;
- var less = require('../less')();
- //module.exports = less;
- less.options = options;
- var environment = less.environment,
- FileManager = require("./file-manager")(options, less.logger),
- fileManager = new FileManager();
- environment.addFileManager(fileManager);
- less.FileManager = FileManager;
- require("./log-listener")(less, options);
- var errors = require("./error-reporting")(window, less, options);
- var cache = less.cache = options.cache || require("./cache")(window, options, less.logger);
- require('./image-size')(less.environment);
- //Setup user functions
- if (options.functions) {
- less.functions.functionRegistry.addMultiple(options.functions);
- }
- var typePattern = /^text\/(x-)?less$/;
- function postProcessCSS(styles) { // deprecated, use a plugin for postprocesstasks
- if (options.postProcessor && typeof options.postProcessor === 'function') {
- styles = options.postProcessor.call(styles, styles) || styles;
- }
- return styles;
- }
- function clone(obj) {
- var cloned = {};
- for (var prop in obj) {
- if (obj.hasOwnProperty(prop)) {
- cloned[prop] = obj[prop];
- }
- }
- return cloned;
- }
- // only really needed for phantom
- function bind(func, thisArg) {
- var curryArgs = Array.prototype.slice.call(arguments, 2);
- return function() {
- var args = curryArgs.concat(Array.prototype.slice.call(arguments, 0));
- return func.apply(thisArg, args);
- };
- }
- function loadStyles(modifyVars) {
- var styles = document.getElementsByTagName('style'),
- style;
- for (var i = 0; i < styles.length; i++) {
- style = styles[i];
- if (style.type.match(typePattern)) {
- var instanceOptions = clone(options);
- instanceOptions.modifyVars = modifyVars;
- var lessText = style.innerHTML || '';
- instanceOptions.filename = document.location.href.replace(/#.*$/, '');
- /*jshint loopfunc:true */
- // use closure to store current style
- less.render(lessText, instanceOptions,
- bind(function(style, e, result) {
- if (e) {
- errors.add(e, "inline");
- } else {
- style.type = 'text/css';
- if (style.styleSheet) {
- style.styleSheet.cssText = result.css;
- } else {
- style.innerHTML = result.css;
- }
- }
- }, null, style));
- }
- }
- }
- function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) {
- var instanceOptions = clone(options);
- addDataAttr(instanceOptions, sheet);
- instanceOptions.mime = sheet.type;
- if (modifyVars) {
- instanceOptions.modifyVars = modifyVars;
- }
- function loadInitialFileCallback(loadedFile) {
- var data = loadedFile.contents,
- path = loadedFile.filename,
- webInfo = loadedFile.webInfo;
- var newFileInfo = {
- currentDirectory: fileManager.getPath(path),
- filename: path,
- rootFilename: path,
- relativeUrls: instanceOptions.relativeUrls};
- newFileInfo.entryPath = newFileInfo.currentDirectory;
- newFileInfo.rootpath = instanceOptions.rootpath || newFileInfo.currentDirectory;
- if (webInfo) {
- webInfo.remaining = remaining;
- var css = cache.getCSS(path, webInfo, instanceOptions.modifyVars);
- if (!reload && css) {
- webInfo.local = true;
- callback(null, css, data, sheet, webInfo, path);
- return;
- }
- }
- //TODO add tests around how this behaves when reloading
- errors.remove(path);
- instanceOptions.rootFileInfo = newFileInfo;
- less.render(data, instanceOptions, function(e, result) {
- if (e) {
- e.href = path;
- callback(e);
- } else {
- result.css = postProcessCSS(result.css);
- cache.setCSS(sheet.href, webInfo.lastModified, instanceOptions.modifyVars, result.css);
- callback(null, result.css, data, sheet, webInfo, path);
- }
- });
- }
- fileManager.loadFile(sheet.href, null, instanceOptions, environment, function(e, loadedFile) {
- if (e) {
- callback(e);
- return;
- }
- loadInitialFileCallback(loadedFile);
- });
- }
- function loadStyleSheets(callback, reload, modifyVars) {
- for (var i = 0; i < less.sheets.length; i++) {
- loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1), modifyVars);
- }
- }
- function initRunningMode() {
- if (less.env === 'development') {
- less.watchTimer = setInterval(function () {
- if (less.watchMode) {
- fileManager.clearFileCache();
- loadStyleSheets(function (e, css, _, sheet, webInfo) {
- if (e) {
- errors.add(e, e.href || sheet.href);
- } else if (css) {
- browser.createCSS(window.document, css, sheet);
- }
- });
- }
- }, options.poll);
- }
- }
- //
- // Watch mode
- //
- less.watch = function () {
- if (!less.watchMode ) {
- less.env = 'development';
- initRunningMode();
- }
- this.watchMode = true;
- return true;
- };
- less.unwatch = function () {clearInterval(less.watchTimer); this.watchMode = false; return false; };
- //
- // Synchronously get all <link> tags with the 'rel' attribute set to
- // "stylesheet/less".
- //
- less.registerStylesheetsImmediately = function() {
- var links = document.getElementsByTagName('link');
- less.sheets = [];
- for (var i = 0; i < links.length; i++) {
- if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
- (links[i].type.match(typePattern)))) {
- less.sheets.push(links[i]);
- }
- }
- };
- //
- // Asynchronously get all <link> tags with the 'rel' attribute set to
- // "stylesheet/less", returning a Promise.
- //
- less.registerStylesheets = function() {
- return new Promise(function(resolve, reject) {
- less.registerStylesheetsImmediately();
- resolve();
- });
- };
- //
- // With this function, it's possible to alter variables and re-render
- // CSS without reloading less-files
- //
- less.modifyVars = function(record) {
- return less.refresh(true, record, false);
- };
- less.refresh = function (reload, modifyVars, clearFileCache) {
- if ((reload || clearFileCache) && clearFileCache !== false) {
- fileManager.clearFileCache();
- }
- return new Promise(function (resolve, reject) {
- var startTime, endTime, totalMilliseconds, remainingSheets;
- startTime = endTime = new Date();
- // Set counter for remaining unprocessed sheets
- remainingSheets = less.sheets.length;
- if (remainingSheets === 0) {
- endTime = new Date();
- totalMilliseconds = endTime - startTime;
- less.logger.info("Less has finished and no sheets were loaded.");
- resolve({
- startTime: startTime,
- endTime: endTime,
- totalMilliseconds: totalMilliseconds,
- sheets: less.sheets.length
- });
- } else {
- // Relies on less.sheets array, callback seems to be guaranteed to be called for every element of the array
- loadStyleSheets(function (e, css, _, sheet, webInfo) {
- if (e) {
- errors.add(e, e.href || sheet.href);
- reject(e);
- return;
- }
- if (webInfo.local) {
- less.logger.info("Loading " + sheet.href + " from cache.");
- } else {
- less.logger.info("Rendered " + sheet.href + " successfully.");
- }
- browser.createCSS(window.document, css, sheet);
- less.logger.info("CSS for " + sheet.href + " generated in " + (new Date() - endTime) + 'ms');
- // Count completed sheet
- remainingSheets--;
- // Check if the last remaining sheet was processed and then call the promise
- if (remainingSheets === 0) {
- totalMilliseconds = new Date() - startTime;
- less.logger.info("Less has finished. CSS generated in " + totalMilliseconds + 'ms');
- resolve({
- startTime: startTime,
- endTime: endTime,
- totalMilliseconds: totalMilliseconds,
- sheets: less.sheets.length
- });
- }
- endTime = new Date();
- }, reload, modifyVars);
- }
- loadStyles(modifyVars);
- });
- };
- less.refreshStyles = loadStyles;
- return less;
- };
|