3 * Copyright (C) 2010 Google Inc.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 * @fileoverview A formatter which formats phone numbers as they are entered.
20 * (based on the java implementation).
22 * An AsYouTypeFormatter could be created by new AsYouTypeFormatter(). After
23 * that digits could be added by invoking the inputDigit method on the formatter
24 * instance, and the partially formatted phone number will be returned each time
25 * a digit is added. The clear method should be invoked before a new number
26 * needs to be formatted.
28 * See testAsYouTypeFormatterUS(), testAsYouTestFormatterGB() and
29 * testAsYouTypeFormatterDE() in asyoutypeformatter_test.js for more details
30 * on how the formatter is to be used.
32 * @author Nikolaos Trogkanis
35 goog.provide('i18n.phonenumbers.AsYouTypeFormatter');
37 goog.require('goog.string.StringBuffer');
38 goog.require('i18n.phonenumbers.NumberFormat');
39 goog.require('i18n.phonenumbers.PhoneMetadata');
40 goog.require('i18n.phonenumbers.PhoneMetadataCollection');
41 goog.require('i18n.phonenumbers.PhoneNumber');
42 goog.require('i18n.phonenumbers.PhoneNumber.CountryCodeSource');
43 goog.require('i18n.phonenumbers.PhoneNumberDesc');
44 goog.require('i18n.phonenumbers.PhoneNumberUtil');
45 goog.require('i18n.phonenumbers.metadata');
50 * Constructs a light-weight formatter which does no formatting, but outputs
51 * exactly what is fed into the inputDigit method.
53 * @param {string} regionCode the country/region where the phone number is being
57 i18n.phonenumbers.AsYouTypeFormatter = function(regionCode) {
59 * A pattern that is used to match character classes in regular expressions.
60 * An example of a character class is [1-4].
65 this.CHARACTER_CLASS_PATTERN_ = /\[([^\[\]])*\]/g;
67 * Any digit in a regular expression that actually denotes a digit. For
68 * example, in the regular expression 80[0-2]\d{6,10}, the first 2 digits
69 * (8 and 0) are standalone digits, but the rest are not.
70 * Two look-aheads are needed because the number following \\d could be a
71 * two-digit number, since the phone number can be as long as 15 digits.
76 this.STANDALONE_DIGIT_PATTERN_ = /\d(?=[^,}][^,}])/g;
78 * This is the minimum length of national number accrued that is required to
79 * trigger the formatter. The first element of the leadingDigitsPattern of
80 * each numberFormat contains a regular expression that matches up to this
86 this.MIN_LEADING_DIGITS_LENGTH_ = 3;
88 * The digits that have not been entered yet will be represented by a \u2008,
89 * the punctuation space.
94 this.digitPlaceholder_ = '\u2008';
99 this.digitPattern_ = new RegExp(this.digitPlaceholder_);
104 this.currentOutput_ = '';
106 * @type {!goog.string.StringBuffer}
109 this.formattingTemplate_ = new goog.string.StringBuffer();
111 * The pattern from numberFormat that is currently used to create
112 * formattingTemplate.
116 this.currentFormattingPattern_ = '';
118 * @type {!goog.string.StringBuffer}
121 this.accruedInput_ = new goog.string.StringBuffer();
123 * @type {!goog.string.StringBuffer}
126 this.accruedInputWithoutFormatting_ = new goog.string.StringBuffer();
131 this.ableToFormat_ = true;
136 this.isInternationalFormatting_ = false;
141 this.isExpectingCountryCode_ = false;
143 * @type {i18n.phonenumbers.PhoneNumberUtil}
146 this.phoneUtil_ = i18n.phonenumbers.PhoneNumberUtil.getInstance();
151 this.lastMatchPosition_ = 0;
153 * The position of a digit upon which inputDigitAndRememberPosition is most
154 * recently invoked, as found in the original sequence of characters the user
159 this.originalPosition_ = 0;
161 * The position of a digit upon which inputDigitAndRememberPosition is most
162 * recently invoked, as found in accruedInputWithoutFormatting.
167 this.positionToRemember_ = 0;
169 * @type {!goog.string.StringBuffer}
172 this.prefixBeforeNationalNumber_ = new goog.string.StringBuffer();
174 * @type {!goog.string.StringBuffer}
177 this.nationalNumber_ = new goog.string.StringBuffer();
179 * @type {Array.<i18n.phonenumbers.NumberFormat>}
182 this.possibleFormats_ = [];
187 this.defaultCountry_ = regionCode;
188 this.initializeCountrySpecificInfo_(this.defaultCountry_);
190 * @type {i18n.phonenumbers.PhoneMetadata}
193 this.defaultMetaData_ = this.currentMetaData_;
198 * @param {string} regionCode
201 i18n.phonenumbers.AsYouTypeFormatter.prototype.initializeCountrySpecificInfo_ =
202 function(regionCode) {
204 /** @type {i18n.phonenumbers.PhoneMetadata} */
205 this.currentMetaData_ = this.phoneUtil_.getMetadataForRegion(regionCode);
206 if (this.currentMetaData_ == null) {
207 // Set to a default instance of the metadata. This allows us to function
208 // with an incorrect region code, even if formatting only works for numbers
209 // specified with '+'.
210 this.currentMetaData_ = new i18n.phonenumbers.PhoneMetadata();
211 this.currentMetaData_.setInternationalPrefix('NA');
213 /** @type {RegExp} */
214 this.nationalPrefixForParsing_ = new RegExp('^(' + this.currentMetaData_
215 .getNationalPrefixForParsing() + ')');
216 /** @type {RegExp} */
217 this.internationalPrefix_ = new RegExp('^(' + '\\+|' +
218 this.currentMetaData_.getInternationalPrefix() + ')');
223 * @return {boolean} true if a new template is created as opposed to reusing the
227 i18n.phonenumbers.AsYouTypeFormatter.prototype.maybeCreateNewTemplate_ =
230 // When there are multiple available formats, the formatter uses the first
231 // format where a formatting template could be created.
232 /** @type {number} */
233 var possibleFormatsLength = this.possibleFormats_.length;
234 for (var i = 0; i < possibleFormatsLength; ++i) {
235 /** @type {i18n.phonenumbers.NumberFormat} */
236 var numberFormat = this.possibleFormats_[i];
237 /** @type {string} */
238 var pattern = numberFormat.getPatternOrDefault();
239 if (this.currentFormattingPattern_ == pattern) {
242 if (this.createFormattingTemplate_(numberFormat)) {
243 this.currentFormattingPattern_ = pattern;
247 this.ableToFormat_ = false;
253 * @param {string} leadingThreeDigits
256 i18n.phonenumbers.AsYouTypeFormatter.prototype.getAvailableFormats_ =
257 function(leadingThreeDigits) {
259 /** @type {Array.<i18n.phonenumbers.NumberFormat>} */
260 var formatList = (this.isInternationalFormatting_ && this.currentMetaData_
261 .intlNumberFormatCount() > 0) ? this.currentMetaData_
262 .intlNumberFormatArray() : this.currentMetaData_.numberFormatArray();
263 this.possibleFormats_ = formatList;
264 this.narrowDownPossibleFormats_(leadingThreeDigits);
269 * @param {string} leadingDigits
272 i18n.phonenumbers.AsYouTypeFormatter.prototype.narrowDownPossibleFormats_ =
273 function(leadingDigits) {
275 /** @type {Array.<i18n.phonenumbers.NumberFormat>} */
276 var possibleFormats = [];
277 /** @type {number} */
278 var lengthOfLeadingDigits = leadingDigits.length;
279 /** @type {number} */
280 var indexOfLeadingDigitsPattern =
281 lengthOfLeadingDigits - this.MIN_LEADING_DIGITS_LENGTH_;
282 /** @type {number} */
283 var possibleFormatsLength = this.possibleFormats_.length;
284 for (var i = 0; i < possibleFormatsLength; ++i) {
285 /** @type {i18n.phonenumbers.NumberFormat} */
286 var format = this.possibleFormats_[i];
287 if (format.leadingDigitsPatternCount() > indexOfLeadingDigitsPattern) {
288 /** @type {RegExp} */
289 var leadingDigitsPattern = new RegExp('^(' +
290 format.getLeadingDigitsPattern(indexOfLeadingDigitsPattern) + ')');
291 if (leadingDigitsPattern.test(leadingDigits)) {
292 possibleFormats.push(this.possibleFormats_[i]);
295 // else the particular format has no more specific leadingDigitsPattern,
296 // and it should be retained.
297 possibleFormats.push(this.possibleFormats_[i]);
300 this.possibleFormats_ = possibleFormats;
305 * @param {i18n.phonenumbers.NumberFormat} format
309 i18n.phonenumbers.AsYouTypeFormatter.prototype.createFormattingTemplate_ =
312 /** @type {string} */
313 var numberFormat = format.getFormatOrDefault();
314 /** @type {string} */
315 var numberPattern = format.getPatternOrDefault();
317 // The formatter doesn't format numbers when numberPattern contains '|', e.g.
318 // (20|3)\d{4}. In those cases we quickly return.
319 if (numberPattern.indexOf('|') != -1) {
323 // Replace anything in the form of [..] with \d
324 numberPattern = numberPattern.replace(this.CHARACTER_CLASS_PATTERN_, '\\d');
326 // Replace any standalone digit (not the one in d{}) with \d
327 numberPattern = numberPattern.replace(this.STANDALONE_DIGIT_PATTERN_, '\\d');
328 this.formattingTemplate_.clear();
329 /** @type {string} */
330 var tempTemplate = this.getFormattingTemplate_(numberPattern, numberFormat);
331 if (tempTemplate.length > this.nationalNumber_.getLength()) {
332 this.formattingTemplate_.append(tempTemplate);
340 * Gets a formatting template which could be used to efficiently format a
341 * partial number where digits are added one by one.
343 * @param {string} numberPattern
344 * @param {string} numberFormat
348 i18n.phonenumbers.AsYouTypeFormatter.prototype.getFormattingTemplate_ =
349 function(numberPattern, numberFormat) {
351 // Creates a phone number consisting only of the digit 9 that matches the
352 // numberPattern by applying the pattern to the longestPhoneNumber string.
353 /** @type {string} */
354 var longestPhoneNumber = '999999999999999';
355 /** @type {Array.<string>} */
356 var m = longestPhoneNumber.match(numberPattern);
357 // this match will always succeed
358 /** @type {string} */
359 var aPhoneNumber = m[0];
360 // Formats the number according to numberFormat
361 /** @type {string} */
362 var template = aPhoneNumber.replace(new RegExp(numberPattern, 'g'),
364 // Replaces each digit with character digitPlaceholder
365 template = template.replace(new RegExp('9', 'g'), this.digitPlaceholder_);
371 * Clears the internal state of the formatter, so it could be reused.
373 i18n.phonenumbers.AsYouTypeFormatter.prototype.clear = function() {
374 this.currentOutput_ = '';
375 this.accruedInput_.clear();
376 this.accruedInputWithoutFormatting_.clear();
377 this.formattingTemplate_.clear();
378 this.lastMatchPosition_ = 0;
379 this.currentFormattingPattern_ = '';
380 this.prefixBeforeNationalNumber_.clear();
381 this.nationalNumber_.clear();
382 this.ableToFormat_ = true;
383 this.positionToRemember_ = 0;
384 this.originalPosition_ = 0;
385 this.isInternationalFormatting_ = false;
386 this.isExpectingCountryCode_ = false;
387 this.possibleFormats_ = [];
388 if (this.currentMetaData_ != this.defaultMetaData_) {
389 this.initializeCountrySpecificInfo_(this.defaultCountry_);
395 * Formats a phone number on-the-fly as each digit is entered.
397 * @param {string} nextChar the most recently entered digit of a phone number.
398 * Formatting characters are allowed, but they are removed from the result.
399 * @return {string} the partially formatted phone number.
401 i18n.phonenumbers.AsYouTypeFormatter.prototype.inputDigit = function(nextChar) {
402 this.currentOutput_ =
403 this.inputDigitWithOptionToRememberPosition_(nextChar, false);
404 return this.currentOutput_;
409 * Same as inputDigit, but remembers the position where nextChar is inserted, so
410 * that it could be retrieved later by using getRememberedPosition(). The
411 * remembered position will be automatically adjusted if additional formatting
412 * characters are later inserted/removed in front of nextChar.
414 * @param {string} nextChar
417 i18n.phonenumbers.AsYouTypeFormatter.prototype.inputDigitAndRememberPosition =
420 this.currentOutput_ =
421 this.inputDigitWithOptionToRememberPosition_(nextChar, true);
422 return this.currentOutput_;
427 * @param {string} nextChar
428 * @param {boolean} rememberPosition
432 i18n.phonenumbers.AsYouTypeFormatter.prototype.
433 inputDigitWithOptionToRememberPosition_ = function(nextChar,
436 this.accruedInput_.append(nextChar);
437 if (rememberPosition) {
438 this.originalPosition_ = this.accruedInput_.getLength();
440 // We do formatting on-the-fly only when each character entered is either a
441 // plus sign or a digit.
442 if (!i18n.phonenumbers.PhoneNumberUtil.VALID_START_CHAR_PATTERN
444 this.ableToFormat_ = false;
446 if (!this.ableToFormat_) {
447 return this.accruedInput_.toString();
450 nextChar = this.normalizeAndAccrueDigitsAndPlusSign_(nextChar,
453 // We start to attempt to format only when at least MIN_LEADING_DIGITS_LENGTH
454 // digits (the plus sign is counted as a digit as well for this purpose) have
456 switch (this.accruedInputWithoutFormatting_.getLength()) {
457 case 0: // when the first few inputs are neither digits nor the plus sign.
460 return this.accruedInput_.toString();
462 if (this.attemptToExtractIdd_()) {
463 this.isExpectingCountryCode_ = true;
465 // No IDD or plus sign is found, must be entering in national format.
466 this.removeNationalPrefixFromNationalNumber_();
467 return this.attemptToChooseFormattingPattern_();
471 if (this.isExpectingCountryCode_) {
472 if (this.attemptToExtractCountryCode_()) {
473 this.isExpectingCountryCode_ = false;
475 return this.prefixBeforeNationalNumber_.toString() +
476 this.nationalNumber_.toString();
478 // We make a last attempt to extract a country code at the 6th digit because
479 // the maximum length of IDD and country code are both 3.
481 if (this.isExpectingCountryCode_ &&
482 !this.attemptToExtractCountryCode_()) {
483 this.ableToFormat_ = false;
484 return this.accruedInput_.toString();
487 if (this.possibleFormats_.length > 0) {
488 // The formatting pattern is already chosen.
489 /** @type {string} */
490 var tempNationalNumber = this.inputDigitHelper_(nextChar);
491 // See if the accrued digits can be formatted properly already. If not,
492 // use the results from inputDigitHelper, which does formatting based on
493 // the formatting pattern chosen.
494 /** @type {string} */
495 var formattedNumber = this.attemptToFormatAccruedDigits_();
496 if (formattedNumber.length > 0) {
497 return formattedNumber;
499 this.narrowDownPossibleFormats_(this.nationalNumber_.toString());
500 if (this.maybeCreateNewTemplate_()) {
501 return this.inputAccruedNationalNumber_();
503 return this.ableToFormat_ ?
504 this.prefixBeforeNationalNumber_.toString() + tempNationalNumber :
507 return this.attemptToChooseFormattingPattern_();
517 i18n.phonenumbers.AsYouTypeFormatter.prototype.attemptToFormatAccruedDigits_ =
520 /** @type {string} */
521 var nationalNumber = this.nationalNumber_.toString();
522 /** @type {number} */
523 var possibleFormatsLength = this.possibleFormats_.length;
524 for (var i = 0; i < possibleFormatsLength; ++i) {
525 /** @type {i18n.phonenumbers.NumberFormat} */
526 var numFormat = this.possibleFormats_[i];
527 /** @type {string} */
528 var pattern = numFormat.getPatternOrDefault();
529 /** @type {RegExp} */
530 var patternRegExp = new RegExp('^(' + pattern + ')$');
531 if (patternRegExp.test(nationalNumber)) {
532 /** @type {string} */
533 var formattedNumber = nationalNumber.replace(new RegExp(pattern, 'g'),
534 numFormat.getFormat());
535 return this.prefixBeforeNationalNumber_.toString() + formattedNumber;
543 * Returns the current position in the partially formatted phone number of the
544 * character which was previously passed in as the parameter of
545 * inputDigitAndRememberPosition().
549 i18n.phonenumbers.AsYouTypeFormatter.prototype.getRememberedPosition =
552 if (!this.ableToFormat_) {
553 return this.originalPosition_;
555 /** @type {number} */
556 var accruedInputIndex = 0;
557 /** @type {number} */
558 var currentOutputIndex = 0;
559 /** @type {string} */
560 var accruedInputWithoutFormatting =
561 this.accruedInputWithoutFormatting_.toString();
562 /** @type {string} */
563 var currentOutput = this.currentOutput_.toString();
564 /** @type {number} */
565 var currentOutputLength = currentOutput.length;
566 while (accruedInputIndex < this.positionToRemember_ &&
567 currentOutputIndex < currentOutputLength) {
568 if (accruedInputWithoutFormatting.charAt(accruedInputIndex) ==
569 currentOutput.charAt(currentOutputIndex)) {
571 currentOutputIndex++;
573 currentOutputIndex++;
576 return currentOutputIndex;
581 * Attempts to set the formatting template and returns a string which contains
582 * the formatted version of the digits entered so far.
587 i18n.phonenumbers.AsYouTypeFormatter.prototype.
588 attemptToChooseFormattingPattern_ = function() {
590 /** @type {string} */
591 var nationalNumber = this.nationalNumber_.toString();
592 // We start to attempt to format only when as least MIN_LEADING_DIGITS_LENGTH
593 // digits of national number (excluding national prefix) have been entered.
594 if (nationalNumber.length >= this.MIN_LEADING_DIGITS_LENGTH_) {
595 this.getAvailableFormats_(
596 nationalNumber.substring(0, this.MIN_LEADING_DIGITS_LENGTH_));
597 this.maybeCreateNewTemplate_();
598 return this.inputAccruedNationalNumber_();
600 return this.prefixBeforeNationalNumber_.toString() + nationalNumber;
606 * Invokes inputDigitHelper on each digit of the national number accrued, and
607 * returns a formatted string in the end.
612 i18n.phonenumbers.AsYouTypeFormatter.prototype.inputAccruedNationalNumber_ =
615 /** @type {string} */
616 var nationalNumber = this.nationalNumber_.toString();
617 /** @type {number} */
618 var lengthOfNationalNumber = nationalNumber.length;
619 if (lengthOfNationalNumber > 0) {
620 /** @type {string} */
621 var tempNationalNumber = '';
622 for (var i = 0; i < lengthOfNationalNumber; i++) {
624 this.inputDigitHelper_(nationalNumber.charAt(i));
626 return this.ableToFormat_ ?
627 this.prefixBeforeNationalNumber_.toString() + tempNationalNumber :
630 return this.prefixBeforeNationalNumber_.toString();
638 i18n.phonenumbers.AsYouTypeFormatter.prototype.
639 removeNationalPrefixFromNationalNumber_ = function() {
641 /** @type {string} */
642 var nationalNumber = this.nationalNumber_.toString();
643 /** @type {number} */
644 var startOfNationalNumber = 0;
645 if (this.currentMetaData_.getCountryCode() == 1 &&
646 nationalNumber.charAt(0) == '1') {
647 startOfNationalNumber = 1;
648 this.prefixBeforeNationalNumber_.append('1 ');
649 this.isInternationalFormatting_ = true;
650 } else if (this.currentMetaData_.hasNationalPrefix()) {
651 /** @type {Array.<string>} */
652 var m = nationalNumber.match(this.nationalPrefixForParsing_);
653 if (m != null && m[0] != null && m[0].length > 0) {
654 // When the national prefix is detected, we use international formatting
655 // rules instead of national ones, because national formatting rules could
656 // contain local formatting rules for numbers entered without area code.
657 this.isInternationalFormatting_ = true;
658 startOfNationalNumber = m[0].length;
659 this.prefixBeforeNationalNumber_.append(nationalNumber.substring(0,
660 startOfNationalNumber));
663 this.nationalNumber_.clear();
664 this.nationalNumber_.append(nationalNumber.substring(startOfNationalNumber));
669 * Extracts IDD and plus sign to prefixBeforeNationalNumber when they are
670 * available, and places the remaining input into nationalNumber.
672 * @return {boolean} true when accruedInputWithoutFormatting begins with the
673 * plus sign or valid IDD for defaultCountry.
676 i18n.phonenumbers.AsYouTypeFormatter.prototype.attemptToExtractIdd_ =
679 /** @type {string} */
680 var accruedInputWithoutFormatting =
681 this.accruedInputWithoutFormatting_.toString();
682 /** @type {Array.<string>} */
683 var m = accruedInputWithoutFormatting.match(this.internationalPrefix_);
684 if (m != null && m[0] != null && m[0].length > 0) {
685 this.isInternationalFormatting_ = true;
686 /** @type {number} */
687 var startOfCountryCode = m[0].length;
688 this.nationalNumber_.clear();
689 this.nationalNumber_.append(
690 accruedInputWithoutFormatting.substring(startOfCountryCode));
691 this.prefixBeforeNationalNumber_.append(
692 accruedInputWithoutFormatting.substring(0, startOfCountryCode));
693 if (accruedInputWithoutFormatting.charAt(0) !=
694 i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN) {
695 this.prefixBeforeNationalNumber_.append(' ');
704 * Extracts country code from the beginning of nationalNumber to
705 * prefixBeforeNationalNumber when they are available, and places the remaining
706 * input into nationalNumber.
708 * @return {boolean} true when a valid country code can be found.
711 i18n.phonenumbers.AsYouTypeFormatter.prototype.attemptToExtractCountryCode_ =
714 if (this.nationalNumber_.getLength() == 0) {
717 /** @type {!goog.string.StringBuffer} */
718 var numberWithoutCountryCode = new goog.string.StringBuffer();
719 /** @type {number} */
720 var countryCode = this.phoneUtil_.extractCountryCode(
721 this.nationalNumber_, numberWithoutCountryCode);
722 if (countryCode == 0) {
725 this.nationalNumber_.clear();
726 this.nationalNumber_.append(numberWithoutCountryCode.toString());
727 /** @type {string} */
729 this.phoneUtil_.getRegionCodeForCountryCode(countryCode);
730 if (newRegionCode != this.defaultCountry_) {
731 this.initializeCountrySpecificInfo_(newRegionCode);
733 /** @type {string} */
734 var countryCodeString = '' + countryCode;
735 this.prefixBeforeNationalNumber_.append(countryCodeString).append(' ');
742 * Accrues digits and the plus sign to accruedInputWithoutFormatting for later
743 * use. If nextChar contains a digit in non-ASCII format (e.g. the full-width
744 * version of digits), it is first normalized to the ASCII version. The return
745 * value is nextChar itself, or its normalized version, if nextChar is a digit
746 * in non-ASCII format.
748 * @param {string} nextChar
749 * @param {boolean} rememberPosition
753 i18n.phonenumbers.AsYouTypeFormatter.prototype.
754 normalizeAndAccrueDigitsAndPlusSign_ = function(nextChar,
757 if (nextChar == i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN) {
758 this.accruedInputWithoutFormatting_.append(nextChar);
760 if (nextChar in i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS) {
761 nextChar = i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS[nextChar];
762 this.accruedInputWithoutFormatting_.append(nextChar);
763 this.nationalNumber_.append(nextChar);
765 if (rememberPosition) {
766 this.positionToRemember_ = this.accruedInputWithoutFormatting_.getLength();
773 * @param {string} nextChar
777 i18n.phonenumbers.AsYouTypeFormatter.prototype.inputDigitHelper_ =
780 /** @type {string} */
781 var formattingTemplate = this.formattingTemplate_.toString();
782 if (formattingTemplate.substring(this.lastMatchPosition_)
783 .search(this.digitPattern_) >= 0) {
784 /** @type {number} */
785 var digitPatternStart = formattingTemplate.search(this.digitPattern_);
786 /** @type {string} */
787 var tempTemplate = formattingTemplate.replace(this.digitPattern_, nextChar);
788 this.formattingTemplate_.clear();
789 this.formattingTemplate_.append(tempTemplate);
790 this.lastMatchPosition_ = digitPatternStart;
791 return tempTemplate.substring(0, this.lastMatchPosition_ + 1);
793 if (this.possibleFormats_.length == 1) {
794 // More digits are entered than we could handle, and there are no other
795 // valid patterns to try.
796 this.ableToFormat_ = false;
797 } // else, we just reset the formatting pattern.
798 this.currentFormattingPattern_ = '';
799 return this.accruedInput_.toString();