Skip to content

Commit

Permalink
fixes #56 and #57
Browse files Browse the repository at this point in the history
  • Loading branch information
guybedford committed Mar 29, 2013
1 parent 54f5869 commit 758976f
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 70 deletions.
77 changes: 31 additions & 46 deletions css-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,45 +89,6 @@ define(['require', './normalize'], function(req, normalize) {
.replace(/[\r]/g, "\\r");
}

var baseUrl;
var cssBase;

var loadCSS = function(cssId, parse) {
if (!baseUrl) {
var baseParts = req.toUrl('base_url').split('/');
baseParts.pop();
baseUrl = baseParts.join('/') + '/';
}

var fileUrl = cssId;

if (fileUrl.substr(fileUrl.length - 4, 4) != '.css' && !parse)
fileUrl += '.css';

fileUrl = req.toUrl(fileUrl);

//external URLS don't get added (just like JS requires)
if (fileUrl.substr(0, 7) == 'http://' || fileUrl.substr(0, 8) == 'https://')
return;

//add to the buffer
var css = loadCSSFile(fileUrl);

//make file url absolute
//if (fileUrl.substr(0, 1) != '/')
// fileUrl = '/' + fileUrl;

//normalize all css to the base url - as the common path reference
//for injection we then only need one normalization from the base url
//css = normalize(css, fileUrl, baseUrl);

// parse if necessary
if (parse)
css = parse(css);

return css;
}

// NB add @media query support for media imports
var importRegEx = /@import\s*(url)?\s*(('([^']*)'|"([^"]*)")|\(('([^']*)'|"([^"]*)"|([^\)]*))\))\s*;?/g;

Expand Down Expand Up @@ -159,8 +120,6 @@ define(['require', './normalize'], function(req, normalize) {
else
importUrl = baseUrl + importUrl;

console.log('importing ' + importUrl);

importUrls.push(importUrl);
importIndex.push(importRegEx.lastIndex - match[0].length);
importLength.push(match[0].length);
Expand All @@ -179,8 +138,11 @@ define(['require', './normalize'], function(req, normalize) {
return css;
}


var baseUrl;
var cssBase;
var curModule;
cssAPI.load = function(name, req, load, config) {
cssAPI.load = function(name, req, load, config, parse) {
if (!cssBase) {
cssBase = config.cssBase || config.appDir || baseUrl;
if (cssBase.substr(cssBase.length - 1, 1) != '/')
Expand All @@ -196,10 +158,31 @@ define(['require', './normalize'], function(req, normalize) {
break;
}
}

if (!baseUrl) {
var baseParts = req.toUrl('base_url').split('/');
baseParts.pop();
baseUrl = baseParts.join('/') + '/';
}

//store config
cssAPI.config = cssAPI.config || config;
//just return - 'write' calls are made after exclusions so we run loading there

name += !parse ? '.css' : '.less';

var fileUrl = req.toUrl(name);

//external URLS don't get added (just like JS requires)
if (fileUrl.substr(0, 7) == 'http://' || fileUrl.substr(0, 8) == 'https://')
return;

//add to the buffer
_cssBuffer[name] = loadCSSFile(fileUrl);

// parse if necessary
if (parse)
_cssBuffer[name] = parse(_cssBuffer[name]);

load();
}

Expand All @@ -211,13 +194,15 @@ define(['require', './normalize'], function(req, normalize) {

//list of cssIds included in this layer
var _layerBuffer = [];
var _cssBuffer = [];

cssAPI.write = function(pluginName, moduleName, write, extension, parse) {
cssAPI.write = function(pluginName, moduleName, write, parse) {
//external URLS don't get added (just like JS requires)
if (moduleName.substr(0, 7) == 'http://' || moduleName.substr(0, 8) == 'https://')
return;

_layerBuffer.push(loadCSS(moduleName + (extension ? '.' + extension : ''), parse));
var resourceName = moduleName + (!parse ? '.css' : '.less');
_layerBuffer.push(_cssBuffer[resourceName]);

var separateCSS = false;
if (cssAPI.config.separateCSS)
Expand All @@ -227,7 +212,7 @@ define(['require', './normalize'], function(req, normalize) {
if (separateCSS)
write.asModule(pluginName + '!' + moduleName, 'define(function(){})');
else
write("requirejs.s.contexts._.nextTick = function(f){f()}; require(['css'], function(css) { css.addBuffer('" + moduleName + (parse ? ".less', true" : ".css'") + "); }); requirejs.s.contexts._.nextTick = requirejs.nextTick;");
write("requirejs.s.contexts._.nextTick = function(f){f()}; require(['css'], function(css) { css.addBuffer('" + resourceName + "'); }); requirejs.s.contexts._.nextTick = requirejs.nextTick;");
}

cssAPI.onLayerEnd = function(write, data, parser) {
Expand Down
94 changes: 70 additions & 24 deletions css.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,30 @@ define(['./normalize'], function(normalize) {
//main api object
var cssAPI = {};

// for builds, store css for injection
cssAPI.bufferLoaded = {};
cssAPI.pluginBuilder = './css-builder';

// used by layer builds to register their css buffers
var buffer = [];
cssAPI.addBuffer = function(cssId) {
if (indexOf(buffer, cssId) == -1)
buffer.push(cssId);

// the current layer buffer items (from addBuffer)
var curBuffer = [];

// the callbacks for buffer loads
var onBufferLoad = [];

// the full list of resources in the buffer
var bufferResources = [];

cssAPI.addBuffer = function(resourceId) {
// just in case layer scripts are included twice, also check
// against the previous buffers
if (indexOf(curBuffer, resourceId) != -1)
return;
if (indexOf(bufferResources, resourceId) != -1)
return;
curBuffer.push(resourceId);
bufferResources.push(resourceId);
}
cssAPI.setBuffer = function(css, parser) {
cssAPI.setBuffer = function(css, isLess) {
var pathname = window.location.pathname.split('/');
pathname.pop();
pathname = pathname.join('/') + '/';
Expand All @@ -96,15 +109,53 @@ define(['./normalize'], function(normalize) {

cssAPI.inject(normalize(css, baseUrl, pathname));

for (var i = 0; i < buffer.length; i++)
if (cssAPI.bufferLoaded[buffer[i]] !== true && (!parser == (buffer[i].substr(buffer[i].length - 4, 4) == '.css')))
// set up attach callback if registered
// clear the current buffer for the next layer
// (just the less or css part as we have two buffers in one effectively)
for (var i = 0; i < curBuffer.length; i++) {
// find the resources in the less or css buffer dependening which one this is
if ((isLess && curBuffer[i].substr(curBuffer[i].length - 5, 5) == '.less') ||
(!isLess && curBuffer[i].substr(curBuffer[i].length - 4, 4) == '.css')) {

// mark that the onBufferLoad is about to be called (set to true if not already a callback function)
onBufferLoad[curBuffer[i]] = onBufferLoad[curBuffer[i]] || true;

// set a short timeout (as injection isn't instant in Chrome), then call the load
(function(i) {
setTimeout(function() {
if (typeof cssAPI.bufferLoaded[buffer[i]] == 'function')
cssAPI.bufferLoaded[buffer[i]]();
cssAPI.bufferLoaded[buffer[i]] = true;
})
if (typeof onBufferLoad[curBuffer[i]] == 'function')
onBufferLoad[curBuffer[i]]();
// remove from onBufferLoad to indicate loaded
delete onBufferLoad[curBuffer[i]];
}, 7);
})(i);
}
}
}
cssAPI.attachBuffer = function(resourceId, load) {
// attach can happen during buffer collecting, or between injection and callback
// we assume it is not possible to attach multiple callbacks
// requirejs plugin load function ensures this by queueing duplicate calls

// check if the resourceId is in the current buffer
for (var i = 0; i < curBuffer.length; i++)
if (curBuffer[i] == resourceId) {
onBufferLoad[resourceId] = load;
return true;
}

// check if the resourceId is waiting for injection callback
// (onBufferLoad === true is a shortcut indicator for this)
if (onBufferLoad[resourceId] === true) {
onBufferLoad[resourceId] = load;
return true;
}

// if it's in the full buffer list and not either of the above, its loaded already
if (bufferResources[resourceId]) {
load();
return true;
}
}

var webkitLoadCheck = function(link, callback) {
Expand Down Expand Up @@ -336,19 +387,14 @@ define(['./normalize'], function(normalize) {

waitSeconds = waitSeconds || config.waitSeconds || 7;

var fileUrl = cssId + (parse ? '.less' : '.css');
var resourceId = cssId + (!parse ? '.css' : '.less');

// if in the built buffer do injection
for (var i = 0; i < buffer.length; i++)
if (buffer[i] == fileUrl) {
if (cssAPI.bufferLoaded[fileUrl] === true)
load();
else
cssAPI.bufferLoaded[fileUrl] = load;
return;
}
// attach the load function to a buffer if there is one in registration
// if not, we do a full injection load
if (cssAPI.attachBuffer(resourceId, load))
return;

fileUrl = req.toUrl(fileUrl);
fileUrl = req.toUrl(resourceId);

if (!alerted && testing) {
alert(hackLinks ? 'hacking links' : 'not hacking');
Expand Down

0 comments on commit 758976f

Please sign in to comment.