Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*~
._*
.DS_Store
node_modules
40 changes: 40 additions & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module.exports = function(grunt) {

// Import task configurations
var jshint = require('./grunt/jshint'),
uglify = require('./grunt/uglify'),
watch = require('./grunt/watch');

// Main project configuration.
grunt.initConfig({
// Read NPM package information
pkg: grunt.file.readJSON('package.json'),
// Static code analysis of Javascript
jshint: jshint,
// Concatenate, minify and beautify/uglify Javascript
uglify: uglify.config,
// Watcher
watch: watch
});

// Load the grunt tasks
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');

// Compile production files
grunt.registerTask('dist', [
'jshint',
'uglify:dist'
]);

// Compile developer friendly environment
grunt.registerTask('dev', [
'jshint',
'uglify:dev'
]);

// Default task(s).
grunt.registerTask('default', 'dist');

};
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,22 @@ Progressive.js is a work-in-progress. If you come across any issues not mentione

- Multiple enhancements cannot be applied to individual elements
- You can only use a class name to select elements
- The fallback in browsers that don't support CSS animations uses the `onload` event. It would be nicer to use `DOMContentLoaded` where available.
- The fallback in browsers that don't support CSS animations uses the `onload` event. It would be nicer to use `DOMContentLoaded` where available.

##Contribute

If you would like to contribute, I would advise you to setup `grunt` locally. That way the javascript is both automatically checked for syntax errors and minified before your changes are pushed to the remote branch.

You will need to have `grunt` installed globally. Run:

npm install -g grunt-cli

Once you have installed `grunt` globally, run:

npm install

...while at the root of this repository. The dependencies/plugins will be retrieved and you'll have `grunt` running the linting and minification tasks on the background as you develop, by running:

grunt watch

Run this command on a dedicated shell so that it keeps running uninterrupted. Enjoy!
14 changes: 14 additions & 0 deletions grunt/jshint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
var gruntfiles = ['Gruntfile.js', 'config/*.js'];
var jsfiles = [
'Gruntfile.js',
'config/*.js',
'progressive.js'
];

module.exports = {
options: {
evil: true
},
grunt: gruntfiles,
all: jsfiles
};
23 changes: 23 additions & 0 deletions grunt/uglify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
var files = {
'progressive.min.js': [
'progressive.js'
]
};

// Grunt configuration settings
module.exports.config = {
options: {
mangle: false,
report: 'min' // 'false', 'min' or 'gzip' Default: false
},
dist: {
files: files
},
dev: {
options: {
compress: false,
beautify: true
},
files: files
}
};
15 changes: 15 additions & 0 deletions grunt/watch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// This task watches files and runs the appropriate
// tasks when files are changed.
module.exports = {

grunt: {
files: ['Gruntfile.js', 'config/*.js'],
tasks: ['jshint:grunt']
},

js: {
files: ['config/*.js', 'progressive.js'],
tasks: ['jshint', 'uglify:dist']
}

};
15 changes: 15 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "go",
"version": "0.0.0",
"private": true,
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-jshint": "~0.6.0",
"grunt-contrib-uglify": "~0.1.1",
"grunt-contrib-watch": "~0.4.4"
},
"engines": {
"node": ">=0.8.0"
}
}
220 changes: 110 additions & 110 deletions progressive.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,125 +6,125 @@ Progressive.js v0.1 - Brought to you by James Allardice (@james_allardice) and K

