Comparing version 0.0.1 to 0.0.2
174
index.js
@@ -15,71 +15,30 @@ | ||
/** | ||
* Converts `value` to a string using `Object.prototype.toString`. | ||
* | ||
* @private | ||
* @param {*} value The value to convert. | ||
* @returns {string} Returns the converted string. | ||
*/ | ||
function toString(value) { | ||
return Object.prototype.toString.call(value); | ||
}; | ||
/** | ||
* Array tag reference. | ||
*/ | ||
var arrayTag = '[object Array]'; | ||
/** | ||
* Checks if `value` is classified as an `Array` object. | ||
* | ||
* @param {*} value The value to check. | ||
* @return Returns `true` if `value` is an array, else `false`. | ||
*/ | ||
function isArray(value) { | ||
return toString(value) === arrayTag; | ||
}; | ||
/** | ||
* Function tag reference. | ||
*/ | ||
var functionTag = '[object Function]'; | ||
/** | ||
* Checks if `value` is classified as an `Function` object. | ||
* | ||
* @param {*} value The value to check. | ||
* @return Returns `true` if `value` is a function, else `false`. | ||
*/ | ||
function isFunction(value) { | ||
return toString(value) === functionTag; | ||
} | ||
/** | ||
* Loads and inserts stylesheets with the specified `href` and `options`; | ||
* | ||
* @param {Array|string} href | ||
* @param {Object} [options] | ||
* @param {Object|Function} [options] | ||
* @param {DOMElement} [options.before] | ||
* @param {string} [options.media] | ||
* @param {Function} [options.done] | ||
* @param {Function} [options.complete] | ||
*/ | ||
function loadcss(href, options) { | ||
options || (options = {}); | ||
if (({}).toString.call(options) === '[object Function]') { | ||
options = { complete: options }; | ||
} | ||
var doc = document; | ||
var styles = doc.styleSheets; | ||
var hrefs = isArray(href) ? href : [href]; // cast href to array of hrefs | ||
var length = hrefs.length; | ||
var sheets = doc.styleSheets; | ||
var hrefs = ({}).toString.call(href) === '[object Array]' ? href : [href]; | ||
var media = options.media ? options.media : 'all'; | ||
var oncomplete = options.complete || function () {}; | ||
var links = []; | ||
// reference to node to insert links before | ||
var before; | ||
if (options && options.before) { | ||
if (options.before) { | ||
before = options.before; | ||
} else { | ||
// if no before node specified, then default reference to the last node of | ||
// documents head element | ||
var refs = (doc.body || doc.getElementsByTagName('head')[0]).childNodes; | ||
@@ -89,50 +48,3 @@ before = refs[refs.length - 1]; | ||
// reference to stylesheets media type | ||
var media; | ||
if (options && options.media) { | ||
media = options.media; | ||
} else { | ||
// if no media type specified, then default media type to `all` value | ||
media = 'all'; | ||
} | ||
// reference to a callback function | ||
var done = isFunction(options) ? options : options.done || function () {}; | ||
// reference to array of link nodes | ||
var links = []; | ||
// insert link when document body is processed | ||
ready(function () { | ||
var index = -1; | ||
while (++index < length) { | ||
var referenceNode; | ||
if (options && options.before) { | ||
referenceNode = before; | ||
} else { | ||
referenceNode = before.nextSibling; | ||
} | ||
links[index] = doc.createElement('link'); | ||
links[index].href = hrefs[index]; | ||
links[index].media = media; | ||
links[index].rel = 'stylesheet'; | ||
before.parentNode.insertBefore(links[index], referenceNode); | ||
} | ||
load(); // begin stylesheets loading | ||
}); | ||
/** | ||
* Executes `callback` when document body is ready | ||
* @param {Function} callback | ||
*/ | ||
function ready(callback) { | ||
function onready(callback) { | ||
if (doc.body){ | ||
@@ -143,50 +55,54 @@ return callback(); | ||
callasync(function () { | ||
ready(callback); | ||
onready(callback); | ||
}); | ||
} | ||
function load() { | ||
function onloaded() { | ||
var loaded = 0; | ||
var index = -1; | ||
var loaded = 0; | ||
// test wether document has applied stylesheets | ||
var length = links.length; | ||
while (++index < length) { | ||
if (exists(href[index]) && ++loaded === length) { | ||
// when all stylesheets applied, call done and exit | ||
return complete(links); | ||
if (exists(links[index].href) && ++loaded === length) { | ||
return oncomplete(links); | ||
} | ||
} | ||
// continue loading stylesheets (recursevly) | ||
callasync(load); | ||
callasync(onloaded); | ||
} | ||
/** | ||
* Test wether stylesheet with `href` has been applied to document. | ||
* @param {string} href Href attribute of the stylesheet. | ||
* @return {boolean} | ||
*/ | ||
function exists(href) { | ||
var index = -1; | ||
var length = styles.length; | ||
var length = sheets.length; | ||
while (++index < length) { | ||
if (styles[index].href && styles[index].href.indexOf(href) > -1) { | ||
if (sheets[index].href === null || sheets[index].href.length === 0) { | ||
continue; | ||
} | ||
if (sheets[index].href === href) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
/** | ||
* Executes when all stylesheets where loaded. | ||
*/ | ||
onready(function () { | ||
var index = -1; | ||
var length = hrefs.length; | ||
var referenceNode = options.before ? before : before.nextSibling; | ||
function complete() { | ||
done(links); | ||
} | ||
while (++index < length) { | ||
links[index] = doc.createElement('link'); | ||
links[index].rel = 'stylesheet'; | ||
links[index].href = hrefs[index]; | ||
links[index].media = media; | ||
before.parentNode.insertBefore(links[index], referenceNode); | ||
} | ||
callasync(onloaded); | ||
}); | ||
return links; | ||
} |
{ | ||
"name": "loadcss", | ||
"version": "0.0.1", | ||
"version": "0.0.2", | ||
"description": "Fast and reliable utility to asynchronously load multiple css files", | ||
"main": "index.js", | ||
"directories": { | ||
"example": "example" | ||
}, | ||
"keywords": ["css", "stylesheets", "preload", "load"], | ||
"dependencies": { | ||
@@ -20,3 +18,4 @@ "callasync": "^1.0.0" | ||
"test": "node-qunit-phantomjs test/index.html", | ||
"build": "browserify index.js -s loadcss | uglifyjs -o loadcss.js" | ||
"prebuild": "rm -rf dist", | ||
"build": "mkdir -p dist && browserify index.js -s loadcss -o dist/loadcss.js" | ||
}, | ||
@@ -27,4 +26,4 @@ "repository": { | ||
}, | ||
"author": "Anton Yefremov", | ||
"license": "ISC", | ||
"author": "Anton Yefremov <anton.yefremov@gmail.com>", | ||
"license": "MIT", | ||
"bugs": { | ||
@@ -31,0 +30,0 @@ "url": "https://github.com/yefremov/loadcss/issues" |
# loadcss | ||
[![npm version](https://badge.fury.io/js/loadcss.svg)](https://badge.fury.io/js/loadcss) | ||
[![Build Status](https://travis-ci.org/yefremov/loadcss.svg?branch=master)](https://travis-ci.org/yefremov/loadcss) | ||
Fast and reliable utility to asynchronously load multiple css files and apply to | ||
the document. | ||
## Installation | ||
```bash | ||
$ npm install loadcss | ||
``` | ||
## API | ||
```js | ||
import loadcss from 'loadcss'; | ||
// load a single css file | ||
loadcss('/foo.css', links => { | ||
links.forEach(link => console.log(link.href)); | ||
}); | ||
// load multiple css files | ||
loadcss(['/a/foo.css', '/b/bar.css'], links => { | ||
links.forEach(link => console.log(link.href)); | ||
}); | ||
``` | ||
## Running tests | ||
@@ -7,0 +32,0 @@ |
@@ -0,61 +1,124 @@ | ||
(function (window) { | ||
QUnit.test("should be exposed to window object", function( assert ) { | ||
assert.expect(2); | ||
assert.ok(window.loadcss, "loadcss should exist on the window object" ); | ||
assert.ok(typeof window.loadcss === "function", "loadcss should be a function" ); | ||
}); | ||
var getStyles = window.getComputedStyle | ||
? function (node) { return window.getComputedStyle(node, null) } | ||
: function (node) { return node.currentStyle }; | ||
QUnit.test("should load a single css file", function( assert ) { | ||
assert.expect(1); | ||
QUnit.assert.contains = function(needle, target, message) { | ||
var actual = target.indexOf(needle) > -1; | ||
var done = assert.async(1); | ||
this.pushResult({ | ||
result: actual, | ||
actual: actual, | ||
expected: needle, | ||
message: message | ||
}); | ||
}; | ||
loadcss("fixtures/a.css", function (links) { | ||
assert.ok(links[0].href.indexOf("fixtures/a.css") > -1); | ||
done(); | ||
QUnit.test('should be exposed to window object', function( assert ) { | ||
assert.expect(2); | ||
assert.ok(window.loadcss); | ||
assert.ok(typeof window.loadcss === 'function'); | ||
}); | ||
}); | ||
QUnit.test("should load a multiple css files", function( assert ) { | ||
assert.expect(2); | ||
QUnit.test('should load a single css file', function( assert ) { | ||
assert.expect(1); | ||
var done = assert.async(1); | ||
var done = assert.async(1); | ||
loadcss(["fixtures/b.css", "fixtures/c.css"], function (links) { | ||
assert.ok(links[0].href.indexOf("fixtures/b.css") > -1); | ||
assert.ok(links[1].href.indexOf("fixtures/c.css") > -1); | ||
done(); | ||
loadcss('./fixtures/a.css', function (links) { | ||
var a = links.shift(); | ||
assert.contains('fixtures/a.css', a.href); | ||
done(); | ||
}); | ||
}); | ||
QUnit.test("should load css with a media specified media type", function( assert ) { | ||
assert.expect(1); | ||
QUnit.test('should load a multiple css files', function(assert) { | ||
assert.expect(2); | ||
var done = assert.async(1); | ||
loadcss(["fixtures/d.css"], { | ||
media: "screen", | ||
done: function (links) { | ||
console.log(links); | ||
assert.ok(links[0].media === 'screen'); | ||
done(); | ||
} | ||
loadcss(['fixtures/b.css', 'fixtures/c.css'], function (links) { | ||
var b = links.shift(); | ||
var c = links.shift(); | ||
assert.contains('fixtures/b.css', b.href); | ||
assert.contains('fixtures/c.css', c.href); | ||
done(); | ||
}); | ||
}); | ||
QUnit.test("should insert line before a specified element", function( assert ) { | ||
assert.expect(1); | ||
QUnit.test('should default media type to all devices', function( assert ) { | ||
assert.expect(1); | ||
var done = assert.async(1); | ||
var done = assert.async(1); | ||
var element = document.getElementById("before"); | ||
loadcss(['fixtures/d.css'], function (links) { | ||
var d = links.shift(); | ||
loadcss(["fixtures/e.css"], { | ||
before: element, | ||
done: function (links) { | ||
assert.equal(links[0].nextElementSibling, element); | ||
assert.equal(d.media, 'all'); | ||
done(); | ||
} | ||
}); | ||
}); | ||
QUnit.test('should set media type specified in options', function( assert ) { | ||
assert.expect(1); | ||
var done = assert.async(1); | ||
loadcss(['fixtures/e.css'], { | ||
media: 'print', | ||
before: document.getElementById('loader'), | ||
complete: function (links) { | ||
var e = links.shift(); | ||
assert.ok(e.media === 'print'); | ||
done(); | ||
} | ||
}); | ||
}); | ||
QUnit.test('should insert link before specified node', function(assert) { | ||
assert.expect(1); | ||
var done = assert.async(1); | ||
var element = document.getElementById('loader'); | ||
loadcss(['fixtures/f.css'], { | ||
before: element, | ||
complete: function (links) { | ||
var f = links.shift(); | ||
assert.equal(f.nextElementSibling, element); | ||
done(); | ||
} | ||
}); | ||
}); | ||
QUnit.test('should fire callback after stylesheet is loaded', function(assert) { | ||
assert.expect(1); | ||
var done = assert.async(1); | ||
var fixtures = window.document.getElementById("qunit-fixture"); | ||
var header = window.document.createElement('div'); | ||
header.innerHTML = 'Hello, World!'; | ||
header.id = 'header'; | ||
fixtures.appendChild(header); | ||
loadcss(['fixtures/g.css'], { | ||
complete: function (links) { | ||
var g = links.shift(); | ||
assert.equal(getStyles(header).color, 'rgb(238, 130, 238)'); | ||
done(); | ||
} | ||
}); | ||
}); | ||
}); | ||
}); | ||
}(window)); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
16
0
1
41
0
8858
192
1