I wrote a basic JavaScript plugin that allows you to specify what specific JavaScript files and CSS files to be loaded in, and in addition specify attributes for each file.
To specify where to load in scripts, you just have to add a data-script-loader
attribute to an element, and all scripts will be inserted after that element. To specify where to load in link elements, you just have to add a data-css-loader
attribute to an element, and all link elements will be inserted after that element.
The following function is used to load scripts/css files:
ScriptLoader.load({
scripts:{
files:['bower_components/jquery/dist/jquery.min.js', 'dist/test-2.js'],
options: {
'jquery': {
async:true
},
'test-2': {
defer:true
}
}
},
css: {
files:['dist/style.css'],
options: {
'style': {
hreflang:'en'
}
}
},
callbacks: {
'jquery':jqueryCallback,
'style':function(){
console.log("stylesheet loaded");
}
}
});
This all works fine, and all elements are loaded in with their specified attributes.
This is the code for the plugin:
window.ScriptLoader = (function(window, document, undefined){
var loadedScripts = [];
var loadedStyleSheets = [];
//script loader
var ScriptLoader = {
load: function (){
var options = {
scripts:{
files:[],
options:{}
},
css:{
files:[],
options: {}
},
callbacks:{}
}
if(arguments[0] && typeof arguments[0] === "object") {
if(!arguments[0].scripts && !arguments[0].css){
throw new Error("Error: Failed to supply required arguments (CSS or JS array is required)");
} else {
options = setOptions(options, arguments[0]);
if(arguments[0].scripts)
loadScripts(options);
if(arguments[0].css)
loadCss(options);
}
} else {
throw new Error("Error: No arguments given.");
}
},
showJS: function(){
//returns array with script sources
return loadedScripts;
},
showCSS: function(){
//returns array with css sources
return loadedStyleSheets;
}
}
//load scripts
function loadScripts(options){
var loc = document.querySelector('[data-script-loader]');
var scriptOptions = options.scripts.options;
var asyncOpt = scriptOptions.defer, deferOpt = scriptOptions.defer;
for(var i = 0; i < options.scripts.files.length; i++){
var prettyName = prettySource(options.scripts.files[i]);
var script = document.createElement('script'),
scriptSrc = options.scripts.files[i];
script.src = scriptSrc;
//default
script.type = "text/javascript";
//custom options
for(var opt in scriptOptions[prettyName])
script[opt] = scriptOptions[prettyName][opt];
//callback
if(options.callbacks[prettyName])
script.onload = options.callbacks[prettyName];
loc.parentNode.insertBefore(script, loc.nextSibling);
//push to list of loaded scripts
loadedScripts.push(scriptSrc);
}
}
//load css
function loadCss(options){
var loc = document.querySelector('[data-css-loader]');;
var cssOptions = options.css.options;
for(var i = 0; i < options.css.files.length; i++){
var prettyName = prettySource(options.css.files[i]);
var link = document.createElement('link'),
linkHref = options.css.files[i];
link.href = linkHref;
//defaults
link.type = "text/css";
link.rel = "stylesheet";
//custom options
for(var opt in cssOptions[prettyName])
link[opt] = cssOptions[prettyName][opt];
//callback
if(options.callbacks[prettyName])
link.onload = options.callbacks[prettyName];
//insert after
loc.parentNode.insertBefore(link, loc.nextSibling);
//push to list of loaded style sheets
loadedStyleSheets.push(linkHref);
}
}
//make sources pretty
function prettySource(src){
var s = src.split('/'), len = s.length - 1;
var pretty = s[len].split('.')[0];
return pretty;
}
//utility function to set options
function setOptions(src, props){
var prop;
//js files
if(props.scripts){
//scripts
for(var js in props.scripts.files){
src.scripts.files[js] = props.scripts.files[js];
}
//javascript options
for(var jsopt in props.scripts.options){
src.scripts.options[jsopt] = props.scripts.options[jsopt];
}
}
//css files
if(props.css){
for(var css in props.css.files){
src.css.files[css] = props.css.files[css];
}
//css options
for(var cssopt in props.css.options){
src.css.options[cssopt] = props.css.options[cssopt];
}
}
if(props.callbacks){
//callback options
for(cb in props.callbacks){
src.callbacks[cb] = props.callbacks[cb];
}
}
return src;
}
return ScriptLoader;
})(window, document);
How can I improve this ? Are there any browser compatibility issues I need to consider ? Can my code be improved ?