1) {
169 | $scope.newTodo = parts.slice(1).join(' ');
170 | $scope.addTodo();
171 | $scope.safeApply();
172 | }
173 | }
174 | },
175 | 'show-all': {
176 | 'regex': /show.*all/gi,
177 | 'lang': 'en-US',
178 | 'call': function(utterance){
179 | $location.path('/');
180 | $scope.safeApply();
181 | }
182 | },
183 | 'show-active': {
184 | 'regex': /show.*active/gi,
185 | 'lang': 'en-US',
186 | 'call': function(utterance){
187 | $location.path('/active');
188 | $scope.safeApply();
189 | }
190 | },
191 | 'show-completed': {
192 | 'regex': /show.*complete/gi,
193 | 'lang': 'en-US',
194 | 'call': function(utterance){
195 | $location.path('/completed');
196 | $scope.safeApply();
197 | }
198 | },
199 | 'mark-all': {
200 | 'regex': /^mark/gi,
201 | 'lang': 'en-US',
202 | 'call': function(utterance){
203 | $scope.markAll(1);
204 | $scope.safeApply();
205 | }
206 | },
207 | 'unmark-all': {
208 | 'regex': /^unmark/gi,
209 | 'lang': 'en-US',
210 | 'call': function(utterance){
211 | $scope.markAll(1);
212 | $scope.safeApply();
213 | }
214 | },
215 | 'clear-completed': {
216 | 'regex': /clear.*/gi,
217 | 'lang': 'en-US',
218 | 'call': function(utterance){
219 | $scope.clearCompletedTodos();
220 | $scope.safeApply();
221 | }
222 | },
223 | 'listTasks': [{
224 | 'regex': /^complete .+/gi,
225 | 'lang': 'en-US',
226 | 'call': function(utterance){
227 | var parts = utterance.split(' ');
228 | if (parts.length > 1) {
229 | completeTodo(parts.slice(1).join(' '));
230 | }
231 | }
232 | },{
233 | 'regex': /^remove .+/gi,
234 | 'lang': 'en-US',
235 | 'call': function(utterance){
236 | var parts = utterance.split(' ');
237 | if (parts.length > 1) {
238 | var todo = findTodo(parts.slice(1).join(' '));
239 | console.log(todo);
240 | if (todo) {
241 | $scope.removeTodo(todo);
242 | $scope.safeApply();
243 | }
244 | }
245 | }
246 | }]
247 | };
248 |
249 | var ignoreUtterance = {};
250 | ignoreUtterance['addToList'] = $speechRecognition.listenUtterance($scope.recognition['en-US']['addToList']);
251 | ignoreUtterance['show-all'] = $speechRecognition.listenUtterance($scope.recognition['en-US']['show-all']);
252 | ignoreUtterance['show-active'] = $speechRecognition.listenUtterance($scope.recognition['en-US']['show-active']);
253 | ignoreUtterance['show-completed'] = $speechRecognition.listenUtterance($scope.recognition['en-US']['show-completed']);
254 | ignoreUtterance['mark-all'] = $speechRecognition.listenUtterance($scope.recognition['en-US']['mark-all']);
255 | ignoreUtterance['unmark-all'] = $speechRecognition.listenUtterance($scope.recognition['en-US']['unmark-all']);
256 | ignoreUtterance['clear-completed'] = $speechRecognition.listenUtterance($scope.recognition['en-US']['clear-completed']);
257 |
258 | /*
259 | to ignore listener call returned function
260 | */
261 | // ignoreUtterance['addToList']();
262 | });
263 |
264 | }());
265 |
--------------------------------------------------------------------------------
/demo/bower_components/angular-route/angular-route.min.js.map:
--------------------------------------------------------------------------------
1 | {
2 | "version":3,
3 | "file":"angular-route.min.js",
4 | "lineCount":13,
5 | "mappings":"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",
6 | "sources":["angular-route.js"],
7 | "names":["window","angular","undefined","ngViewFactory","$route","$anchorScroll","$animate","link","scope","$element","attr","ctrl","$transclude","cleanupLastView","currentScope","$destroy","currentElement","leave","update","locals","current","$template","newScope","$new","clone","enter","onNgViewEnter","isDefined","autoScrollExp","$eval","$emit","onloadExp","autoscroll","onload","$on","ngViewFillContentFactory","$compile","$controller","html","contents","controller","$scope","controllerAs","data","children","ngRouteModule","module","provider","$RouteProvider","inherit","parent","extra","extend","pathRegExp","path","opts","insensitive","caseInsensitiveMatch","ret","keys","replace","_","slash","key","option","optional","star","push","regexp","RegExp","routes","when","this.when","route","redirectPath","length","substr","otherwise","this.otherwise","params","$get","$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce","updateRoute","next","parseRoute","last","$$route","equals","pathParams","reloadOnSearch","forceReload","copy","$broadcast","redirectTo","isString","interpolate","search","url","then","resolve","template","templateUrl","forEach","value","get","invoke","isFunction","getTrustedResourceUrl","loadedTemplateUrl","response","all","error","match","m","exec","on","i","len","val","decodeURIComponent","name","string","result","split","segment","segmentMatch","join","reload","$evalAsync","$RouteParamsProvider","this.$get","directive","$inject"]
8 | }
9 |
--------------------------------------------------------------------------------
/demo/bower_components/todomvc-common/base.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | margin: 0;
4 | padding: 0;
5 | }
6 |
7 | button {
8 | margin: 0;
9 | padding: 0;
10 | border: 0;
11 | background: none;
12 | font-size: 100%;
13 | vertical-align: baseline;
14 | font-family: inherit;
15 | color: inherit;
16 | -webkit-appearance: none;
17 | -ms-appearance: none;
18 | -o-appearance: none;
19 | appearance: none;
20 | }
21 |
22 | body {
23 | font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
24 | line-height: 1.4em;
25 | background: #eaeaea url('bg.png');
26 | color: #4d4d4d;
27 | width: 550px;
28 | margin: 0 auto;
29 | -webkit-font-smoothing: antialiased;
30 | -moz-font-smoothing: antialiased;
31 | -ms-font-smoothing: antialiased;
32 | -o-font-smoothing: antialiased;
33 | font-smoothing: antialiased;
34 | }
35 |
36 | button,
37 | input[type="checkbox"] {
38 | outline: none;
39 | }
40 |
41 | #todoapp {
42 | background: #fff;
43 | background: rgba(255, 255, 255, 0.9);
44 | margin: 130px 0 40px 0;
45 | border: 1px solid #ccc;
46 | position: relative;
47 | border-top-left-radius: 2px;
48 | border-top-right-radius: 2px;
49 | box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.2),
50 | 0 25px 50px 0 rgba(0, 0, 0, 0.15);
51 | }
52 |
53 | #todoapp:before {
54 | content: '';
55 | border-left: 1px solid #f5d6d6;
56 | border-right: 1px solid #f5d6d6;
57 | width: 2px;
58 | position: absolute;
59 | top: 0;
60 | left: 40px;
61 | height: 100%;
62 | }
63 |
64 | #todoapp input::-webkit-input-placeholder {
65 | font-style: italic;
66 | }
67 |
68 | #todoapp input::-moz-placeholder {
69 | font-style: italic;
70 | color: #a9a9a9;
71 | }
72 |
73 | #todoapp h1 {
74 | position: absolute;
75 | top: -120px;
76 | width: 100%;
77 | font-size: 70px;
78 | font-weight: bold;
79 | text-align: center;
80 | color: #b3b3b3;
81 | color: rgba(255, 255, 255, 0.3);
82 | text-shadow: -1px -1px rgba(0, 0, 0, 0.2);
83 | -webkit-text-rendering: optimizeLegibility;
84 | -moz-text-rendering: optimizeLegibility;
85 | -ms-text-rendering: optimizeLegibility;
86 | -o-text-rendering: optimizeLegibility;
87 | text-rendering: optimizeLegibility;
88 | }
89 |
90 | #header {
91 | padding-top: 15px;
92 | border-radius: inherit;
93 | }
94 |
95 | #header:before {
96 | content: '';
97 | position: absolute;
98 | top: 0;
99 | right: 0;
100 | left: 0;
101 | height: 15px;
102 | z-index: 2;
103 | border-bottom: 1px solid #6c615c;
104 | background: #8d7d77;
105 | background: -webkit-gradient(linear, left top, left bottom, from(rgba(132, 110, 100, 0.8)),to(rgba(101, 84, 76, 0.8)));
106 | background: -webkit-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
107 | background: linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
108 | filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670');
109 | border-top-left-radius: 1px;
110 | border-top-right-radius: 1px;
111 | }
112 |
113 | #new-todo,
114 | .edit {
115 | position: relative;
116 | margin: 0;
117 | width: 100%;
118 | font-size: 24px;
119 | font-family: inherit;
120 | line-height: 1.4em;
121 | border: 0;
122 | outline: none;
123 | color: inherit;
124 | padding: 6px;
125 | border: 1px solid #999;
126 | box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
127 | -moz-box-sizing: border-box;
128 | -ms-box-sizing: border-box;
129 | -o-box-sizing: border-box;
130 | box-sizing: border-box;
131 | -webkit-font-smoothing: antialiased;
132 | -moz-font-smoothing: antialiased;
133 | -ms-font-smoothing: antialiased;
134 | -o-font-smoothing: antialiased;
135 | font-smoothing: antialiased;
136 | }
137 |
138 | #new-todo {
139 | padding: 16px 16px 16px 60px;
140 | border: none;
141 | background: rgba(0, 0, 0, 0.02);
142 | z-index: 2;
143 | box-shadow: none;
144 | }
145 |
146 | #main {
147 | position: relative;
148 | z-index: 2;
149 | border-top: 1px dotted #adadad;
150 | }
151 |
152 | label[for='toggle-all'] {
153 | display: none;
154 | }
155 |
156 | #toggle-all {
157 | position: absolute;
158 | top: -42px;
159 | left: -4px;
160 | width: 40px;
161 | text-align: center;
162 | /* Mobile Safari */
163 | border: none;
164 | }
165 |
166 | #toggle-all:before {
167 | content: '»';
168 | font-size: 28px;
169 | color: #d9d9d9;
170 | padding: 0 25px 7px;
171 | }
172 |
173 | #toggle-all:checked:before {
174 | color: #737373;
175 | }
176 |
177 | #todo-list {
178 | margin: 0;
179 | padding: 0;
180 | list-style: none;
181 | }
182 |
183 | #todo-list li {
184 | position: relative;
185 | font-size: 24px;
186 | border-bottom: 1px dotted #ccc;
187 | }
188 |
189 | #todo-list li:last-child {
190 | border-bottom: none;
191 | }
192 |
193 | #todo-list li.editing {
194 | border-bottom: none;
195 | padding: 0;
196 | }
197 |
198 | #todo-list li.editing .edit {
199 | display: block;
200 | width: 506px;
201 | padding: 13px 17px 12px 17px;
202 | margin: 0 0 0 43px;
203 | }
204 |
205 | #todo-list li.editing .view {
206 | display: none;
207 | }
208 |
209 | #todo-list li .toggle {
210 | text-align: center;
211 | width: 40px;
212 | /* auto, since non-WebKit browsers doesn't support input styling */
213 | height: auto;
214 | position: absolute;
215 | top: 0;
216 | bottom: 0;
217 | margin: auto 0;
218 | /* Mobile Safari */
219 | border: none;
220 | -webkit-appearance: none;
221 | -ms-appearance: none;
222 | -o-appearance: none;
223 | appearance: none;
224 | }
225 |
226 | #todo-list li .toggle:after {
227 | content: '✔';
228 | /* 40 + a couple of pixels visual adjustment */
229 | line-height: 43px;
230 | font-size: 20px;
231 | color: #d9d9d9;
232 | text-shadow: 0 -1px 0 #bfbfbf;
233 | }
234 |
235 | #todo-list li .toggle:checked:after {
236 | color: #85ada7;
237 | text-shadow: 0 1px 0 #669991;
238 | bottom: 1px;
239 | position: relative;
240 | }
241 |
242 | #todo-list li label {
243 | white-space: pre;
244 | word-break: break-word;
245 | padding: 15px 60px 15px 15px;
246 | margin-left: 45px;
247 | display: block;
248 | line-height: 1.2;
249 | -webkit-transition: color 0.4s;
250 | transition: color 0.4s;
251 | }
252 |
253 | #todo-list li.completed label {
254 | color: #a9a9a9;
255 | text-decoration: line-through;
256 | }
257 |
258 | #todo-list li .destroy {
259 | display: none;
260 | position: absolute;
261 | top: 0;
262 | right: 10px;
263 | bottom: 0;
264 | width: 40px;
265 | height: 40px;
266 | margin: auto 0;
267 | font-size: 22px;
268 | color: #a88a8a;
269 | -webkit-transition: all 0.2s;
270 | transition: all 0.2s;
271 | }
272 |
273 | #todo-list li .destroy:hover {
274 | text-shadow: 0 0 1px #000,
275 | 0 0 10px rgba(199, 107, 107, 0.8);
276 | -webkit-transform: scale(1.3);
277 | -ms-transform: scale(1.3);
278 | transform: scale(1.3);
279 | }
280 |
281 | #todo-list li .destroy:after {
282 | content: '✖';
283 | }
284 |
285 | #todo-list li:hover .destroy {
286 | display: block;
287 | }
288 |
289 | #todo-list li .edit {
290 | display: none;
291 | }
292 |
293 | #todo-list li.editing:last-child {
294 | margin-bottom: -1px;
295 | }
296 |
297 | #footer {
298 | color: #777;
299 | padding: 0 15px;
300 | position: absolute;
301 | right: 0;
302 | bottom: -31px;
303 | left: 0;
304 | height: 20px;
305 | z-index: 1;
306 | text-align: center;
307 | }
308 |
309 | #footer:before {
310 | content: '';
311 | position: absolute;
312 | right: 0;
313 | bottom: 31px;
314 | left: 0;
315 | height: 50px;
316 | z-index: -1;
317 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3),
318 | 0 6px 0 -3px rgba(255, 255, 255, 0.8),
319 | 0 7px 1px -3px rgba(0, 0, 0, 0.3),
320 | 0 43px 0 -6px rgba(255, 255, 255, 0.8),
321 | 0 44px 2px -6px rgba(0, 0, 0, 0.2);
322 | }
323 |
324 | #todo-count {
325 | float: left;
326 | text-align: left;
327 | }
328 |
329 | #filters {
330 | margin: 0;
331 | padding: 0;
332 | list-style: none;
333 | position: absolute;
334 | right: 0;
335 | left: 0;
336 | }
337 |
338 | #filters li {
339 | display: inline;
340 | }
341 |
342 | #filters li a {
343 | color: #83756f;
344 | margin: 2px;
345 | text-decoration: none;
346 | }
347 |
348 | #filters li a.selected {
349 | font-weight: bold;
350 | }
351 |
352 | #clear-completed {
353 | float: right;
354 | position: relative;
355 | line-height: 20px;
356 | text-decoration: none;
357 | background: rgba(0, 0, 0, 0.1);
358 | font-size: 11px;
359 | padding: 0 10px;
360 | border-radius: 3px;
361 | box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.2);
362 | }
363 |
364 | #clear-completed:hover {
365 | background: rgba(0, 0, 0, 0.15);
366 | box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.3);
367 | }
368 |
369 | #info {
370 | margin: 65px auto 0;
371 | color: #a6a6a6;
372 | font-size: 12px;
373 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7);
374 | text-align: center;
375 | }
376 |
377 | #info a {
378 | color: inherit;
379 | }
380 |
381 | /*
382 | Hack to remove background from Mobile Safari.
383 | Can't use it globally since it destroys checkboxes in Firefox and Opera
384 | */
385 |
386 | @media screen and (-webkit-min-device-pixel-ratio:0) {
387 | #toggle-all,
388 | #todo-list li .toggle {
389 | background: none;
390 | }
391 |
392 | #todo-list li .toggle {
393 | height: 40px;
394 | }
395 |
396 | #toggle-all {
397 | top: -56px;
398 | left: -15px;
399 | width: 65px;
400 | height: 41px;
401 | -webkit-transform: rotate(90deg);
402 | -ms-transform: rotate(90deg);
403 | transform: rotate(90deg);
404 | -webkit-appearance: none;
405 | appearance: none;
406 | }
407 | }
408 |
409 | .hidden {
410 | display: none;
411 | }
412 |
413 | hr {
414 | margin: 20px 0;
415 | border: 0;
416 | border-top: 1px dashed #C5C5C5;
417 | border-bottom: 1px dashed #F7F7F7;
418 | }
419 |
420 | .learn a {
421 | font-weight: normal;
422 | text-decoration: none;
423 | color: #b83f45;
424 | }
425 |
426 | .learn a:hover {
427 | text-decoration: underline;
428 | color: #787e7e;
429 | }
430 |
431 | .learn h3,
432 | .learn h4,
433 | .learn h5 {
434 | margin: 10px 0;
435 | font-weight: 500;
436 | line-height: 1.2;
437 | color: #000;
438 | }
439 |
440 | .learn h3 {
441 | font-size: 24px;
442 | }
443 |
444 | .learn h4 {
445 | font-size: 18px;
446 | }
447 |
448 | .learn h5 {
449 | margin-bottom: 0;
450 | font-size: 14px;
451 | }
452 |
453 | .learn ul {
454 | padding: 0;
455 | margin: 0 0 30px 25px;
456 | }
457 |
458 | .learn li {
459 | line-height: 20px;
460 | }
461 |
462 | .learn p {
463 | font-size: 15px;
464 | font-weight: 300;
465 | line-height: 1.3;
466 | margin-top: 0;
467 | margin-bottom: 0;
468 | }
469 |
470 | .quote {
471 | border: none;
472 | margin: 20px 0 60px 0;
473 | }
474 |
475 | .quote p {
476 | font-style: italic;
477 | }
478 |
479 | .quote p:before {
480 | content: '“';
481 | font-size: 50px;
482 | opacity: .15;
483 | position: absolute;
484 | top: -20px;
485 | left: 3px;
486 | }
487 |
488 | .quote p:after {
489 | content: '”';
490 | font-size: 50px;
491 | opacity: .15;
492 | position: absolute;
493 | bottom: -42px;
494 | right: 3px;
495 | }
496 |
497 | .quote footer {
498 | position: absolute;
499 | bottom: -40px;
500 | right: 0;
501 | }
502 |
503 | .quote footer img {
504 | border-radius: 3px;
505 | }
506 |
507 | .quote footer a {
508 | margin-left: 5px;
509 | vertical-align: middle;
510 | }
511 |
512 | .speech-bubble {
513 | position: relative;
514 | padding: 10px;
515 | background: rgba(0, 0, 0, .04);
516 | border-radius: 5px;
517 | }
518 |
519 | .speech-bubble:after {
520 | content: '';
521 | position: absolute;
522 | top: 100%;
523 | right: 30px;
524 | border: 13px solid transparent;
525 | border-top-color: rgba(0, 0, 0, .04);
526 | }
527 |
528 | .learn-bar > .learn {
529 | position: absolute;
530 | width: 272px;
531 | top: 8px;
532 | left: -300px;
533 | padding: 10px;
534 | border-radius: 5px;
535 | background-color: rgba(255, 255, 255, .6);
536 | -webkit-transition-property: left;
537 | transition-property: left;
538 | -webkit-transition-duration: 500ms;
539 | transition-duration: 500ms;
540 | }
541 |
542 | @media (min-width: 899px) {
543 | .learn-bar {
544 | width: auto;
545 | margin: 0 0 0 300px;
546 | }
547 |
548 | .learn-bar > .learn {
549 | left: 8px;
550 | }
551 |
552 | .learn-bar #todoapp {
553 | width: 550px;
554 | margin: 130px auto 40px auto;
555 | }
556 | }
557 |
--------------------------------------------------------------------------------
/test/unit.spec.js:
--------------------------------------------------------------------------------
1 | describe('adaptive.speech', function() {
2 |
3 | describe('$speechSynthetisProvider', function() {
4 | var speechSynthetis;
5 |
6 | beforeEach(module('adaptive.speech', function($speechSynthetisProvider) {
7 | speechSynthetis = $speechSynthetisProvider;
8 | }));
9 |
10 | it('should be defined', inject(function() {
11 | expect(speechSynthetis).toBeDefined();
12 | }));
13 |
14 | it('should have corsProxyServer variable', inject(function() {
15 | expect(speechSynthetis.corsProxyServer).toBeDefined();
16 | expect(typeof speechSynthetis.corsProxyServer).toBe('string');
17 | }));
18 |
19 | it('should have corsProxyServer string to match server url', inject(function() {
20 | expect(speechSynthetis.corsProxyServer).toMatch(/http(s)?:\/\/.+\//);
21 | }));
22 |
23 | it('should have $get method', inject(function() {
24 | expect(speechSynthetis.$get).toBeDefined();
25 | expect(typeof speechSynthetis.$get).toBe('function');
26 | }));
27 | });
28 |
29 |
30 | describe('$speechSynthetis service', function() {
31 |
32 | beforeEach(module('adaptive.speech', function($speechSynthetisProvider) {
33 | // config provider
34 | }));
35 |
36 | it('should be defined', inject(function($speechSynthetis) {
37 | expect($speechSynthetis).toBeDefined();
38 | }));
39 |
40 | it('should have public methods', inject(function($speechSynthetis) {
41 | expect($speechSynthetis.speak).toBeDefined();
42 | expect($speechSynthetis.justSpoke).toBeDefined();
43 | expect($speechSynthetis.recognised).toBeDefined();
44 |
45 | expect(typeof $speechSynthetis.speak).toBe('function');
46 | expect(typeof $speechSynthetis.justSpoke).toBe('function');
47 | expect(typeof $speechSynthetis.recognised).toBe('function');
48 | }));
49 |
50 | it('should not to speak at the start', inject(function($speechSynthetis) {
51 | expect($speechSynthetis.justSpoke()).toBe(false);
52 | }));
53 | });
54 |
55 |
56 | describe('$speechRecognitionProvider', function() {
57 | var speechRecognition;
58 |
59 | beforeEach(module('adaptive.speech', function($speechRecognitionProvider) {
60 | speechRecognition = $speechRecognitionProvider;
61 | }));
62 |
63 | it('should be defined', inject(function() {
64 | expect(speechRecognition).toBeDefined();
65 | }));
66 |
67 | it('should have DEST_LANG variable', inject(function() {
68 | expect(speechRecognition.DEST_LANG).toBeDefined();
69 | expect(typeof speechRecognition.DEST_LANG).toBe('string');
70 | expect(speechRecognition.DEST_LANG).toBe('en-US');
71 | }));
72 |
73 | it('should have default value en-US', inject(function() {
74 | expect(speechRecognition.DEST_LANG).toBe('en-US');
75 | }));
76 |
77 | it('should have setLang method', inject(function() {
78 | expect(speechRecognition.setLang).toBeDefined();
79 | expect(typeof speechRecognition.setLang).toBe('function');
80 | }));
81 |
82 | it('should change language', inject(function() {
83 | speechRecognition.setLang('sk-SK');
84 | expect(speechRecognition.DEST_LANG).toBe('sk-SK');
85 | }));
86 |
87 | it('should have $get method', inject(function() {
88 | expect(speechRecognition.$get).toBeDefined();
89 | expect(typeof speechRecognition.$get).toBe('object');
90 | }));
91 | });
92 |
93 |
94 | describe('$speechRecognition service', function() {
95 |
96 | beforeEach(module('adaptive.speech', function($speechRecognitionProvider) {
97 | // config provider
98 | }));
99 |
100 | it('should be defined', inject(function($speechRecognition) {
101 | expect($speechRecognition).toBeDefined();
102 | }));
103 |
104 | it('should have public methods', inject(function($speechRecognition) {
105 | expect($speechRecognition.onstart).toBeDefined();
106 | expect($speechRecognition.onerror).toBeDefined();
107 | expect($speechRecognition.onUtterance).toBeDefined();
108 | expect($speechRecognition.setLang).toBeDefined();
109 | expect($speechRecognition.getLang).toBeDefined();
110 | expect($speechRecognition.payAttention).toBeDefined();
111 | expect($speechRecognition.listen).toBeDefined();
112 | expect($speechRecognition.stopListening).toBeDefined();
113 | expect($speechRecognition.command).toBeDefined();
114 | expect($speechRecognition.listenUtterance).toBeDefined();
115 |
116 | expect(typeof $speechRecognition.onstart).toBe('function');
117 | expect(typeof $speechRecognition.onerror).toBe('function');
118 | expect(typeof $speechRecognition.onUtterance).toBe('function');
119 | expect(typeof $speechRecognition.setLang).toBe('function');
120 | expect(typeof $speechRecognition.getLang).toBe('function');
121 | expect(typeof $speechRecognition.payAttention).toBe('function');
122 | expect(typeof $speechRecognition.listen).toBe('function');
123 | expect(typeof $speechRecognition.stopListening).toBe('function');
124 | expect(typeof $speechRecognition.command).toBe('function');
125 | expect(typeof $speechRecognition.listenUtterance).toBe('function');
126 | }));
127 |
128 | it('should call functions', inject(function($speechRecognition) {
129 | spyOn($speechRecognition, 'onstart').andCallThrough();
130 | spyOn($speechRecognition, 'onerror').andCallThrough();
131 | spyOn($speechRecognition, 'onUtterance').andCallThrough();
132 | spyOn($speechRecognition, 'payAttention').andCallThrough();
133 | spyOn($speechRecognition, 'listen').andCallThrough();
134 | spyOn($speechRecognition, 'stopListening').andCallThrough();
135 |
136 | $speechRecognition.onstart();
137 | expect($speechRecognition.onstart).toHaveBeenCalled();
138 | $speechRecognition.onerror();
139 | expect($speechRecognition.onerror).toHaveBeenCalled();
140 | $speechRecognition.onUtterance();
141 | expect($speechRecognition.onUtterance).toHaveBeenCalled();
142 | $speechRecognition.payAttention();
143 | expect($speechRecognition.payAttention).toHaveBeenCalled();
144 | $speechRecognition.listen();
145 | expect($speechRecognition.listen).toHaveBeenCalled();
146 | $speechRecognition.stopListening();
147 | expect($speechRecognition.stopListening).toHaveBeenCalled();
148 | }));
149 |
150 | it('should change a language', inject(function($speechRecognition) {
151 | expect($speechRecognition.getLang()).toEqual('en-US');
152 | $speechRecognition.setLang('sk-SK');
153 | expect($speechRecognition.getLang()).toEqual('sk-SK');
154 | }));
155 |
156 | it('should have called rootScope.$on', inject(function($speechRecognition, $rootScope) {
157 | spyOn($rootScope, '$on').andCallThrough();
158 |
159 | $speechRecognition.listenUtterance();
160 | expect($rootScope.$on).toHaveBeenCalled();
161 | }));
162 |
163 | it('should have called rootScope.$emit', inject(function($speechRecognition, $rootScope) {
164 | spyOn($rootScope, '$emit').andCallThrough();
165 | $speechRecognition.command('do something');
166 | expect($rootScope.$emit).toHaveBeenCalled();
167 | }));
168 |
169 | it('should call a function after recognition - object', inject(function($speechRecognition, $rootScope) {
170 | var calledCount = 0;
171 | var mockUtterance = {'lang': 'en-US', 'utterance': 'do something'};
172 | var mockObject = {
173 | 'regex': /^do .+/gi,
174 | 'lang': 'en-US',
175 | 'call': function(utterance){
176 | calledCount += 1;
177 | }
178 | };
179 |
180 | $speechRecognition.listenUtterance(mockObject);
181 | expect(calledCount).toEqual(0);
182 |
183 | $rootScope.$emit('adaptive.speech:utterance', mockUtterance);
184 | expect(calledCount).toEqual(1);
185 | }));
186 |
187 | it('should call a function after recognition - array', inject(function($speechRecognition, $rootScope) {
188 | var calledCount = 0;
189 | var mockUtterance1 = {'lang': 'en-US', 'utterance': 'complete something'};
190 | var mockUtterance2 = {'lang': 'en-US', 'utterance': 'clear'};
191 | var mockArray = [{
192 | 'regex': /^complete .+/gi,
193 | 'lang': 'en-US',
194 | 'call': function(utterance){
195 | calledCount += 1;
196 | }
197 | },{
198 | 'regex': /clear.*/gi,
199 | 'lang': 'en-US',
200 | 'call': function(utterance){
201 | calledCount += 1;
202 | }
203 | }];
204 |
205 | $speechRecognition.listenUtterance(mockArray);
206 | expect(calledCount).toEqual(0);
207 |
208 | $rootScope.$emit('adaptive.speech:utterance', mockUtterance1);
209 | expect(calledCount).toEqual(1);
210 |
211 | $rootScope.$emit('adaptive.speech:utterance', mockUtterance2);
212 | expect(calledCount).toEqual(2);
213 | }));
214 |
215 | });
216 |
217 |
218 |
219 | describe('speechrecognition directive - object', function() {
220 | var elm, scope, calledCount;
221 | var rootscope;
222 |
223 | beforeEach(module('adaptive.speech'));
224 |
225 | beforeEach(inject(function($rootScope) {
226 | rootScope = $rootScope;
227 | spyOn(rootScope, '$on').andCallThrough();
228 | spyOn(rootScope, '$emit').andCallThrough();
229 | }));
230 |
231 | beforeEach(inject(function($rootScope, $compile) {
232 |
233 | elm = angular.element(
234 | '' +
235 | '' +
236 | '' +
237 | '' +
238 | '' +
239 | '
' +
240 | '' +
243 | ''
244 | );
245 |
246 | scope = $rootScope;
247 |
248 | scope.todo = {
249 | title: 'something',
250 | completed: false
251 | };
252 |
253 | scope.mockObject = {
254 | 'regex': /^complete .+/gi,
255 | 'lang': 'en-US',
256 | 'call': function(utterance){
257 | calledCount += 1;
258 | }
259 | };
260 |
261 | $compile(elm)(scope);
262 | scope.$digest();
263 | }));
264 |
265 | it('should have called rootScope.$on', function(){
266 | expect(rootScope.$on).toHaveBeenCalled();
267 | });
268 |
269 | it('should call a function after recognition', function() {
270 | calledCount = 0;
271 | var mockUtterance = {'lang': 'en-US', 'utterance': 'complete something'};
272 |
273 | rootScope.$emit('adaptive.speech:utterance', mockUtterance);
274 | expect(calledCount).toEqual(1);
275 | });
276 |
277 | });
278 |
279 |
280 | describe('speechrecognition directive - array', function() {
281 | var elm, scope, calledCount;
282 | var rootscope;
283 |
284 | beforeEach(module('adaptive.speech'));
285 |
286 | beforeEach(inject(function($rootScope) {
287 | rootScope = $rootScope;
288 | spyOn(rootScope, '$on').andCallThrough();
289 | spyOn(rootScope, '$emit').andCallThrough();
290 | }));
291 |
292 | beforeEach(inject(function($rootScope, $compile) {
293 | elm = angular.element(
294 | '' +
295 | '' +
296 | '' +
297 | '' +
298 | '' +
299 | '
' +
300 | '' +
303 | ''
304 | );
305 |
306 | scope = $rootScope;
307 |
308 | scope.todo = {
309 | title: 'something',
310 | completed: false
311 | };
312 |
313 | scope.mockArray = [{
314 | 'regex': /^complete .+/gi,
315 | 'lang': 'en-US',
316 | 'call': function(utterance){
317 | calledCount += 1;
318 | }
319 | },{
320 | 'regex': /^remove .+/gi,
321 | 'lang': 'en-US',
322 | 'call': function(utterance){
323 | calledCount += 1;
324 | }
325 | }];
326 |
327 | $compile(elm)(scope);
328 | scope.$digest();
329 | }));
330 |
331 | it('should have called rootScope.$on', function(){
332 | expect(rootScope.$on).toHaveBeenCalled();
333 | });
334 |
335 | it('should call a function after recognition', function() {
336 | calledCount = 0;
337 | var mockUtterance1 = {'lang': 'en-US', 'utterance': 'complete something'};
338 | var mockUtterance2 = {'lang': 'en-US', 'utterance': 'remove something'};
339 |
340 | rootScope.$emit('adaptive.speech:utterance', mockUtterance1);
341 | expect(calledCount).toEqual(1);
342 |
343 | rootScope.$emit('adaptive.speech:utterance', mockUtterance2);
344 | expect(calledCount).toEqual(2);
345 | });
346 |
347 | });
348 | });
349 |
--------------------------------------------------------------------------------
/src/angular-adaptive-speech.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var callCommands = function(tasks, DEST_LANG, utterance, reference){
4 | reference = reference || '.+';
5 | var commands = [];
6 |
7 | if (angular.isArray(tasks)) {
8 | commands = tasks;
9 | }
10 | else {
11 | commands.push(tasks);
12 | }
13 |
14 | commands.forEach(function(command){
15 | if (command.lang !== DEST_LANG) {
16 | return false;
17 | }
18 |
19 | var regex = command.regex || null;
20 |
21 | if (utterance.match(regex)) {
22 | if (utterance.match(new RegExp(reference, 'ig'))) {
23 | command.call(utterance);
24 | }
25 | }
26 | });
27 | };
28 |
29 | /**
30 | * @ngdoc overview
31 | * @name adaptive.speech
32 | *
33 | * @description
34 | * `adaptive.speech` is an Angular module which provides you with speech recognition
35 | * API's. Use its service to control your web app using speech commands. It's based
36 | * on Chrome's speech recognition API.
37 | */
38 | var adaptive = angular.module('adaptive.speech', []);
39 |
40 | adaptive.provider('$speechCorrection', function() {
41 |
42 | this.STORAGE_ID = 'adaptive:speech:correction';
43 | this.$get = function() {
44 |
45 | var STORAGE_ID = this.STORAGE_ID;
46 | var correctionMap = JSON.parse(localStorage.getItem(STORAGE_ID) || '{}');
47 |
48 | var save = function(STORAGE_ID, correctionMap){
49 | localStorage.setItem(STORAGE_ID, JSON.stringify(correctionMap));
50 | };
51 |
52 | var addUtterance = function(utterance, correction, lang){
53 | correctionMap[lang] = correctionMap[lang] || {};
54 | correctionMap[lang][utterance] = correction;
55 | };
56 |
57 | var removeUtterance = function(utterance, lang){
58 | delete correctionMap.lang[utterance];
59 | };
60 |
61 | var addLangMap = function(lang, map){
62 | correctionMap[lang] = correctionMap[lang] || {};
63 | correctionMap[lang] = map;
64 | };
65 |
66 | var clearLangMap = function(lang){
67 | delete correctionMap[lang];
68 | };
69 |
70 | var getCorrectionMap = function(){
71 | return correctionMap;
72 | };
73 |
74 | var getLangMap = function(lang){
75 | return correctionMap[lang];
76 | };
77 |
78 | var getCorrection = function(utterance, lang){
79 | return ((correctionMap[lang] && correctionMap[lang][utterance]) || utterance);
80 | };
81 |
82 | return {
83 | addUtterance: function(utterance, correction, lang){
84 | addUtterance(utterance, correction, lang);
85 | save(STORAGE_ID, correctionMap);
86 | },
87 |
88 | removeUtterance: function(utterance, lang){
89 | removeUtterance(utterance, lang);
90 | save(STORAGE_ID, correctionMap);
91 | },
92 |
93 | addLangMap: function(lang, map){
94 | addLangMap(lang, map);
95 | save(STORAGE_ID, correctionMap);
96 | },
97 |
98 | clearLangMap: function(lang){
99 | clearLangMap(lang);
100 | save(STORAGE_ID, correctionMap);
101 | },
102 |
103 | getCorrectionMap: function(){
104 | return getCorrectionMap();
105 | },
106 |
107 | getLangMap: function(lang){
108 | return getLangMap(lang);
109 | },
110 |
111 | getCorrection: function(utterance, lang){
112 | return getCorrection(utterance, lang);
113 | }
114 | };
115 |
116 | };
117 | });
118 |
119 | adaptive.provider('$speechSynthetis', function() {
120 |
121 | this.corsProxyServer = 'http://www.corsproxy.com/';
122 |
123 | this.$get = function() {
124 |
125 | var corsProxyServer = this.corsProxyServer;
126 | var justSpoke = false;
127 |
128 | /**
129 | * @ngdoc function
130 | * @name adaptive.speech.$speechSynthetis#speak
131 | * @methodOf apdative.speech.$speechSynthetis
132 | *
133 | * @description
134 | * Let's your computer speak to you. Simply pass a string with a text
135 | * you want your computer to say.
136 | *
137 | * @param {string} text Text
138 | * @param {string} lang Language
139 | */
140 | var speak = function(text, lang){
141 | if (!text) {
142 | return false;
143 | }
144 |
145 | var audioURL = [corsProxyServer, 'translate.google.com/translate_tts?ie=UTF-8&q=', text , '&tl=', lang].join('');
146 | var audio = new Audio();
147 |
148 | audio.addEventListener('play', function() {
149 | }, false);
150 |
151 | audio.addEventListener('ended', function() {
152 | justSpoke = true;
153 | }, false);
154 |
155 | audio.addEventListener('error', function() {
156 | }, false);
157 |
158 | audio.autoplay = true;
159 | audio.src = audioURL;
160 | };
161 |
162 | return {
163 | speak: function(text, lang){
164 | speak(text, lang);
165 | },
166 |
167 | justSpoke: function(){
168 | return justSpoke;
169 | },
170 |
171 | recognised: function(){
172 | justSpoke = false;
173 | }
174 | };
175 | };
176 | });
177 |
178 | /**
179 | * @ngdoc object
180 | * @name adaptive.speech.$speechRecognitionProvider
181 | *
182 | * @description
183 | * The `$speechRecognitionProvider` provides an interface to configure `$speechRecognition
184 | * service for runtime.
185 | */
186 |
187 | adaptive.provider('$speechRecognition', function() {
188 |
189 | this.DEST_LANG = 'en-US';
190 |
191 | this.setLang = function(lang){
192 | this.DEST_LANG = lang;
193 | };
194 |
195 | /**
196 | * @ngdoc object
197 | * @name adaptive.speech.$speechRecognition
198 | * @requires $rootScope
199 | *
200 | * @description
201 | * The `$speechRecognition` service is your interface to communicate with underlying
202 | * native speech recognition implementations by the browser. It provides several methods
203 | * to for example paying attention and listening to what the user says, or it can
204 | * react on specific callbacks.
205 | */
206 | this.$get = ['$rootScope', '$speechSynthetis', '$speechCorrection', function($rootScope, $speechSynthetis, $speechCorrection) {
207 |
208 | var DEST_LANG = this.DEST_LANG;
209 |
210 | var SpeechRecognitionMock = function(){
211 | this.start = function() { this.onerror({'code': 0, 'error': 'speech recognition is not supported'}); }.bind(this);
212 | this.stop = function() { this.onerror({'code': 0, 'error': 'speech recognition is not supported'}); }.bind(this);
213 | };
214 |
215 | window.SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition || SpeechRecognitionMock;
216 |
217 | var recognizer;
218 |
219 | var init = function(){
220 | recognizer = new window.SpeechRecognition();
221 | recognizer.continuous = true;
222 | recognizer.interimResults = true;
223 | recognizer.maxAlternatives = 3;
224 |
225 | recognizer.onresult = function(e) {
226 | if (onresult) {
227 | onresult(e);
228 | }
229 | };
230 |
231 | recognizer.onstart = function(e) {
232 | if (onstart) {
233 | onstart(e);
234 | }
235 | };
236 |
237 | recognizer.onend = function(e) {
238 | if (onend) {
239 | onend(e);
240 | }
241 | };
242 |
243 | recognizer.onerror = function(e) {
244 | if (onerror) {
245 | onerror(e);
246 | }
247 | };
248 | };
249 |
250 | init();
251 |
252 | var payingAttention = true;
253 | var isListening = false;
254 |
255 | /**
256 | * @ngdoc function
257 | * @name adaptive.speech.$speechRecognition#listen
258 | * @methodOf adaptive.speech.$speechRecognition
259 | *
260 | * @description
261 | * Starts the speech recognizer and listens for speech input.
262 | */
263 | var listen = function(){
264 | if (!isListening) {
265 | init();
266 | recognizer.start();
267 | }
268 | isListening = true;
269 | };
270 |
271 | var stopListening = function(){
272 | if (isListening) {
273 | recognizer.stop();
274 | }
275 | isListening = false;
276 | };
277 |
278 | var command = function(utterance){
279 | utterance = $speechCorrection.getCorrection(utterance, DEST_LANG);
280 | $rootScope.$emit('adaptive.speech:utterance', {'lang': DEST_LANG, 'utterance': utterance});
281 | };
282 |
283 | /**
284 | * @ngdoc function
285 | * @name adaptive.speech.$speechRecognition#setLang
286 | * @methodOf adaptive.speech.$speechRecognition
287 | *
288 | * @description
289 | * Configures speech recognizer to use given language when trying to recognize
290 | * speech input. Default is `en-US`.
291 | *
292 | * @
293 | */
294 | var setLang = function(lang){
295 | DEST_LANG = lang;
296 | recognizer.lang = lang;
297 | };
298 |
299 | var onstart, onerror;
300 |
301 | var onend = function(e){
302 | payingAttention = false;
303 | recognizer = null;
304 | };
305 |
306 | var onresult = function(e){
307 | if (e.results.length) {
308 | var result = e.results[e.resultIndex];
309 | if (result.isFinal) {
310 |
311 | if ($speechSynthetis.justSpoke()) {
312 | $speechSynthetis.recognised();
313 | return false;
314 | }
315 |
316 | var utterance = result[0].transcript.trim();
317 |
318 | if (payingAttention) {
319 | command(utterance);
320 | }
321 | }
322 | }
323 | };
324 |
325 | /**
326 | * @ngdoc function
327 | * @name adaptive.speech.$speechRecognition#listenUtterance
328 | * @methodOf adaptive.speech.$speechRecognition
329 | *
330 | * @description
331 | * With `$speechRecognition.listenUtterance()` you're able to setup several tasks
332 | * for the speech recognizer within your controller. `listenUtterance()` expects a
333 | * task description object, that holds defined tasks. A task needs an identifier,
334 | * a regex for the speech recognizer, as well as the language in which the speech
335 | * recognizer should interpret it.
336 | *
337 | * In addition one has to provide a function that will be called once the speech
338 | * recognizer recognizes the given pattern.
339 | *
340 | *
341 | * var app = angular.module('myApp', ['adaptive.speech']);
342 | *
343 | * app.controller('Ctrl', function ($speechRecognition) {
344 | *
345 | * $scope.recognition = {};
346 | * $scope.recognition['en-US'] = {
347 | * 'addToList': {
348 | * 'regex': /^to do .+/gi,
349 | * 'lang': 'en-US',
350 | * 'call': function(e){
351 | * $scope.addToList(e);
352 | * }
353 | * },
354 | * 'listTasks': [{
355 | * 'regex': /^complete .+/gi,
356 | * 'lang': 'en-US',
357 | * 'call': function(e){
358 | * $scope.completeTask(e);
359 | * }
360 | * },{
361 | * 'regex': /^remove .+/gi,
362 | * 'lang': 'en-US',
363 | * 'call': function(e){
364 | * $scope.removeTask(e);
365 | * }
366 | * }]
367 | * };
368 | * });
369 | *
370 | *
371 | * @param {object} tasks Task definition object
372 | */
373 | var listenUtterance = function(tasks){
374 | return $rootScope.$on('adaptive.speech:utterance', function(e, data){
375 | var utterance = data.utterance;
376 | callCommands(tasks, DEST_LANG, utterance);
377 | });
378 | };
379 |
380 | return {
381 | /**
382 | * @ngdoc function
383 | * @name adaptive.speech.$speechRecognition#onstart
384 | * @method adaptive.speech.$speechRecognition
385 | *
386 | * @description
387 | * Exepts a function which gets executed once `$speechRecognition` service
388 | * starts listening to speech input.
389 | *
390 | *
391 | * var app = angular.module('myApp', ['adaptive.speech']);
392 | *
393 | * app.controller('Ctrl', function ($speechRecognition, $speechSynthetis) {
394 | * $speechRecognition.onstart(function() {
395 | * $speechSynthetis.speak('Yes?, How can I help you?);
396 | * });
397 | * });
398 | *
399 | *
400 | * @param {object} onstartFn Function callback
401 | */
402 | onstart: function(fn){
403 | onstart = fn;
404 | },
405 |
406 | onerror: function(fn){
407 | onerror = fn;
408 | },
409 |
410 | onUtterance: function(cb){
411 | var unbind = $rootScope.$on('adaptive.speech:utterance', function(e, data){
412 | cb(data.utterance);
413 | });
414 |
415 | $rootScope.$on('destroy', unbind);
416 | },
417 |
418 | setLang: function(lang){
419 | setLang(lang);
420 | },
421 |
422 | /**
423 | * @ngdoc function
424 | * @name adaptive.speech.$speechRecognition#getLang
425 | * @methodOf adaptive.speech.$speechRecognition
426 | *
427 | * @description
428 | * Returns configured language that is used by speech recognizer.
429 | *
430 | * @return {string} lang Language key
431 | */
432 | getLang: function(){
433 | return DEST_LANG;
434 | },
435 |
436 | payAttention: function(){
437 | payingAttention = true;
438 | },
439 |
440 | ignore: function(){
441 | payingAttention = false;
442 | },
443 |
444 | listen: function(){
445 | listen();
446 | },
447 |
448 | stopListening: function(){
449 | stopListening();
450 | },
451 |
452 | command: function(utterance){
453 | command(utterance);
454 | },
455 |
456 | listenUtterance: function(tasks){
457 | return listenUtterance(tasks);
458 | }
459 | };
460 | }];
461 | });
462 |
463 | /**
464 | * @ngdoc object
465 | * @name adaptive.speech.directive:speechrecognition
466 | * @requires $rootScope
467 | * @restrict A
468 | *
469 | * @description
470 | * `adaptive.speech` provides an alternative way to define tasks, the speech
471 | * recognizer should listen to, to the `$speechRecognition.listenUtterance()` method.
472 | * All you have to do is to apply the `speechrecognition` directive to any element
473 | * and declare a object literal expression just as you would when using
474 | * `$speechRecognition.listenUtterance()`.
475 | */
476 | adaptive.directive('speechrecognition', ['$rootScope', '$speechRecognition', function ($rootScope, $speechRecognition) {
477 | return {
478 | restrict: 'A',
479 | link: function (scope, element, attrs) {
480 | var getOptions = function() {
481 | return angular.extend({}, scope.$eval(attrs.speechrecognition));
482 | };
483 | var opts = getOptions();
484 | var unbind = $rootScope.$on('adaptive.speech:utterance', function(e, data){
485 |
486 | var DEST_LANG = $speechRecognition.getLang();
487 | var utterance = data.utterance;
488 | callCommands(opts.tasks, DEST_LANG, utterance, opts.reference);
489 | });
490 |
491 | element.bind('$destroy', function() {
492 | unbind();
493 | });
494 |
495 | }
496 | };
497 | }]);
498 |
499 | })();
500 |
--------------------------------------------------------------------------------
/angular-adaptive-speech.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * angular-adaptive-speech v0.3.0
3 | * The MIT License
4 | * Copyright (c) 2014 Jan Antala
5 | */
6 |
7 | (function() {
8 |
9 | var callCommands = function(tasks, DEST_LANG, utterance, reference){
10 | reference = reference || '.+';
11 | var commands = [];
12 |
13 | if (angular.isArray(tasks)) {
14 | commands = tasks;
15 | }
16 | else {
17 | commands.push(tasks);
18 | }
19 |
20 | commands.forEach(function(command){
21 | if (command.lang !== DEST_LANG) {
22 | return false;
23 | }
24 |
25 | var regex = command.regex || null;
26 |
27 | if (utterance.match(regex)) {
28 | if (utterance.match(new RegExp(reference, 'ig'))) {
29 | command.call(utterance);
30 | }
31 | }
32 | });
33 | };
34 |
35 | /**
36 | * @ngdoc overview
37 | * @name adaptive.speech
38 | *
39 | * @description
40 | * `adaptive.speech` is an Angular module which provides you with speech recognition
41 | * API's. Use its service to control your web app using speech commands. It's based
42 | * on Chrome's speech recognition API.
43 | */
44 | var adaptive = angular.module('adaptive.speech', []);
45 |
46 | adaptive.provider('$speechCorrection', function() {
47 |
48 | this.STORAGE_ID = 'adaptive:speech:correction';
49 | this.$get = function() {
50 |
51 | var STORAGE_ID = this.STORAGE_ID;
52 | var correctionMap = JSON.parse(localStorage.getItem(STORAGE_ID) || '{}');
53 |
54 | var save = function(STORAGE_ID, correctionMap){
55 | localStorage.setItem(STORAGE_ID, JSON.stringify(correctionMap));
56 | };
57 |
58 | var addUtterance = function(utterance, correction, lang){
59 | correctionMap[lang] = correctionMap[lang] || {};
60 | correctionMap[lang][utterance] = correction;
61 | };
62 |
63 | var removeUtterance = function(utterance, lang){
64 | delete correctionMap.lang[utterance];
65 | };
66 |
67 | var addLangMap = function(lang, map){
68 | correctionMap[lang] = correctionMap[lang] || {};
69 | correctionMap[lang] = map;
70 | };
71 |
72 | var clearLangMap = function(lang){
73 | delete correctionMap[lang];
74 | };
75 |
76 | var getCorrectionMap = function(){
77 | return correctionMap;
78 | };
79 |
80 | var getLangMap = function(lang){
81 | return correctionMap[lang];
82 | };
83 |
84 | var getCorrection = function(utterance, lang){
85 | return ((correctionMap[lang] && correctionMap[lang][utterance]) || utterance);
86 | };
87 |
88 | return {
89 | addUtterance: function(utterance, correction, lang){
90 | addUtterance(utterance, correction, lang);
91 | save(STORAGE_ID, correctionMap);
92 | },
93 |
94 | removeUtterance: function(utterance, lang){
95 | removeUtterance(utterance, lang);
96 | save(STORAGE_ID, correctionMap);
97 | },
98 |
99 | addLangMap: function(lang, map){
100 | addLangMap(lang, map);
101 | save(STORAGE_ID, correctionMap);
102 | },
103 |
104 | clearLangMap: function(lang){
105 | clearLangMap(lang);
106 | save(STORAGE_ID, correctionMap);
107 | },
108 |
109 | getCorrectionMap: function(){
110 | return getCorrectionMap();
111 | },
112 |
113 | getLangMap: function(lang){
114 | return getLangMap(lang);
115 | },
116 |
117 | getCorrection: function(utterance, lang){
118 | return getCorrection(utterance, lang);
119 | }
120 | };
121 |
122 | };
123 | });
124 |
125 | adaptive.provider('$speechSynthetis', function() {
126 |
127 | this.corsProxyServer = 'http://www.corsproxy.com/';
128 |
129 | this.$get = function() {
130 |
131 | var corsProxyServer = this.corsProxyServer;
132 | var justSpoke = false;
133 |
134 | /**
135 | * @ngdoc function
136 | * @name adaptive.speech.$speechSynthetis#speak
137 | * @methodOf apdative.speech.$speechSynthetis
138 | *
139 | * @description
140 | * Let's your computer speak to you. Simply pass a string with a text
141 | * you want your computer to say.
142 | *
143 | * @param {string} text Text
144 | * @param {string} lang Language
145 | */
146 | var speak = function(text, lang){
147 | if (!text) {
148 | return false;
149 | }
150 |
151 | var audioURL = [corsProxyServer, 'translate.google.com/translate_tts?ie=UTF-8&q=', text , '&tl=', lang].join('');
152 | var audio = new Audio();
153 |
154 | audio.addEventListener('play', function() {
155 | }, false);
156 |
157 | audio.addEventListener('ended', function() {
158 | justSpoke = true;
159 | }, false);
160 |
161 | audio.addEventListener('error', function() {
162 | }, false);
163 |
164 | audio.autoplay = true;
165 | audio.src = audioURL;
166 | };
167 |
168 | return {
169 | speak: function(text, lang){
170 | speak(text, lang);
171 | },
172 |
173 | justSpoke: function(){
174 | return justSpoke;
175 | },
176 |
177 | recognised: function(){
178 | justSpoke = false;
179 | }
180 | };
181 | };
182 | });
183 |
184 | /**
185 | * @ngdoc object
186 | * @name adaptive.speech.$speechRecognitionProvider
187 | *
188 | * @description
189 | * The `$speechRecognitionProvider` provides an interface to configure `$speechRecognition
190 | * service for runtime.
191 | */
192 |
193 | adaptive.provider('$speechRecognition', function() {
194 |
195 | this.DEST_LANG = 'en-US';
196 |
197 | this.setLang = function(lang){
198 | this.DEST_LANG = lang;
199 | };
200 |
201 | /**
202 | * @ngdoc object
203 | * @name adaptive.speech.$speechRecognition
204 | * @requires $rootScope
205 | *
206 | * @description
207 | * The `$speechRecognition` service is your interface to communicate with underlying
208 | * native speech recognition implementations by the browser. It provides several methods
209 | * to for example paying attention and listening to what the user says, or it can
210 | * react on specific callbacks.
211 | */
212 | this.$get = ['$rootScope', '$speechSynthetis', '$speechCorrection', function($rootScope, $speechSynthetis, $speechCorrection) {
213 |
214 | var DEST_LANG = this.DEST_LANG;
215 |
216 | var SpeechRecognitionMock = function(){
217 | this.start = function() { this.onerror({'code': 0, 'error': 'speech recognition is not supported'}); }.bind(this);
218 | this.stop = function() { this.onerror({'code': 0, 'error': 'speech recognition is not supported'}); }.bind(this);
219 | };
220 |
221 | window.SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition || SpeechRecognitionMock;
222 |
223 | var recognizer;
224 |
225 | var init = function(){
226 | recognizer = new window.SpeechRecognition();
227 | recognizer.continuous = true;
228 | recognizer.interimResults = true;
229 | recognizer.maxAlternatives = 3;
230 |
231 | recognizer.onresult = function(e) {
232 | if (onresult) {
233 | onresult(e);
234 | }
235 | };
236 |
237 | recognizer.onstart = function(e) {
238 | if (onstart) {
239 | onstart(e);
240 | }
241 | };
242 |
243 | recognizer.onend = function(e) {
244 | if (onend) {
245 | onend(e);
246 | }
247 | };
248 |
249 | recognizer.onerror = function(e) {
250 | if (onerror) {
251 | onerror(e);
252 | }
253 | };
254 | };
255 |
256 | init();
257 |
258 | var payingAttention = true;
259 | var isListening = false;
260 |
261 | /**
262 | * @ngdoc function
263 | * @name adaptive.speech.$speechRecognition#listen
264 | * @methodOf adaptive.speech.$speechRecognition
265 | *
266 | * @description
267 | * Starts the speech recognizer and listens for speech input.
268 | */
269 | var listen = function(){
270 | if (!isListening) {
271 | init();
272 | recognizer.start();
273 | }
274 | isListening = true;
275 | };
276 |
277 | var stopListening = function(){
278 | if (isListening) {
279 | recognizer.stop();
280 | }
281 | isListening = false;
282 | };
283 |
284 | var command = function(utterance){
285 | utterance = $speechCorrection.getCorrection(utterance, DEST_LANG);
286 | $rootScope.$emit('adaptive.speech:utterance', {'lang': DEST_LANG, 'utterance': utterance});
287 | };
288 |
289 | /**
290 | * @ngdoc function
291 | * @name adaptive.speech.$speechRecognition#setLang
292 | * @methodOf adaptive.speech.$speechRecognition
293 | *
294 | * @description
295 | * Configures speech recognizer to use given language when trying to recognize
296 | * speech input. Default is `en-US`.
297 | *
298 | * @
299 | */
300 | var setLang = function(lang){
301 | DEST_LANG = lang;
302 | recognizer.lang = lang;
303 | };
304 |
305 | var onstart, onerror;
306 |
307 | var onend = function(e){
308 | payingAttention = false;
309 | recognizer = null;
310 | };
311 |
312 | var onresult = function(e){
313 | if (e.results.length) {
314 | var result = e.results[e.resultIndex];
315 | if (result.isFinal) {
316 |
317 | if ($speechSynthetis.justSpoke()) {
318 | $speechSynthetis.recognised();
319 | return false;
320 | }
321 |
322 | var utterance = result[0].transcript.trim();
323 |
324 | if (payingAttention) {
325 | command(utterance);
326 | }
327 | }
328 | }
329 | };
330 |
331 | /**
332 | * @ngdoc function
333 | * @name adaptive.speech.$speechRecognition#listenUtterance
334 | * @methodOf adaptive.speech.$speechRecognition
335 | *
336 | * @description
337 | * With `$speechRecognition.listenUtterance()` you're able to setup several tasks
338 | * for the speech recognizer within your controller. `listenUtterance()` expects a
339 | * task description object, that holds defined tasks. A task needs an identifier,
340 | * a regex for the speech recognizer, as well as the language in which the speech
341 | * recognizer should interpret it.
342 | *
343 | * In addition one has to provide a function that will be called once the speech
344 | * recognizer recognizes the given pattern.
345 | *
346 | *
347 | * var app = angular.module('myApp', ['adaptive.speech']);
348 | *
349 | * app.controller('Ctrl', function ($speechRecognition) {
350 | *
351 | * $scope.recognition = {};
352 | * $scope.recognition['en-US'] = {
353 | * 'addToList': {
354 | * 'regex': /^to do .+/gi,
355 | * 'lang': 'en-US',
356 | * 'call': function(e){
357 | * $scope.addToList(e);
358 | * }
359 | * },
360 | * 'listTasks': [{
361 | * 'regex': /^complete .+/gi,
362 | * 'lang': 'en-US',
363 | * 'call': function(e){
364 | * $scope.completeTask(e);
365 | * }
366 | * },{
367 | * 'regex': /^remove .+/gi,
368 | * 'lang': 'en-US',
369 | * 'call': function(e){
370 | * $scope.removeTask(e);
371 | * }
372 | * }]
373 | * };
374 | * });
375 | *
376 | *
377 | * @param {object} tasks Task definition object
378 | */
379 | var listenUtterance = function(tasks){
380 | return $rootScope.$on('adaptive.speech:utterance', function(e, data){
381 | var utterance = data.utterance;
382 | callCommands(tasks, DEST_LANG, utterance);
383 | });
384 | };
385 |
386 | return {
387 | /**
388 | * @ngdoc function
389 | * @name adaptive.speech.$speechRecognition#onstart
390 | * @method adaptive.speech.$speechRecognition
391 | *
392 | * @description
393 | * Exepts a function which gets executed once `$speechRecognition` service
394 | * starts listening to speech input.
395 | *
396 | *
397 | * var app = angular.module('myApp', ['adaptive.speech']);
398 | *
399 | * app.controller('Ctrl', function ($speechRecognition, $speechSynthetis) {
400 | * $speechRecognition.onstart(function() {
401 | * $speechSynthetis.speak('Yes?, How can I help you?);
402 | * });
403 | * });
404 | *
405 | *
406 | * @param {object} onstartFn Function callback
407 | */
408 | onstart: function(fn){
409 | onstart = fn;
410 | },
411 |
412 | onerror: function(fn){
413 | onerror = fn;
414 | },
415 |
416 | onUtterance: function(cb){
417 | var unbind = $rootScope.$on('adaptive.speech:utterance', function(e, data){
418 | cb(data.utterance);
419 | });
420 |
421 | $rootScope.$on('destroy', unbind);
422 | },
423 |
424 | setLang: function(lang){
425 | setLang(lang);
426 | },
427 |
428 | /**
429 | * @ngdoc function
430 | * @name adaptive.speech.$speechRecognition#getLang
431 | * @methodOf adaptive.speech.$speechRecognition
432 | *
433 | * @description
434 | * Returns configured language that is used by speech recognizer.
435 | *
436 | * @return {string} lang Language key
437 | */
438 | getLang: function(){
439 | return DEST_LANG;
440 | },
441 |
442 | payAttention: function(){
443 | payingAttention = true;
444 | },
445 |
446 | ignore: function(){
447 | payingAttention = false;
448 | },
449 |
450 | listen: function(){
451 | listen();
452 | },
453 |
454 | stopListening: function(){
455 | stopListening();
456 | },
457 |
458 | command: function(utterance){
459 | command(utterance);
460 | },
461 |
462 | listenUtterance: function(tasks){
463 | return listenUtterance(tasks);
464 | }
465 | };
466 | }];
467 | });
468 |
469 | /**
470 | * @ngdoc object
471 | * @name adaptive.speech.directive:speechrecognition
472 | * @requires $rootScope
473 | * @restrict A
474 | *
475 | * @description
476 | * `adaptive.speech` provides an alternative way to define tasks, the speech
477 | * recognizer should listen to, to the `$speechRecognition.listenUtterance()` method.
478 | * All you have to do is to apply the `speechrecognition` directive to any element
479 | * and declare a object literal expression just as you would when using
480 | * `$speechRecognition.listenUtterance()`.
481 | */
482 | adaptive.directive('speechrecognition', ['$rootScope', '$speechRecognition', function ($rootScope, $speechRecognition) {
483 | return {
484 | restrict: 'A',
485 | link: function (scope, element, attrs) {
486 | var getOptions = function() {
487 | return angular.extend({}, scope.$eval(attrs.speechrecognition));
488 | };
489 | var opts = getOptions();
490 | var unbind = $rootScope.$on('adaptive.speech:utterance', function(e, data){
491 |
492 | var DEST_LANG = $speechRecognition.getLang();
493 | var utterance = data.utterance;
494 | callCommands(opts.tasks, DEST_LANG, utterance, opts.reference);
495 | });
496 |
497 | element.bind('$destroy', function() {
498 | unbind();
499 | });
500 |
501 | }
502 | };
503 | }]);
504 |
505 | })();
506 |
--------------------------------------------------------------------------------
/demo/bower_components/angular-route/angular-route.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @license AngularJS v1.2.6-build.2014+sha.277a5ea
3 | * (c) 2010-2014 Google, Inc. http://angularjs.org
4 | * License: MIT
5 | */
6 | (function(window, angular, undefined) {'use strict';
7 |
8 | /**
9 | * @ngdoc overview
10 | * @name ngRoute
11 | * @description
12 | *
13 | * # ngRoute
14 | *
15 | * The `ngRoute` module provides routing and deeplinking services and directives for angular apps.
16 | *
17 | * ## Example
18 | * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
19 | *
20 | * {@installModule route}
21 | *
22 | *
23 | */
24 | /* global -ngRouteModule */
25 | var ngRouteModule = angular.module('ngRoute', ['ng']).
26 | provider('$route', $RouteProvider);
27 |
28 | /**
29 | * @ngdoc object
30 | * @name ngRoute.$routeProvider
31 | * @function
32 | *
33 | * @description
34 | *
35 | * Used for configuring routes.
36 | *
37 | * ## Example
38 | * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
39 | *
40 | * ## Dependencies
41 | * Requires the {@link ngRoute `ngRoute`} module to be installed.
42 | */
43 | function $RouteProvider(){
44 | function inherit(parent, extra) {
45 | return angular.extend(new (angular.extend(function() {}, {prototype:parent}))(), extra);
46 | }
47 |
48 | var routes = {};
49 |
50 | /**
51 | * @ngdoc method
52 | * @name ngRoute.$routeProvider#when
53 | * @methodOf ngRoute.$routeProvider
54 | *
55 | * @param {string} path Route path (matched against `$location.path`). If `$location.path`
56 | * contains redundant trailing slash or is missing one, the route will still match and the
57 | * `$location.path` will be updated to add or drop the trailing slash to exactly match the
58 | * route definition.
59 | *
60 | * * `path` can contain named groups starting with a colon: e.g. `:name`. All characters up
61 | * to the next slash are matched and stored in `$routeParams` under the given `name`
62 | * when the route matches.
63 | * * `path` can contain named groups starting with a colon and ending with a star:
64 | * e.g.`:name*`. All characters are eagerly stored in `$routeParams` under the given `name`
65 | * when the route matches.
66 | * * `path` can contain optional named groups with a question mark: e.g.`:name?`.
67 | *
68 | * For example, routes like `/color/:color/largecode/:largecode*\/edit` will match
69 | * `/color/brown/largecode/code/with/slashs/edit` and extract:
70 | *
71 | * * `color: brown`
72 | * * `largecode: code/with/slashs`.
73 | *
74 | *
75 | * @param {Object} route Mapping information to be assigned to `$route.current` on route
76 | * match.
77 | *
78 | * Object properties:
79 | *
80 | * - `controller` – `{(string|function()=}` – Controller fn that should be associated with
81 | * newly created scope or the name of a {@link angular.Module#controller registered
82 | * controller} if passed as a string.
83 | * - `controllerAs` – `{string=}` – A controller alias name. If present the controller will be
84 | * published to scope under the `controllerAs` name.
85 | * - `template` – `{string=|function()=}` – html template as a string or a function that
86 | * returns an html template as a string which should be used by {@link
87 | * ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives.
88 | * This property takes precedence over `templateUrl`.
89 | *
90 | * If `template` is a function, it will be called with the following parameters:
91 | *
92 | * - `{Array.