var Progressive = (function () {

"use strict";
"use strict";

var styleElem = document.createElement("style"),
animationSupport = false,
animationString,
keyframePrefix = "",
domPrefixes = ["Webkit", "Moz", "O", "ms", "Khtml"],
numPrefixes = domPrefixes.length,
prefix,
enhance,
i;
var styleElem = document.createElement("style"),
animationSupport = false,
animationString,
keyframePrefix = "",
domPrefixes = ["Webkit", "Moz", "O", "ms", "Khtml"],
numPrefixes = domPrefixes.length,
prefix,
enhance,
i;

// Polyfill `getElementsByClassName`, which is used by the fallback method
document.getElementsByClassName = document.getElementsByClassName || function (className) {
var classElements = [],
els,
elsLen,
pattern = new RegExp("(^|\\s)" + className + "(\\s|$)"),
i,
j;
els = document.getElementsByTagName("*");
elsLen = els.length;
for (i = 0, j = 0; i < elsLen; i++) {
if (pattern.test(els[i].className)) {
classElements[j] = els[i];
j++;
}
}
return classElements;
};
// Polyfill `getElementsByClassName`, which is used by the fallback method
document.getElementsByClassName = document.getElementsByClassName || function (className) {
var classElements = [],
els,
elsLen,
pattern = new RegExp("(^|\\s)" + className + "(\\s|$)"),
i,
j;
els = document.getElementsByTagName("*");
elsLen = els.length;
for (i = 0, j = 0; i < elsLen; i++) {
if (pattern.test(els[i].className)) {
classElements[j] = els[i];
j++;
}
}
return classElements;
};

// Feature/vendor prefix detection for CSS animations
if (styleElem.style.animationName) {
animationSupport = true;
} else {
for (i = 0; i < numPrefixes; i++) {
if (styleElem.style[domPrefixes[i] + "AnimationName"] !== undefined) {
prefix = domPrefixes[i];
animationString = prefix + "Animation";
keyframePrefix = "-" + prefix.toLowerCase() + "-";
animationSupport = true;
break;
}
}
}
// Feature/vendor prefix detection for CSS animations
if (styleElem.style.animationName) {
animationSupport = true;
} else {
for (i = 0; i < numPrefixes; i++) {
if (styleElem.style[domPrefixes[i] + "AnimationName"] !== undefined) {
prefix = domPrefixes[i];
animationString = prefix + "Animation";
keyframePrefix = "-" + prefix.toLowerCase() + "-";
animationSupport = true;
break;
}
}
}

// The main `enhance` method to register callbacks that will be executed when certain DOM elements are inserted
enhance = function (enhancements) {
var ruleText,
styleRules = {},
enhancement,
onNodeInserted,
// The fallback function is executed on window load. It will handle any elements not handled by the animation callbacks
fallback = function () {
var enhancement,
elems,
numElems,
i;
for (enhancement in enhancements) {
if (enhancements.hasOwnProperty(enhancement)) {
elems = document.getElementsByClassName(enhancements[enhancement].className);
numElems = elems.length;
if (!enhancements[enhancement].count || enhancements[enhancement].count < numElems) {
for (i = 0; i < numElems; i++) {
enhancements[enhancement].callback.call(elems[i]);
}
}
}
}
};
ruleText = "";
// This is used as a callback to the CSS animation events. It's used to fire the supplied enhancements, in the context of each element
onNodeInserted = function (e) {
var enhancement = enhancements[e.animationName];
if (enhancement) {
enhancement.count = ++enhancement.count || 1;
enhancement.callback.call(e.target);
}
};
// The main `enhance` method to register callbacks that will be executed when certain DOM elements are inserted
enhance = function (enhancements) {
var ruleText,
styleRules = {},
enhancement,
onNodeInserted,
// The fallback function is executed on window load. It will handle any elements not handled by the animation callbacks
fallback = function () {
var enhancement,
elems,
numElems,
i;
for (enhancement in enhancements) {
if (enhancements.hasOwnProperty(enhancement)) {
elems = document.getElementsByClassName(enhancements[enhancement].className);
numElems = elems.length;
if (!enhancements[enhancement].count || enhancements[enhancement].count < numElems) {
for (i = 0; i < numElems; i++) {
enhancements[enhancement].callback.call(elems[i]);
}
}
}
}
};
ruleText = "";
// This is used as a callback to the CSS animation events. It's used to fire the supplied enhancements, in the context of each element
onNodeInserted = function (e) {
var enhancement = enhancements[e.animationName];
if (enhancement) {
enhancement.count = ++enhancement.count || 1;
enhancement.callback.call(e.target);
}
};

if (animationSupport) {
// Build up a set of CSS rules to run animations on newly inserted elements
for (enhancement in enhancements) {
if (enhancements.hasOwnProperty(enhancement)) {
ruleText += "." + enhancements[enhancement].className + "{";
ruleText += keyframePrefix + "animation:" + enhancement + " 0.001s;";
ruleText += "}";
ruleText += "@" + keyframePrefix + "keyframes " + enhancement + "{from{clip:rect(1px,auto,auto,auto);}to{clip:rect(0px,auto,auto,auto);}}";
}
}
if (animationSupport) {
// Build up a set of CSS rules to run animations on newly inserted elements
for (enhancement in enhancements) {
if (enhancements.hasOwnProperty(enhancement)) {
ruleText += "." + enhancements[enhancement].className + "{";
ruleText += keyframePrefix + "animation:" + enhancement + " 0.001s;";
ruleText += "}";
ruleText += "@" + keyframePrefix + "keyframes " + enhancement + "{from{clip:rect(1px,auto,auto,auto);}to{clip:rect(0px,auto,auto,auto);}}";
}
}

styleRules = document.createTextNode(ruleText);
styleElem.type = "text/css";
if (styleElem.styleSheet) {
styleElem.styleSheet.cssText = styleRules.nodeValue;
} else {
styleElem.appendChild(styleRules);
}
styleRules = document.createTextNode(ruleText);
styleElem.type = "text/css";
if (styleElem.styleSheet) {
styleElem.styleSheet.cssText = styleRules.nodeValue;
} else {
styleElem.appendChild(styleRules);
}

document.getElementsByTagName("script")[0].parentNode.appendChild(styleElem);
document.getElementsByTagName("script")[0].parentNode.appendChild(styleElem);

// Register cross-browser CSS animation event handlers
document.addEventListener("animationstart", onNodeInserted, false);
document.addEventListener("oanimationstart", onNodeInserted, false);
document.addEventListener("MSAnimationStart", onNodeInserted, false);
document.addEventListener("webkitAnimationStart", onNodeInserted, false);
}
// Register cross-browser CSS animation event handlers
document.addEventListener("animationstart", onNodeInserted, false);
document.addEventListener("oanimationstart", onNodeInserted, false);
document.addEventListener("MSAnimationStart", onNodeInserted, false);
document.addEventListener("webkitAnimationStart", onNodeInserted, false);
}

// Register fallback event handlers
if (window.addEventListener) {
window.addEventListener("load", fallback);
} else if (window.attachEvent) {
window.attachEvent("onload", fallback);
}
};
// Register fallback event handlers
if (window.addEventListener) {
window.addEventListener("load", fallback);
} else if (window.attachEvent) {
window.attachEvent("onload", fallback);
}
};

// Expose public methods
return {
enhance: enhance
};
// Expose public methods
return {
enhance: enhance
};

}());
4 changes: 1 addition & 3 deletions progressive.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.