| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @fileoverview Base class for all speech rule stores. | 6 * @fileoverview Base class for all speech rule stores. |
| 7 * | 7 * |
| 8 * The base rule store implements some basic functionality that is common to | 8 * The base rule store implements some basic functionality that is common to |
| 9 * most speech rule stores. | 9 * most speech rule stores. |
| 10 */ | 10 */ |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 64 | 64 |
| 65 | 65 |
| 66 /** | 66 /** |
| 67 * @override | 67 * @override |
| 68 */ | 68 */ |
| 69 cvox.BaseRuleStore.prototype.lookupRule = function(node, dynamic) { | 69 cvox.BaseRuleStore.prototype.lookupRule = function(node, dynamic) { |
| 70 if (!node || | 70 if (!node || |
| 71 (node.nodeType != Node.ELEMENT_NODE && node.nodeType != Node.TEXT_NODE)) { | 71 (node.nodeType != Node.ELEMENT_NODE && node.nodeType != Node.TEXT_NODE)) { |
| 72 return null; | 72 return null; |
| 73 } | 73 } |
| 74 var matchingRules = this.speechRules_.filter( | 74 var matchingRules = this.speechRules_.filter(goog.bind(function(rule) { |
| 75 goog.bind( | 75 return this.testDynamicConstraints(dynamic, rule) && |
| 76 function(rule) { | 76 this.testPrecondition_(/** @type {!Node} */ (node), rule); |
| 77 return this.testDynamicConstraints(dynamic, rule) && | 77 }, this)); |
| 78 this.testPrecondition_(/** @type {!Node} */ (node), rule);}, | |
| 79 this)); | |
| 80 return (matchingRules.length > 0) ? | 78 return (matchingRules.length > 0) ? |
| 81 this.pickMostConstraint_(dynamic, matchingRules) : null; | 79 this.pickMostConstraint_(dynamic, matchingRules) : |
| 80 null; |
| 82 }; | 81 }; |
| 83 | 82 |
| 84 | 83 |
| 85 /** | 84 /** |
| 86 * @override | 85 * @override |
| 87 */ | 86 */ |
| 88 cvox.BaseRuleStore.prototype.defineRule = function( | 87 cvox.BaseRuleStore.prototype.defineRule = function( |
| 89 name, dynamic, action, prec, cstr) { | 88 name, dynamic, action, prec, cstr) { |
| 90 try { | 89 try { |
| 91 var postc = cvox.SpeechRule.Action.fromString(action); | 90 var postc = cvox.SpeechRule.Action.fromString(action); |
| 92 var cstrList = Array.prototype.slice.call(arguments, 4); | 91 var cstrList = Array.prototype.slice.call(arguments, 4); |
| 93 var fullPrec = new cvox.SpeechRule.Precondition(prec, cstrList); | 92 var fullPrec = new cvox.SpeechRule.Precondition(prec, cstrList); |
| 94 var dynamicCstr = {}; | 93 var dynamicCstr = {}; |
| 95 dynamicCstr[cvox.SpeechRule.DynamicCstrAttrib.STYLE] = dynamic; | 94 dynamicCstr[cvox.SpeechRule.DynamicCstrAttrib.STYLE] = dynamic; |
| 96 var rule = new cvox.SpeechRule(name, dynamicCstr, fullPrec, postc); | 95 var rule = new cvox.SpeechRule(name, dynamicCstr, fullPrec, postc); |
| 97 } catch (err) { | 96 } catch (err) { |
| 98 if (err.name == 'RuleError') { | 97 if (err.name == 'RuleError') { |
| 99 console.log('Rule Error ', prec, '(' + dynamic + '):', err.message); | 98 console.log('Rule Error ', prec, '(' + dynamic + '):', err.message); |
| 100 return null; | 99 return null; |
| 101 } | 100 } else { |
| 102 else { | |
| 103 throw err; | 101 throw err; |
| 104 } | 102 } |
| 105 } | 103 } |
| 106 this.addRule(rule); | 104 this.addRule(rule); |
| 107 return rule; | 105 return rule; |
| 108 }; | 106 }; |
| 109 | 107 |
| 110 | 108 |
| 111 /** | 109 /** |
| 112 * @override | 110 * @override |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 175 | 173 |
| 176 | 174 |
| 177 /** | 175 /** |
| 178 * Removes duplicates of the given rule from the rule store. Thereby duplicates | 176 * Removes duplicates of the given rule from the rule store. Thereby duplicates |
| 179 * are identified by having the same precondition and dynamic constraint. | 177 * are identified by having the same precondition and dynamic constraint. |
| 180 * @param {cvox.SpeechRule} rule The rule. | 178 * @param {cvox.SpeechRule} rule The rule. |
| 181 */ | 179 */ |
| 182 cvox.BaseRuleStore.prototype.removeDuplicates = function(rule) { | 180 cvox.BaseRuleStore.prototype.removeDuplicates = function(rule) { |
| 183 for (var i = this.speechRules_.length - 1, oldRule; | 181 for (var i = this.speechRules_.length - 1, oldRule; |
| 184 oldRule = this.speechRules_[i]; i--) { | 182 oldRule = this.speechRules_[i]; i--) { |
| 185 if (oldRule != rule && | 183 if (oldRule != rule && |
| 186 cvox.BaseRuleStore.compareDynamicConstraints_( | 184 cvox.BaseRuleStore.compareDynamicConstraints_( |
| 187 oldRule.dynamicCstr, rule.dynamicCstr) && | 185 oldRule.dynamicCstr, rule.dynamicCstr) && |
| 188 cvox.BaseRuleStore.comparePreconditions_(oldRule, rule)) { | 186 cvox.BaseRuleStore.comparePreconditions_(oldRule, rule)) { |
| 189 this.speechRules_.splice(i, 1); | 187 this.speechRules_.splice(i, 1); |
| 190 } | 188 } |
| 191 } | 189 } |
| 192 }; | 190 }; |
| 193 | 191 |
| 194 | 192 |
| 195 // TODO (sorge) These should move into the speech rule functions. | 193 // TODO (sorge) These should move into the speech rule functions. |
| 196 /** | 194 /** |
| 197 * Checks if we have a custom query and applies it. Otherwise returns null. | 195 * Checks if we have a custom query and applies it. Otherwise returns null. |
| 198 * @param {!Node} node The initial node. | 196 * @param {!Node} node The initial node. |
| 199 * @param {string} funcName A function name. | 197 * @param {string} funcName A function name. |
| 200 * @return {Array<Node>} The list of resulting nodes. | 198 * @return {Array<Node>} The list of resulting nodes. |
| 201 */ | 199 */ |
| 202 cvox.BaseRuleStore.prototype.applyCustomQuery = function( | 200 cvox.BaseRuleStore.prototype.applyCustomQuery = function(node, funcName) { |
| 203 node, funcName) { | |
| 204 var func = this.customQueries.lookup(funcName); | 201 var func = this.customQueries.lookup(funcName); |
| 205 return func ? func(node) : null; | 202 return func ? func(node) : null; |
| 206 }; | 203 }; |
| 207 | 204 |
| 208 | 205 |
| 209 /** | 206 /** |
| 210 * Applies either an Xpath selector or a custom query to the node | 207 * Applies either an Xpath selector or a custom query to the node |
| 211 * and returns the resulting node list. | 208 * and returns the resulting node list. |
| 212 * @param {!Node} node The initial node. | 209 * @param {!Node} node The initial node. |
| 213 * @param {string} expr An Xpath expression string or a name of a custom | 210 * @param {string} expr An Xpath expression string or a name of a custom |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 }; | 248 }; |
| 252 | 249 |
| 253 | 250 |
| 254 /** | 251 /** |
| 255 * Tests whether a speech rule satisfies a set of dynamic constraints. | 252 * Tests whether a speech rule satisfies a set of dynamic constraints. |
| 256 * @param {!cvox.SpeechRule.DynamicCstr} dynamic Dynamic constraints. | 253 * @param {!cvox.SpeechRule.DynamicCstr} dynamic Dynamic constraints. |
| 257 * @param {cvox.SpeechRule} rule The rule. | 254 * @param {cvox.SpeechRule} rule The rule. |
| 258 * @return {boolean} True if the preconditions apply to the node. | 255 * @return {boolean} True if the preconditions apply to the node. |
| 259 * @protected | 256 * @protected |
| 260 */ | 257 */ |
| 261 cvox.BaseRuleStore.prototype.testDynamicConstraints = function( | 258 cvox.BaseRuleStore.prototype.testDynamicConstraints = function(dynamic, rule) { |
| 262 dynamic, rule) { | |
| 263 // We allow a default value for each dynamic constraints attribute. | 259 // We allow a default value for each dynamic constraints attribute. |
| 264 // The idea is that when we can not find a speech rule matching the value for | 260 // The idea is that when we can not find a speech rule matching the value for |
| 265 // a particular attribute in the dynamic constraintwe choose the one that has | 261 // a particular attribute in the dynamic constraintwe choose the one that has |
| 266 // the value 'default'. | 262 // the value 'default'. |
| 267 var allKeys = /** @type {Array<cvox.SpeechRule.DynamicCstrAttrib>} */ ( | 263 var allKeys = /** @type {Array<cvox.SpeechRule.DynamicCstrAttrib>} */ ( |
| 268 Object.keys(dynamic)); | 264 Object.keys(dynamic)); |
| 269 return allKeys.every( | 265 return allKeys.every(function(key) { |
| 270 function(key) { | 266 return dynamic[key] == rule.dynamicCstr[key] || |
| 271 return dynamic[key] == rule.dynamicCstr[key] || | 267 rule.dynamicCstr[key] == 'default'; |
| 272 rule.dynamicCstr[key] == 'default'; | 268 }); |
| 273 }); | |
| 274 }; | 269 }; |
| 275 | 270 |
| 276 | 271 |
| 277 /** | 272 /** |
| 278 * Get a set of all dynamic constraint values. | 273 * Get a set of all dynamic constraint values. |
| 279 * @return {!Object<cvox.SpeechRule.DynamicCstrAttrib, Array<string>>} The | 274 * @return {!Object<cvox.SpeechRule.DynamicCstrAttrib, Array<string>>} The |
| 280 * object with all annotations. | 275 * object with all annotations. |
| 281 */ | 276 */ |
| 282 cvox.BaseRuleStore.prototype.getDynamicConstraintValues = function() { | 277 cvox.BaseRuleStore.prototype.getDynamicConstraintValues = function() { |
| 283 var result = {}; | 278 var result = {}; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 302 * @param {cvox.SpeechRule} rule The speech rule to match. | 297 * @param {cvox.SpeechRule} rule The speech rule to match. |
| 303 * @return {number} The number of matching dynamic constraint values. | 298 * @return {number} The number of matching dynamic constraint values. |
| 304 * @private | 299 * @private |
| 305 */ | 300 */ |
| 306 cvox.BaseRuleStore.prototype.countMatchingDynamicConstraintValues_ = function( | 301 cvox.BaseRuleStore.prototype.countMatchingDynamicConstraintValues_ = function( |
| 307 dynamic, rule) { | 302 dynamic, rule) { |
| 308 var result = 0; | 303 var result = 0; |
| 309 for (var i = 0, key; key = this.dynamicCstrAttribs[i]; i++) { | 304 for (var i = 0, key; key = this.dynamicCstrAttribs[i]; i++) { |
| 310 if (dynamic[key] == rule.dynamicCstr[key]) { | 305 if (dynamic[key] == rule.dynamicCstr[key]) { |
| 311 result++; | 306 result++; |
| 312 } else break; | 307 } else |
| 308 break; |
| 313 } | 309 } |
| 314 return result; | 310 return result; |
| 315 }; | 311 }; |
| 316 | 312 |
| 317 | 313 |
| 318 /** | 314 /** |
| 319 * Picks the result of the most constraint rule by prefering those: | 315 * Picks the result of the most constraint rule by prefering those: |
| 320 * 1) that best match the dynamic constraints. | 316 * 1) that best match the dynamic constraints. |
| 321 * 2) with the most additional constraints. | 317 * 2) with the most additional constraints. |
| 322 * @param {cvox.SpeechRule.DynamicCstr} dynamic Dynamic constraints. | 318 * @param {cvox.SpeechRule.DynamicCstr} dynamic Dynamic constraints. |
| 323 * @param {!Array<cvox.SpeechRule>} rules An array of rules. | 319 * @param {!Array<cvox.SpeechRule>} rules An array of rules. |
| 324 * @return {cvox.SpeechRule} The most constraint rule. | 320 * @return {cvox.SpeechRule} The most constraint rule. |
| 325 * @private | 321 * @private |
| 326 */ | 322 */ |
| 327 cvox.BaseRuleStore.prototype.pickMostConstraint_ = function(dynamic, rules) { | 323 cvox.BaseRuleStore.prototype.pickMostConstraint_ = function(dynamic, rules) { |
| 328 rules.sort(goog.bind( | 324 rules.sort(goog.bind(function(r1, r2) { |
| 329 function(r1, r2) { | 325 var count1 = this.countMatchingDynamicConstraintValues_(dynamic, r1); |
| 330 var count1 = this.countMatchingDynamicConstraintValues_(dynamic, r1); | 326 var count2 = this.countMatchingDynamicConstraintValues_(dynamic, r2); |
| 331 var count2 = this.countMatchingDynamicConstraintValues_(dynamic, r2); | 327 // Rule one is a better match, don't swap. |
| 332 // Rule one is a better match, don't swap. | 328 if (count1 > count2) { |
| 333 if (count1 > count2) { | 329 return -1; |
| 334 return -1; | 330 } |
| 335 } | 331 // Rule two is a better match, swap. |
| 336 // Rule two is a better match, swap. | 332 if (count2 > count1) { |
| 337 if (count2 > count1) { | 333 return 1; |
| 338 return 1; | 334 } |
| 339 } | 335 // When same number of dynamic constraint attributes matches for |
| 340 // When same number of dynamic constraint attributes matches for | 336 // both rules, compare length of static constraints. |
| 341 // both rules, compare length of static constraints. | 337 return ( |
| 342 return (r2.precondition.constraints.length - | 338 r2.precondition.constraints.length - |
| 343 r1.precondition.constraints.length);}, | 339 r1.precondition.constraints.length); |
| 344 this)); | 340 }, this)); |
| 345 return rules[0]; | 341 return rules[0]; |
| 346 }; | 342 }; |
| 347 | 343 |
| 348 | 344 |
| 349 /** | 345 /** |
| 350 * Test the precondition of a speech rule. | 346 * Test the precondition of a speech rule. |
| 351 * @param {!Node} node on which to test applicability of the rule. | 347 * @param {!Node} node on which to test applicability of the rule. |
| 352 * @param {cvox.SpeechRule} rule The rule to be tested. | 348 * @param {cvox.SpeechRule} rule The rule to be tested. |
| 353 * @return {boolean} True if the preconditions apply to the node. | 349 * @return {boolean} True if the preconditions apply to the node. |
| 354 * @private | 350 * @private |
| 355 */ | 351 */ |
| 356 cvox.BaseRuleStore.prototype.testPrecondition_ = function(node, rule) { | 352 cvox.BaseRuleStore.prototype.testPrecondition_ = function(node, rule) { |
| 357 var prec = rule.precondition; | 353 var prec = rule.precondition; |
| 358 return this.applyQuery(node, prec.query) === node && | 354 return this.applyQuery(node, prec.query) === node && |
| 359 prec.constraints.every( | 355 prec.constraints.every(goog.bind(function(cstr) { |
| 360 goog.bind(function(cstr) { | 356 return this.applyConstraint(node, cstr); |
| 361 return this.applyConstraint(node, cstr);}, | 357 }, this)); |
| 362 this)); | |
| 363 }; | 358 }; |
| 364 | 359 |
| 365 | 360 |
| 366 // TODO (sorge) Define the following methods directly on the dynamic constraint | 361 // TODO (sorge) Define the following methods directly on the dynamic constraint |
| 367 // and precondition classes, respectively. | 362 // and precondition classes, respectively. |
| 368 /** | 363 /** |
| 369 * Compares two dynamic constraints and returns true if they are equal. | 364 * Compares two dynamic constraints and returns true if they are equal. |
| 370 * @param {cvox.SpeechRule.DynamicCstr} cstr1 First dynamic constraints. | 365 * @param {cvox.SpeechRule.DynamicCstr} cstr1 First dynamic constraints. |
| 371 * @param {cvox.SpeechRule.DynamicCstr} cstr2 Second dynamic constraints. | 366 * @param {cvox.SpeechRule.DynamicCstr} cstr2 Second dynamic constraints. |
| 372 * @return {boolean} True if the dynamic constraints are equal. | 367 * @return {boolean} True if the dynamic constraints are equal. |
| 373 * @private | 368 * @private |
| 374 */ | 369 */ |
| 375 cvox.BaseRuleStore.compareDynamicConstraints_ = function( | 370 cvox.BaseRuleStore.compareDynamicConstraints_ = function(cstr1, cstr2) { |
| 376 cstr1, cstr2) { | |
| 377 if (Object.keys(cstr1).length != Object.keys(cstr2).length) { | 371 if (Object.keys(cstr1).length != Object.keys(cstr2).length) { |
| 378 return false; | 372 return false; |
| 379 } | 373 } |
| 380 for (var key in cstr1) { | 374 for (var key in cstr1) { |
| 381 if (!cstr2[key] || cstr1[key] !== cstr2[key]) { | 375 if (!cstr2[key] || cstr1[key] !== cstr2[key]) { |
| 382 return false; | 376 return false; |
| 383 } | 377 } |
| 384 } | 378 } |
| 385 return true; | 379 return true; |
| 386 }; | 380 }; |
| 387 | 381 |
| 388 | 382 |
| 389 /** | 383 /** |
| 390 * Compares two static constraints (i.e., lists of precondition constraints) and | 384 * Compares two static constraints (i.e., lists of precondition constraints) and |
| 391 * returns true if they are equal. | 385 * returns true if they are equal. |
| 392 * @param {Array<string>} cstr1 First static constraints. | 386 * @param {Array<string>} cstr1 First static constraints. |
| 393 * @param {Array<string>} cstr2 Second static constraints. | 387 * @param {Array<string>} cstr2 Second static constraints. |
| 394 * @return {boolean} True if the static constraints are equal. | 388 * @return {boolean} True if the static constraints are equal. |
| 395 * @private | 389 * @private |
| 396 */ | 390 */ |
| 397 cvox.BaseRuleStore.compareStaticConstraints_ = function( | 391 cvox.BaseRuleStore.compareStaticConstraints_ = function(cstr1, cstr2) { |
| 398 cstr1, cstr2) { | |
| 399 if (cstr1.length != cstr2.length) { | 392 if (cstr1.length != cstr2.length) { |
| 400 return false; | 393 return false; |
| 401 } | 394 } |
| 402 for (var i = 0, cstr; cstr = cstr1[i]; i++) { | 395 for (var i = 0, cstr; cstr = cstr1[i]; i++) { |
| 403 if (cstr2.indexOf(cstr) == -1) { | 396 if (cstr2.indexOf(cstr) == -1) { |
| 404 return false; | 397 return false; |
| 405 } | 398 } |
| 406 } | 399 } |
| 407 return true; | 400 return true; |
| 408 }; | 401 }; |
| 409 | 402 |
| 410 | 403 |
| 411 /** | 404 /** |
| 412 * Compares the preconditions of two speech rules. | 405 * Compares the preconditions of two speech rules. |
| 413 * @param {cvox.SpeechRule} rule1 The first speech rule. | 406 * @param {cvox.SpeechRule} rule1 The first speech rule. |
| 414 * @param {cvox.SpeechRule} rule2 The second speech rule. | 407 * @param {cvox.SpeechRule} rule2 The second speech rule. |
| 415 * @return {boolean} True if the preconditions are equal. | 408 * @return {boolean} True if the preconditions are equal. |
| 416 * @private | 409 * @private |
| 417 */ | 410 */ |
| 418 cvox.BaseRuleStore.comparePreconditions_ = function(rule1, rule2) { | 411 cvox.BaseRuleStore.comparePreconditions_ = function(rule1, rule2) { |
| 419 var prec1 = rule1.precondition; | 412 var prec1 = rule1.precondition; |
| 420 var prec2 = rule2.precondition; | 413 var prec2 = rule2.precondition; |
| 421 if (prec1.query != prec2.query) { | 414 if (prec1.query != prec2.query) { |
| 422 return false; | 415 return false; |
| 423 } | 416 } |
| 424 return cvox.BaseRuleStore.compareStaticConstraints_( | 417 return cvox.BaseRuleStore.compareStaticConstraints_( |
| 425 prec1.constraints, prec2.constraints); | 418 prec1.constraints, prec2.constraints); |
| 426 }; | 419 }; |
| OLD | NEW |