diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..84b6b2d --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,17 @@ +module.exports = function(grunt) { + grunt.initConfig({ + uglify: { + options: { + mangle: true + }, + target: { + files: { + 'egg.min.js': ['egg.js'] + } + } + } + }); + + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.registerTask('build', ['uglify']); +} \ No newline at end of file diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..ddf45b1 --- /dev/null +++ b/bower.json @@ -0,0 +1,22 @@ +{ + "name": "egg.js", + "main": "egg.js", + "version": "0.0.1", + "homepage": "https://github.com/mikeflynn/egg.js", + "authors": [ + "Mike Flynn " + ], + "description": "A simple javascript library to add easter eggs to web pages.", + "keywords": [ + "easter eggs", + "konami code" + ], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ] +} diff --git a/egg.js b/egg.js index 3e502f0..f037e8a 100644 --- a/egg.js +++ b/egg.js @@ -1,15 +1,57 @@ // thatmikeflynn.com/egg.js/ -function Egg() { +function Egg(/* keySequence, fn, metadata */) { this.eggs = []; this.hooks = []; this.kps = []; this.activeEgg = ''; + // for now we'll just ignore the shift key to allow capital letters + this.ignoredKeys = [16]; + + if(arguments.length) { + this.AddCode.apply(this, arguments); + } +} + +// attempt to call passed function bound to Egg object instance +Egg.prototype.__execute = function(fn) { + return typeof fn === 'function' && fn.call(this); +} + +// converts literal character values to keyCodes +Egg.prototype.__toCharCodes = function(keys) { + var special = { + "up": 38, "down": 40, "left": 37, "right": 39, "enter": 13, "space": 32, "ctrl": 7, "alt": 8, "tab": 9 + }, + specialKeys = Object.keys(special); + + if(typeof keys === 'string') { + // make sure there isn't any whitespace + keys = keys.split(',').map(function(key){ + return key.trim(); + }); + } + + var characterKeyCodes = keys.map(function(key) { + // check if it's already a keycode + if(Number.isInteger(parseInt(key, 10))) { + return key; + } + + // lookup in named key map + if(specialKeys.indexOf(key) > -1) { + return special[key]; + } + // it's a letter, return the char code for it + return (key).charCodeAt(0); + }); + + return characterKeyCodes.join(','); } // Keycode lookup: http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes Egg.prototype.AddCode = function(keys, fn, metadata) { - this.eggs.push({keys: keys, fn: fn, metadata: metadata}); + this.eggs.push({keys: this.__toCharCodes(keys), fn: fn, metadata: metadata}); return this; } @@ -22,36 +64,49 @@ Egg.prototype.AddHook = function(fn) { Egg.prototype.Listen = function() { if(window.addEventListener) { - window.addEventListener("keydown", function(e) { - this.kps.push(e.keyCode); + window.addEventListener("keydown", function keydownHandler(e) { + var keyCode = e.keyCode; + // keydown defaults all letters to uppercase + if(keyCode >= 65 && keyCode <= 90) { + if(!e.shiftKey) { + // convert to lower case letter + keyCode = keyCode + 32; + } + } - this.eggs.forEach(function(v, i, a) { - if(this.kps.toString().indexOf(this.eggs[i].keys) >= 0) { - // Call the fired egg function - this.activeEgg = this.eggs[i]; - this.eggs[i].fn(); + // make sure that it's not an ignored key (shift for one) + if(this.ignoredKeys.indexOf(keyCode) === -1) { + this.kps.push(keyCode); + } - // Call the hooks - this.hooks.forEach(function(hook, i, a) { - hook.call(this); - }.bind(this)); + this.eggs.forEach(function(currentEgg, i) { + var foundEgg = this.kps.toString().indexOf(currentEgg.keys) >= 0; - // Reset + if(foundEgg) { + // Reset keys; if more keypresses occur while the callback is executing, it could retrigger the match this.kps = []; + // Set the activeEgg to this one + this.activeEgg = currentEgg; + // if callback is a function, call it + this.__execute(currentEgg.fn, this); + // Call the hooks + this.hooks.forEach(this.__execute, this); + this.activeEgg = ''; } - }.bind(this)); + }, this); + }.bind(this)); } } -// Example: -// var egg = new Egg(); -// egg.AddCode("38,38,40,40,37,39,37,39,66,65", function() { -// alert("Konami!"); -// }, "konami-code"); -// egg.AddHook(function(){ -// console.log("Hook called for: " + this.activeEgg.keys); -// console.log(this.activeEgg.metadata); -// }); -// egg.Listen(); \ No newline at end of file +// EGGSAMPLE + var egg = new Egg(); + egg + .AddCode("up,up,down,down,left,right,left,right,b,a", function() { + alert("Konami!"); + }, "konami-code") + .AddHook(function(){ + console.log("Hook called for: " + this.activeEgg.keys); + console.log(this.activeEgg.metadata); + }).Listen(); \ No newline at end of file diff --git a/egg.min.js b/egg.min.js new file mode 100644 index 0000000..9083b24 --- /dev/null +++ b/egg.min.js @@ -0,0 +1 @@ +function Egg(){this.eggs=[],this.hooks=[],this.kps=[],this.activeEgg="",this.ignoredKeys=[16],arguments.length&&this.AddCode.apply(this,arguments)}Egg.prototype.__execute=function(a){return"function"==typeof a&&a.call(this)},Egg.prototype.__toCharCodes=function(a){var b={up:38,down:40,left:37,right:39,enter:13,space:32,ctrl:7,alt:8,tab:9},c=Object.keys(b);"string"==typeof a&&(a=a.split(",").map(function(a){return a.trim()}));var d=a.map(function(a){return Number.isInteger(parseInt(a,10))?a:c.indexOf(a)>-1?b[a]:a.charCodeAt(0)});return d.join(",")},Egg.prototype.AddCode=function(a,b,c){return this.eggs.push({keys:this.__toCharCodes(a),fn:b,metadata:c}),this},Egg.prototype.AddHook=function(a){return this.hooks.push(a),this},Egg.prototype.Listen=function(){window.addEventListener&&window.addEventListener("keydown",function(a){var b=a.keyCode;b>=65&&90>=b&&(a.shiftKey||(b+=32)),-1===this.ignoredKeys.indexOf(b)&&this.kps.push(b),this.eggs.forEach(function(a,b){var c=this.kps.toString().indexOf(a.keys)>=0;c&&(this.kps=[],this.activeEgg=a,this.__execute(a.fn,this),this.hooks.forEach(this.__execute,this),this.activeEgg="")},this)}.bind(this))};var egg=new Egg;egg.AddCode("up,up,down,down,left,right,left,right,b,a",function(){alert("Konami!")},"konami-code").AddHook(function(){console.log("Hook called for: "+this.activeEgg.keys),console.log(this.activeEgg.metadata)}).Listen(); \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..2fc5f5a --- /dev/null +++ b/package.json @@ -0,0 +1,27 @@ +{ + "name": "egg.js", + "version": "0.0.1", + "description": "A simple javascript library to add easter eggs to web pages.", + "main": "Gruntfile.js", + "devDependencies": { + "grunt": "^0.4.5", + "grunt-contrib-uglify": "^0.9.1" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://github.com/mikeflynn/egg.js.git" + }, + "keywords": [ + "easter eggs", + "konami code" + ], + "author": "Mike Flynn", + "license": "ISC", + "bugs": { + "url": "https://github.com/mikeflynn/egg.js/issues" + }, + "homepage": "https://github.com/mikeflynn/egg.js" +}