diff --git a/.jshintrc b/.jshintrc index e2896df..f78d858 100644 --- a/.jshintrc +++ b/.jshintrc @@ -23,5 +23,8 @@ "sub" : true, "strict" : true, "white" : false, - "indent" : 2 -} \ No newline at end of file + "indent" : 2, + "globals" : { + "define" : false + } +} diff --git a/Gruntfile.js b/Gruntfile.js index 125e052..0b9dc63 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -70,12 +70,27 @@ module.exports = function(grunt) { } }, jasmine: { + browserAMD: { + src: ['annyang.js'], + options: { + specs: 'test/spec/*Spec.js', + outfile: 'test/SpecRunner.html', + vendor: ['test/vendor/corti.js', 'test/init_corti.js'], + keepRunner: true, + template: require('grunt-template-jasmine-requirejs'), + templateOptions: { + requireConfig: { + baseUrl: '../' + } + } + } + }, testAndCoverage: { src: ['annyang.js'], options: { specs: ['test/spec/*Spec.js'], outfile: 'test/SpecRunner.html', - polyfills: ['test/vendor/corti.js', 'test/init_corti.js'], + vendor: ['test/vendor/corti.js', 'test/init_corti.js'], keepRunner: true, template: require('grunt-template-jasmine-istanbul'), templateOptions: { @@ -94,7 +109,7 @@ module.exports = function(grunt) { thresholds: { statements: 80, branches: 65, - functions: 95, + functions: 90, lines: 80 } } diff --git a/annyang.js b/annyang.js index 5c9ddab..bb7d631 100644 --- a/annyang.js +++ b/annyang.js @@ -3,8 +3,18 @@ //! author : Tal Ater @TalAter //! license : MIT //! https://www.TalAter.com/annyang/ - -(function(undefined) { +(function (root, factory) { + "use strict"; + if (typeof define === 'function' && define.amd) { // AMD + global + define([], function () { + return (root.annyang = factory(root)); + }); + } else if (typeof module === 'object' && module.exports) { // CommonJS + module.exports = factory(root); + } else { // Browser globals + root.annyang = factory(root); + } +}(typeof window !== 'undefined' ? window : this, function (root, undefined) { "use strict"; /** @@ -17,8 +27,7 @@ * # API Reference */ - // Save a reference to the global object (window in the browser) - var root = this; + var annyang; // Get the SpeechRecognition object, while handling browser prefixes var SpeechRecognition = root.SpeechRecognition || @@ -30,8 +39,7 @@ // Check browser support // This is done as early as possible, to make it as fast as possible for unsupported browsers if (!SpeechRecognition) { - root.annyang = null; - return undefined; + return null; } var commandsList = []; @@ -75,18 +83,18 @@ var initIfNeeded = function() { if (!isInitialized()) { - root.annyang.init({}, false); + annyang.init({}, false); } }; var registerCommand = function(command, cb, phrase) { commandsList.push({ command: command, callback: cb, originalPhrase: phrase }); if (debugState) { - root.console.log('Command successfully loaded: %c'+phrase, debugStyle); + console.log('Command successfully loaded: %c'+phrase, debugStyle); } }; - root.annyang = { + annyang = { /** * Initialize annyang with a list of commands to recognize. @@ -169,9 +177,9 @@ // play nicely with the browser, and never restart annyang automatically more than once per second var timeSinceLastStart = new Date().getTime()-lastStartedAt; if (timeSinceLastStart < 1000) { - setTimeout(root.annyang.start, 1000-timeSinceLastStart); + setTimeout(annyang.start, 1000-timeSinceLastStart); } else { - root.annyang.start(); + annyang.start(); } } }; @@ -179,7 +187,7 @@ recognition.onresult = function(event) { if(pauseListening) { if (debugState) { - root.console.log('Speech heard, but annyang is paused'); + console.log('Speech heard, but annyang is paused'); } return false; } @@ -198,7 +206,7 @@ // the text recognized commandText = results[i].trim(); if (debugState) { - root.console.log('Speech recognized: %c'+commandText, debugStyle); + console.log('Speech recognized: %c'+commandText, debugStyle); } // try and match recognized text to one of the commands on the list @@ -208,9 +216,9 @@ if (result) { var parameters = result.slice(1); if (debugState) { - root.console.log('command matched: %c'+currentCommand.originalPhrase, debugStyle); + console.log('command matched: %c'+currentCommand.originalPhrase, debugStyle); if (parameters.length) { - root.console.log('with parameters', parameters); + console.log('with parameters', parameters); } } // execute the matched command @@ -270,7 +278,7 @@ recognition.start(); } catch(e) { if (debugState) { - root.console.log(e.message); + console.log(e.message); } } }, @@ -309,7 +317,7 @@ * @method resume */ resume: function() { - root.annyang.start(); + annyang.start(); }, /** @@ -371,7 +379,7 @@ registerCommand(new RegExp(cb.regexp.source, 'i'), cb.callback, phrase); } else { if (debugState) { - root.console.log('Can not register command: %c'+phrase, debugStyle); + console.log('Can not register command: %c'+phrase, debugStyle); } continue; } @@ -544,7 +552,9 @@ } }; -}).call(this); + return annyang; + +})); /** * # Good to Know diff --git a/annyang.min.js b/annyang.min.js index 776a369..aa1110e 100644 --- a/annyang.min.js +++ b/annyang.min.js @@ -3,4 +3,4 @@ //! author : Tal Ater @TalAter //! license : MIT //! https://www.TalAter.com/annyang/ -(function(a){"use strict";var b=this,c=b.SpeechRecognition||b.webkitSpeechRecognition||b.mozSpeechRecognition||b.msSpeechRecognition||b.oSpeechRecognition;if(!c)return b.annyang=null,a;var d,e,f=[],g={start:[],error:[],end:[],result:[],resultMatch:[],resultNoMatch:[],errorNetwork:[],errorPermissionBlocked:[],errorPermissionDenied:[]},h=0,i=!1,j="font-weight: bold; color: #00f;",k=!1,l=!1,m=/\s*\((.*?)\)\s*/g,n=/(\(\?:[^)]+\))\?/g,o=/(\(\?)?:\w+/g,p=/\*\w+/g,q=/[\-{}\[\]+?.,\\\^$|#]/g,r=function(a){return a=a.replace(q,"\\$&").replace(m,"(?:$1)?").replace(o,function(a,b){return b?a:"([^\\s]+)"}).replace(p,"(.*?)").replace(n,"\\s*$1?\\s*"),new RegExp("^"+a+"$","i")},s=function(a){var b=Array.prototype.slice.call(arguments,1);a.forEach(function(a){a.callback.apply(a.context,b)})},t=function(){return d!==a},u=function(){t()||b.annyang.init({},!1)},v=function(a,c,d){f.push({command:a,callback:c,originalPhrase:d}),i&&b.console.log("Command successfully loaded: %c"+d,j)};b.annyang={init:function(m,n){n=n===a?!0:!!n,d&&d.abort&&d.abort(),d=new c,d.maxAlternatives=5,d.continuous="http:"===b.location.protocol,d.lang="en-US",d.onstart=function(){l=!0,s(g.start)},d.onerror=function(a){switch(s(g.error),a.error){case"network":s(g.errorNetwork);break;case"not-allowed":case"service-not-allowed":e=!1,s((new Date).getTime()-h<200?g.errorPermissionBlocked:g.errorPermissionDenied)}},d.onend=function(){if(l=!1,s(g.end),e){var a=(new Date).getTime()-h;1e3>a?setTimeout(b.annyang.start,1e3-a):b.annyang.start()}},d.onresult=function(a){if(k)return i&&b.console.log("Speech heard, but annyang is paused"),!1;for(var c=a.results[a.resultIndex],d=[],e=0;em;m++){var o=f[m],p=o.command.exec(h);if(p){var q=p.slice(1);return i&&(b.console.log("command matched: %c"+o.originalPhrase,j),q.length&&b.console.log("with parameters",q)),o.callback.apply(this,q),s(g.resultMatch,h,o.originalPhrase,d),!0}}}return s(g.resultNoMatch,d),!1},n&&(f=[]),m.length&&this.addCommands(m)},start:function(c){k=!1,u(),c=c||{},e=c.autoRestart!==a?!!c.autoRestart:!0,c.continuous!==a&&(d.continuous=!!c.continuous),h=(new Date).getTime();try{d.start()}catch(f){i&&b.console.log(f.message)}},abort:function(){e=!1,t()&&d.abort()},pause:function(){k=!0},resume:function(){b.annyang.start()},debug:function(a){i=arguments.length>0?!!a:!0},setLanguage:function(a){u(),d.lang=a},addCommands:function(a){var c;u();for(var d in a)if(a.hasOwnProperty(d))if(c=b[a[d]]||a[d],"function"==typeof c)v(r(d),c,d);else{if(!("object"==typeof c&&c.regexp instanceof RegExp)){i&&b.console.log("Can not register command: %c"+d,j);continue}v(new RegExp(c.regexp.source,"i"),c.callback,d)}},removeCommands:function(b){return b===a?void(f=[]):(b=Array.isArray(b)?b:[b],void(f=f.filter(function(a){for(var c=0;ca?setTimeout(c.start,1e3-a):c.start()}},e.onresult=function(a){if(l)return j&&console.log("Speech heard, but annyang is paused"),!1;for(var b=a.results[a.resultIndex],c=[],d=0;di;i++){var n=g[i],o=n.command.exec(e);if(o){var p=o.slice(1);return j&&(console.log("command matched: %c"+n.originalPhrase,k),p.length&&console.log("with parameters",p)),n.callback.apply(this,p),t(h.resultMatch,e,n.originalPhrase,c),!0}}}return t(h.resultNoMatch,c),!1},o&&(g=[]),n.length&&this.addCommands(n)},start:function(a){l=!1,v(),a=a||{},f=a.autoRestart!==b?!!a.autoRestart:!0,a.continuous!==b&&(e.continuous=!!a.continuous),i=(new Date).getTime();try{e.start()}catch(c){j&&console.log(c.message)}},abort:function(){f=!1,u()&&e.abort()},pause:function(){l=!0},resume:function(){c.start()},debug:function(a){j=arguments.length>0?!!a:!0},setLanguage:function(a){v(),e.lang=a},addCommands:function(b){var c;v();for(var d in b)if(b.hasOwnProperty(d))if(c=a[b[d]]||b[d],"function"==typeof c)w(s(d),c,d);else{if(!("object"==typeof c&&c.regexp instanceof RegExp)){j&&console.log("Can not register command: %c"+d,k);continue}w(new RegExp(c.regexp.source,"i"),c.callback,d)}},removeCommands:function(a){return a===b?void(g=[]):(a=Array.isArray(a)?a:[a],void(g=g.filter(function(b){for(var c=0;ca?setTimeout(b.annyang.start,1e3-a):b.annyang.start()}},d.onresult=function(a){if(k)return i&&b.console.log("Speech heard, but annyang is paused"),!1;for(var c=a.results[a.resultIndex],d=[],e=0;em;m++){var o=f[m],p=o.command.exec(h);if(p){var q=p.slice(1);return i&&(b.console.log("command matched: %c"+o.originalPhrase,j),q.length&&b.console.log("with parameters",q)),o.callback.apply(this,q),s(g.resultMatch,h,o.originalPhrase,d),!0}}}return s(g.resultNoMatch,d),!1},n&&(f=[]),m.length&&this.addCommands(m)},start:function(c){k=!1,u(),c=c||{},e=c.autoRestart!==a?!!c.autoRestart:!0,c.continuous!==a&&(d.continuous=!!c.continuous),h=(new Date).getTime();try{d.start()}catch(f){i&&b.console.log(f.message)}},abort:function(){e=!1,t()&&d.abort()},pause:function(){k=!0},resume:function(){b.annyang.start()},debug:function(a){i=arguments.length>0?!!a:!0},setLanguage:function(a){u(),d.lang=a},addCommands:function(a){var c;u();for(var d in a)if(a.hasOwnProperty(d))if(c=b[a[d]]||a[d],"function"==typeof c)v(r(d),c,d);else{if(!("object"==typeof c&&c.regexp instanceof RegExp)){i&&b.console.log("Can not register command: %c"+d,j);continue}v(new RegExp(c.regexp.source,"i"),c.callback,d)}},removeCommands:function(b){return b===a?void(f=[]):(b=Array.isArray(b)?b:[b],void(f=f.filter(function(a){for(var c=0;ca?setTimeout(c.start,1e3-a):c.start()}},e.onresult=function(a){if(l)return j&&console.log("Speech heard, but annyang is paused"),!1;for(var b=a.results[a.resultIndex],c=[],d=0;di;i++){var n=g[i],o=n.command.exec(e);if(o){var p=o.slice(1);return j&&(console.log("command matched: %c"+n.originalPhrase,k),p.length&&console.log("with parameters",p)),n.callback.apply(this,p),t(h.resultMatch,e,n.originalPhrase,c),!0}}}return t(h.resultNoMatch,c),!1},o&&(g=[]),n.length&&this.addCommands(n)},start:function(a){l=!1,v(),a=a||{},f=a.autoRestart!==b?!!a.autoRestart:!0,a.continuous!==b&&(e.continuous=!!a.continuous),i=(new Date).getTime();try{e.start()}catch(c){j&&console.log(c.message)}},abort:function(){f=!1,u()&&e.abort()},pause:function(){l=!0},resume:function(){c.start()},debug:function(a){j=arguments.length>0?!!a:!0},setLanguage:function(a){v(),e.lang=a},addCommands:function(b){var c;v();for(var d in b)if(b.hasOwnProperty(d))if(c=a[b[d]]||b[d],"function"==typeof c)w(s(d),c,d);else{if(!("object"==typeof c&&c.regexp instanceof RegExp)){j&&console.log("Can not register command: %c"+d,k);continue}w(new RegExp(c.regexp.source,"i"),c.callback,d)}},removeCommands:function(a){return a===b?void(g=[]):(a=Array.isArray(a)?a:[a],void(g=g.filter(function(b){for(var c=0;ca?setTimeout(b.annyang.start,1e3-a):b.annyang.start()}},d.onresult=function(a){if(k)return i&&b.console.log("Speech heard, but annyang is paused"),!1;for(var c=a.results[a.resultIndex],d=[],e=0;em;m++){var o=f[m],p=o.command.exec(h);if(p){var q=p.slice(1);return i&&(b.console.log("command matched: %c"+o.originalPhrase,j),q.length&&b.console.log("with parameters",q)),o.callback.apply(this,q),s(g.resultMatch,h,o.originalPhrase,d),!0}}}return s(g.resultNoMatch,d),!1},n&&(f=[]),m.length&&this.addCommands(m)},start:function(c){k=!1,u(),c=c||{},e=c.autoRestart!==a?!!c.autoRestart:!0,c.continuous!==a&&(d.continuous=!!c.continuous),h=(new Date).getTime();try{d.start()}catch(f){i&&b.console.log(f.message)}},abort:function(){e=!1,t()&&d.abort()},pause:function(){k=!0},resume:function(){b.annyang.start()},debug:function(a){i=arguments.length>0?!!a:!0},setLanguage:function(a){u(),d.lang=a},addCommands:function(a){var c;u();for(var d in a)if(a.hasOwnProperty(d))if(c=b[a[d]]||a[d],"function"==typeof c)v(r(d),c,d);else{if(!("object"==typeof c&&c.regexp instanceof RegExp)){i&&b.console.log("Can not register command: %c"+d,j);continue}v(new RegExp(c.regexp.source,"i"),c.callback,d)}},removeCommands:function(b){return b===a?void(f=[]):(b=Array.isArray(b)?b:[b],void(f=f.filter(function(a){for(var c=0;ca?setTimeout(c.start,1e3-a):c.start()}},e.onresult=function(a){if(l)return j&&console.log("Speech heard, but annyang is paused"),!1;for(var b=a.results[a.resultIndex],c=[],d=0;di;i++){var n=g[i],o=n.command.exec(e);if(o){var p=o.slice(1);return j&&(console.log("command matched: %c"+n.originalPhrase,k),p.length&&console.log("with parameters",p)),n.callback.apply(this,p),t(h.resultMatch,e,n.originalPhrase,c),!0}}}return t(h.resultNoMatch,c),!1},o&&(g=[]),n.length&&this.addCommands(n)},start:function(a){l=!1,v(),a=a||{},f=a.autoRestart!==b?!!a.autoRestart:!0,a.continuous!==b&&(e.continuous=!!a.continuous),i=(new Date).getTime();try{e.start()}catch(c){j&&console.log(c.message)}},abort:function(){f=!1,u()&&e.abort()},pause:function(){l=!0},resume:function(){c.start()},debug:function(a){j=arguments.length>0?!!a:!0},setLanguage:function(a){v(),e.lang=a},addCommands:function(b){var c;v();for(var d in b)if(b.hasOwnProperty(d))if(c=a[b[d]]||b[d],"function"==typeof c)w(s(d),c,d);else{if(!("object"==typeof c&&c.regexp instanceof RegExp)){j&&console.log("Can not register command: %c"+d,k);continue}w(new RegExp(c.regexp.source,"i"),c.callback,d)}},removeCommands:function(a){return a===b?void(g=[]):(a=Array.isArray(a)?a:[a],void(g=g.filter(function(b){for(var c=0;c - - - - @@ -26,6 +22,10 @@ + + + + diff --git a/test/spec/.jshintrc b/test/spec/.jshintrc index a7d2470..80d322c 100644 --- a/test/spec/.jshintrc +++ b/test/spec/.jshintrc @@ -34,6 +34,7 @@ "spyOn": false, "it": false, "xit": false, - "annyang": false + "annyang": false, + "define": false } -} \ No newline at end of file +} diff --git a/test/spec/BasicSpec.js b/test/spec/BasicSpec.js index 193910e..08c7761 100644 --- a/test/spec/BasicSpec.js +++ b/test/spec/BasicSpec.js @@ -1,4 +1,13 @@ -(function() { +(function (root, factory) { + // jshint strict: false + if (typeof module === 'object' && module.exports) { // CommonJS + factory(require('../../annyang')); + } else if (typeof define === 'function' && define.amd) { // AMD + define(['annyang'], factory); + } else { // Browser globals + factory(root.annyang); + } +}(typeof window !== 'undefined' ? window : this, function factory(annyang) { "use strict"; describe('annyang', function() { @@ -1172,4 +1181,4 @@ }); -})(); +})); diff --git a/test/vendor/corti.js b/test/vendor/corti.js index 81560f4..fcdb07c 100644 --- a/test/vendor/corti.js +++ b/test/vendor/corti.js @@ -181,4 +181,4 @@ } }; -}).call(this); +}).call(this); \ No newline at end of file