Skip to content

Commit

Permalink
Major update
Browse files Browse the repository at this point in the history
  • Loading branch information
pyrsmk committed Apr 9, 2016
1 parent b509ea2 commit 3d57e3e
Show file tree
Hide file tree
Showing 17 changed files with 221 additions and 248 deletions.
2 changes: 1 addition & 1 deletion .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
.gitignore
nodes_modules/
tests/
Gruntfile.js
gulpfile.js
package.json
25 changes: 4 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
toast 1.2.7
toast 2.0.0
===========

Toast is a tiny resource loader for JS and CSS files.
Expand All @@ -14,10 +14,10 @@ bower install toast
jam install pyrsmk-toast
```

Features
--------
Changes from v1
---------------

Toast has been designed to avoid FOUC issues when loading stylesheets on-the-fly since yepnope (or other libraries) didn't seem to handle this well. Of course, it could load scripts and it's tested against all major browsers versions.
Be careful! The loading state detector has been redesigned and additional loading verification callbacks have been dropped.

Syntax
------
Expand Down Expand Up @@ -53,23 +53,6 @@ toast(
);
```

Sometimes, on some browsers, scripts are not parsed yet when we want to use them (like calling a function from that script). To resolve that issue, toast provides a simple way. You need to provide an array with the resource and a validation callback. The loading process will continue when the validation callback will return a `true` value (a `false` value can be `false`, an empty string, `null`, `undefined`, etc).

```javascript
toast(
'css/screens.css',
['js/modernizr.js',function() {
return window.Modernizr;
}],
['js/classie.js',function() {
return window.IE;
}],
function() {
log('All scripts are fully loaded');
}
);
```

License
-------

Expand Down
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "toast",
"description": "A simple CSS/JS resource loader",
"main": "src/toast.js",
"main": "toast.js",
"repository": {
"type": "git",
"url": "git://github.com/pyrsmk/toast.git"
Expand Down
2 changes: 1 addition & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ gulp.task('publish', shell.task([

// ======================================== gulp

gulp.task('default', ['build', 'publish']);
gulp.task('default', ['build']);
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "pyrsmk-toast",
"description": "A simple CSS/JS resource loader",
"version": "1.2.7",
"version": "2.0.0",
"author": "Aurélien Delogu <pyrsmk@dreamysource.fr> (http://dreamysource.fr)",
"repository": {
"type": "git",
Expand Down
191 changes: 96 additions & 95 deletions src/toast.js
Original file line number Diff line number Diff line change
@@ -1,111 +1,112 @@
/*! toast 1.2.7 (https://github.com/pyrsmk/toast) */
/*! toast 2.0.0 (https://github.com/pyrsmk/toast) */

var handled_resources = {};

function toast() {
var head = document.getElementsByTagName('head')[0],
setTimeout = this.setTimeout,
loading=0,
decrementLoading = function() { --loading; },
i,

// Load as much resources as we can
loadResources = function(resources, callback, a, b) {
// Waiting for DOM readiness then load resources
if(!head) {
setTimeout(function() {
loadResources(resources);
}, 10);
}
// Load resources
else if(resources.length) {
i = -1;
while(a = resources[++i]) {
// Simple callback
if((b = typeof a) == 'function') {
callback=function(){a();return true;};
break;
}
// Resource
else if(b == 'string') {
loadResource(a);
}
// Resource + validation callback
else if(a.pop) {
loadResource(a[0]);
callback = a[1];
break;
}
}
watchResources(callback, Array.prototype.slice.call(resources, i+1));
}
},

// Load one resource
loadResource = function(resource, a, b) {
// Extract resource name
b = /(^.+\.\w+)(\?.*)?$/.exec(resource)[1];
// Verify if the resource is not already handled
if(handled_resources[b]) {
return;
}
// Load resource
handled_resources[b] = 1;
++loading;
// JS
if(/\.js$/.test(b)) {
// Create SCRIPT element
a = document.createElement('script');
a.src = resource;
head.appendChild(a);
// Watching loading state
if(a.onreadystatechange === null){
// Trident, Presto
a.onreadystatechange = watchScript;
// Load as much resources as we can
loadResources = function(resources) {
// Waiting for DOM readiness then load resources
if(!head) {
setTimeout(function() {
loadResources(resources);
}, 50);
}
// Load resources
else if(resources.length) {
var i = -1,
resource,
callback;
while(resource = resources[++i]) {
// Resource
if(typeof resource == 'string') {
loadResource(resource);
}
else{
// Webkit, Gecko (also IE>=9 and Presto)
a.onload=decrementLoading;
// Callback
else if(typeof resource == 'function') {
callback = resource;
break;
}
}
// CSS
else{
// Create LINK element
a = document.createElement('link');
a.rel = 'styleSheet';
a.href = resource;
head.appendChild(a);
// Watching loading state
watchStylesheet(a);
watchResources(callback, Array.prototype.slice.call(resources, i+1));
}
},

// Load one resource
loadResource = function(resource) {
// Extract resource name
var name = /(^.+\.\w+)(\?.*)?$/.exec(resource)[1],
node;
// Verify if the resource is not already handled
if(name in handled_resources) {
return;
}
// Add resource to loading stack
handled_resources[name] = false;
// JS
if(/\.js$/.test(name)) {
// Create SCRIPT element
node = document.createElement('script');
node.src = resource;
node.type = 'text/javascript';
head.appendChild(node);
// Watch loading state
var version = navigator.appVersion.match(/MSIE (\d)/);
if(version !== null && parseInt(version[1], 10) < 9) {
// IE
node.onreadystatechange = function() {
if(/ded|co/.test(this.readyState)) {
handled_resources[name] = true;
}
};
}
},

// Watch if all resources have been loaded
watchResources = function(callback, resourcesToLoad) {
if(!loading) {
if(!callback || callback()) {
loadResources(resourcesToLoad);
return;
}
else {
// Other browsers
node.onload = function() {
handled_resources[name] = true;
};
}
setTimeout(function() { watchResources(callback, resourcesToLoad); }, 10);
},

// Watch if a CSS resource has been loaded
watchStylesheet = function(node) {
if(node.sheet || node.styleSheet) {
decrementLoading();
}
// CSS
else if(/\.css$/.test(name)) {
// Create LINK element
node = document.createElement('link');
node.rel = 'styleSheet';
node.href = resource;
head.appendChild(node);
// Watch loading state
watchStylesheet(node, name);
}
},

// Watch if all resources have been loaded
watchResources = function(callback, resourcesToLoad) {
for(var name in handled_resources) {
if(!handled_resources[name]) {
setTimeout(function() {
watchResources(callback, resourcesToLoad);
}, 50);
return;
}
setTimeout(function() { watchStylesheet(node); }, 10);
},

// Watch if a script has been loaded
watchScript = function() {
if(/ded|co/.test(this.readyState)) {
decrementLoading();
}
};
}
if(typeof callback == 'function') {
callback();
}
loadResources(resourcesToLoad);
},

// Watch if a CSS resource has been loaded
watchStylesheet = function(node, name) {
if(node.sheet || node.styleSheet) {
handled_resources[name] = true;
}
else {
setTimeout(function() {
watchStylesheet(node, name);
}, 50);
}
};

// Load resources
loadResources(arguments);
Expand Down
6 changes: 6 additions & 0 deletions tests/foo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
if(!('foo' in window)) {
window.foo = 1;
}
else {
++window.foo;
}
1 change: 0 additions & 1 deletion tests/resources/a.css

This file was deleted.

1 change: 0 additions & 1 deletion tests/resources/a.js

This file was deleted.

1 change: 0 additions & 1 deletion tests/resources/b.css

This file was deleted.

6 changes: 0 additions & 6 deletions tests/resources/b.js

This file was deleted.

1 change: 0 additions & 1 deletion tests/resources/c.css

This file was deleted.

1 change: 0 additions & 1 deletion tests/resources/c.js

This file was deleted.

1 change: 0 additions & 1 deletion tests/resources/d.js

This file was deleted.

34 changes: 14 additions & 20 deletions tests/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,50 +6,44 @@ QUnit.test('One resource', function(assert) {

// One JS resource
toast(
['resources/a.js', function() { return window.a; }],
'foo.js',
function() {
assert.ok(true, 'One JS resource loaded');
assert.ok('foo' in window && foo == 1, 'One JS resource loaded');
done1();
}
);

// One CSS resource
toast(
['resources/a.css', function() { return document.styleSheets.length >= 1; }],
'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.1/animate.min.css',
function() {
assert.ok(true, 'One CSS resource loaded');
assert.ok(document.styleSheets.length == 2, 'One CSS resource loaded');
done2();
}
);
});

QUnit.test('Several resources', function(assert) {
var done1 = assert.async(),
done2 = assert.async(),
done3 = assert.async();
done2 = assert.async();

assert.expect(4);

toast(
'resources/b.js?v=1',
'resources/b.css',
'https://code.jquery.com/jquery-2.2.3.min.js',
'https://rawgit.com/pyrsmk/qwest/master/qwest.min.js',
'https://rawgit.com/pyrsmk/Horizon/master/build/minified/Horizon.min.js',
function() {
assert.ok(true, 'Callback called');
assert.ok(typeof jQuery == 'function', 'jQuery loaded');
assert.ok(typeof qwest == 'object', 'qwest loaded');
assert.ok(typeof Horizon == 'object', 'Horizon loaded');
done1();
},
'resources/c.js',
'resources/c.css',
['resources/d.js', function() { return window.b && window.c && window.d; }],
function() {
assert.ok(true, 'Three JS resources loaded');
assert.ok(document.styleSheets.length >= 2, 'Two CSS resources loaded');
done2();

toast(
'resources/b.js',
'foo.js',
function() {
assert.ok(window.b == 1, 'Cannot call a resource twice');
done3();
assert.ok(foo == 1, 'Cannot load a resource twice');
done2();
}
);
}
Expand Down
Loading

0 comments on commit 3d57e3e

Please sign in to comment.