/ * *
* @ license AngularJS v1 . 5.7
* ( c ) 2010 - 2016 Google , Inc . http : //angularjs.org
* License : MIT
* /
( function ( window , angular ) { 'use strict' ;
// NOTE: ADVANCED_OPTIMIZATIONS mode.
//
// This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using
// constructs incompatible with that mode.
var $interpolateMinErr = window [ 'angular' ] [ '$interpolateMinErr' ] ;
var noop = window [ 'angular' ] [ 'noop' ] ,
isFunction = window [ 'angular' ] [ 'isFunction' ] ,
toJson = window [ 'angular' ] [ 'toJson' ] ;
function stringify ( value ) {
if ( value == null /* null/undefined */ ) { return '' ; }
switch ( typeof value ) {
case 'string' : return value ;
case 'number' : return '' + value ;
default : return toJson ( value ) ;
}
}
// Convert an index into the string into line/column for use in error messages
// As such, this doesn't have to be efficient.
function indexToLineAndColumn ( text , index ) {
var lines = text . split ( /\n/g ) ;
for ( var i = 0 ; i < lines . length ; i ++ ) {
var line = lines [ i ] ;
if ( index >= line . length ) {
index -= line . length ;
} else {
return { line : i + 1 , column : index + 1 } ;
}
}
}
var PARSE _CACHE _FOR _TEXT _LITERALS = Object . create ( null ) ;
function parseTextLiteral ( text ) {
var cachedFn = PARSE _CACHE _FOR _TEXT _LITERALS [ text ] ;
if ( cachedFn != null ) {
return cachedFn ;
}
function parsedFn ( context ) { return text ; }
parsedFn [ '$$watchDelegate' ] = function watchDelegate ( scope , listener , objectEquality ) {
var unwatch = scope [ '$watch' ] ( noop ,
function textLiteralWatcher ( ) {
if ( isFunction ( listener ) ) { listener . call ( null , text , text , scope ) ; }
unwatch ( ) ;
} ,
objectEquality ) ;
return unwatch ;
} ;
PARSE _CACHE _FOR _TEXT _LITERALS [ text ] = parsedFn ;
parsedFn [ 'exp' ] = text ; // Needed to pretend to be $interpolate for tests copied from interpolateSpec.js
parsedFn [ 'expressions' ] = [ ] ; // Require this to call $compile.$$addBindingInfo() which allows Protractor to find elements by binding.
return parsedFn ;
}
function subtractOffset ( expressionFn , offset ) {
if ( offset === 0 ) {
return expressionFn ;
}
function minusOffset ( value ) {
return ( value == void 0 ) ? value : value - offset ;
}
function parsedFn ( context ) { return minusOffset ( expressionFn ( context ) ) ; }
var unwatch ;
parsedFn [ '$$watchDelegate' ] = function watchDelegate ( scope , listener , objectEquality ) {
unwatch = scope [ '$watch' ] ( expressionFn ,
function pluralExpressionWatchListener ( newValue , oldValue ) {
if ( isFunction ( listener ) ) { listener . call ( null , minusOffset ( newValue ) , minusOffset ( oldValue ) , scope ) ; }
} ,
objectEquality ) ;
return unwatch ;
} ;
return parsedFn ;
}
// NOTE: ADVANCED_OPTIMIZATIONS mode.
//
// This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using
// constructs incompatible with that mode.
/* global $interpolateMinErr: false */
/* global isFunction: false */
/* global noop: false */
/ * *
* @ constructor
* @ private
* /
function MessageSelectorBase ( expressionFn , choices ) {
var self = this ;
this . expressionFn = expressionFn ;
this . choices = choices ;
if ( choices [ "other" ] === void 0 ) {
throw $interpolateMinErr ( 'reqother' , '“other” is a required option.' ) ;
}
this . parsedFn = function ( context ) { return self . getResult ( context ) ; } ;
this . parsedFn [ '$$watchDelegate' ] = function $$watchDelegate ( scope , listener , objectEquality ) {
return self . watchDelegate ( scope , listener , objectEquality ) ;
} ;
this . parsedFn [ 'exp' ] = expressionFn [ 'exp' ] ;
this . parsedFn [ 'expressions' ] = expressionFn [ 'expressions' ] ;
}
MessageSelectorBase . prototype . getMessageFn = function getMessageFn ( value ) {
return this . choices [ this . categorizeValue ( value ) ] ;
} ;
MessageSelectorBase . prototype . getResult = function getResult ( context ) {
return this . getMessageFn ( this . expressionFn ( context ) ) ( context ) ;
} ;
MessageSelectorBase . prototype . watchDelegate = function watchDelegate ( scope , listener , objectEquality ) {
var watchers = new MessageSelectorWatchers ( this , scope , listener , objectEquality ) ;
return function ( ) { watchers . cancelWatch ( ) ; } ;
} ;
/ * *
* @ constructor
* @ private
* /
function MessageSelectorWatchers ( msgSelector , scope , listener , objectEquality ) {
var self = this ;
this . scope = scope ;
this . msgSelector = msgSelector ;
this . listener = listener ;
this . objectEquality = objectEquality ;
this . lastMessage = void 0 ;
this . messageFnWatcher = noop ;
var expressionFnListener = function ( newValue , oldValue ) { return self . expressionFnListener ( newValue , oldValue ) ; } ;
this . expressionFnWatcher = scope [ '$watch' ] ( msgSelector . expressionFn , expressionFnListener , objectEquality ) ;
}
MessageSelectorWatchers . prototype . expressionFnListener = function expressionFnListener ( newValue , oldValue ) {
var self = this ;
this . messageFnWatcher ( ) ;
var messageFnListener = function ( newMessage , oldMessage ) { return self . messageFnListener ( newMessage , oldMessage ) ; } ;
var messageFn = this . msgSelector . getMessageFn ( newValue ) ;
this . messageFnWatcher = this . scope [ '$watch' ] ( messageFn , messageFnListener , this . objectEquality ) ;
} ;
MessageSelectorWatchers . prototype . messageFnListener = function messageFnListener ( newMessage , oldMessage ) {
if ( isFunction ( this . listener ) ) {
this . listener . call ( null , newMessage , newMessage === oldMessage ? newMessage : this . lastMessage , this . scope ) ;
}
this . lastMessage = newMessage ;
} ;
MessageSelectorWatchers . prototype . cancelWatch = function cancelWatch ( ) {
this . expressionFnWatcher ( ) ;
this . messageFnWatcher ( ) ;
} ;
/ * *
* @ constructor
* @ extends MessageSelectorBase
* @ private
* /
function SelectMessage ( expressionFn , choices ) {
MessageSelectorBase . call ( this , expressionFn , choices ) ;
}
function SelectMessageProto ( ) { }
SelectMessageProto . prototype = MessageSelectorBase . prototype ;
SelectMessage . prototype = new SelectMessageProto ( ) ;
SelectMessage . prototype . categorizeValue = function categorizeSelectValue ( value ) {
return ( this . choices [ value ] !== void 0 ) ? value : "other" ;
} ;
/ * *
* @ constructor
* @ extends MessageSelectorBase
* @ private
* /
function PluralMessage ( expressionFn , choices , offset , pluralCat ) {
MessageSelectorBase . call ( this , expressionFn , choices ) ;
this . offset = offset ;
this . pluralCat = pluralCat ;
}
function PluralMessageProto ( ) { }
PluralMessageProto . prototype = MessageSelectorBase . prototype ;
PluralMessage . prototype = new PluralMessageProto ( ) ;
PluralMessage . prototype . categorizeValue = function categorizePluralValue ( value ) {
if ( isNaN ( value ) ) {
return "other" ;
} else if ( this . choices [ value ] !== void 0 ) {
return value ;
} else {
var category = this . pluralCat ( value - this . offset ) ;
return ( this . choices [ category ] !== void 0 ) ? category : "other" ;
}
} ;
// NOTE: ADVANCED_OPTIMIZATIONS mode.
//
// This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using
// constructs incompatible with that mode.
/* global $interpolateMinErr: false */
/* global isFunction: false */
/* global parseTextLiteral: false */
/ * *
* @ constructor
* @ private
* /
function InterpolationParts ( trustedContext , allOrNothing ) {
this . trustedContext = trustedContext ;
this . allOrNothing = allOrNothing ;
this . textParts = [ ] ;
this . expressionFns = [ ] ;
this . expressionIndices = [ ] ;
this . partialText = '' ;
this . concatParts = null ;
}
InterpolationParts . prototype . flushPartialText = function flushPartialText ( ) {
if ( this . partialText ) {
if ( this . concatParts == null ) {
this . textParts . push ( this . partialText ) ;
} else {
this . textParts . push ( this . concatParts . join ( '' ) ) ;
this . concatParts = null ;
}
this . partialText = '' ;
}
} ;
InterpolationParts . prototype . addText = function addText ( text ) {
if ( text . length ) {
if ( ! this . partialText ) {
this . partialText = text ;
} else if ( this . concatParts ) {
this . concatParts . push ( text ) ;
} else {
this . concatParts = [ this . partialText , text ] ;
}
}
} ;
InterpolationParts . prototype . addExpressionFn = function addExpressionFn ( expressionFn ) {
this . flushPartialText ( ) ;
this . expressionIndices . push ( this . textParts . length ) ;
this . expressionFns . push ( expressionFn ) ;
this . textParts . push ( '' ) ;
} ;
InterpolationParts . prototype . getExpressionValues = function getExpressionValues ( context ) {
var expressionValues = new Array ( this . expressionFns . length ) ;
for ( var i = 0 ; i < this . expressionFns . length ; i ++ ) {
expressionValues [ i ] = this . expressionFns [ i ] ( context ) ;
}
return expressionValues ;
} ;
InterpolationParts . prototype . getResult = function getResult ( expressionValues ) {
for ( var i = 0 ; i < this . expressionIndices . length ; i ++ ) {
var expressionValue = expressionValues [ i ] ;
if ( this . allOrNothing && expressionValue === void 0 ) return ;
this . textParts [ this . expressionIndices [ i ] ] = expressionValue ;
}
return this . textParts . join ( '' ) ;
} ;
InterpolationParts . prototype . toParsedFn = function toParsedFn ( mustHaveExpression , originalText ) {
var self = this ;
this . flushPartialText ( ) ;
if ( mustHaveExpression && this . expressionFns . length === 0 ) {
return void 0 ;
}
if ( this . textParts . length === 0 ) {
return parseTextLiteral ( '' ) ;
}
if ( this . trustedContext && this . textParts . length > 1 ) {
$interpolateMinErr [ 'throwNoconcat' ] ( originalText ) ;
}
if ( this . expressionFns . length === 0 ) {
if ( this . textParts . length != 1 ) { this . errorInParseLogic ( ) ; }
return parseTextLiteral ( this . textParts [ 0 ] ) ;
}
var parsedFn = function ( context ) {
return self . getResult ( self . getExpressionValues ( context ) ) ;
} ;
parsedFn [ '$$watchDelegate' ] = function $$watchDelegate ( scope , listener , objectEquality ) {
return self . watchDelegate ( scope , listener , objectEquality ) ;
} ;
parsedFn [ 'exp' ] = originalText ; // Needed to pretend to be $interpolate for tests copied from interpolateSpec.js
parsedFn [ 'expressions' ] = new Array ( this . expressionFns . length ) ; // Require this to call $compile.$$addBindingInfo() which allows Protractor to find elements by binding.
for ( var i = 0 ; i < this . expressionFns . length ; i ++ ) {
parsedFn [ 'expressions' ] [ i ] = this . expressionFns [ i ] [ 'exp' ] ;
}
return parsedFn ;
} ;
InterpolationParts . prototype . watchDelegate = function watchDelegate ( scope , listener , objectEquality ) {
var watcher = new InterpolationPartsWatcher ( this , scope , listener , objectEquality ) ;
return function ( ) { watcher . cancelWatch ( ) ; } ;
} ;
function InterpolationPartsWatcher ( interpolationParts , scope , listener , objectEquality ) {
this . interpolationParts = interpolationParts ;
this . scope = scope ;
this . previousResult = ( void 0 ) ;
this . listener = listener ;
var self = this ;
this . expressionFnsWatcher = scope [ '$watchGroup' ] ( interpolationParts . expressionFns , function ( newExpressionValues , oldExpressionValues ) {
self . watchListener ( newExpressionValues , oldExpressionValues ) ;
} ) ;
}
InterpolationPartsWatcher . prototype . watchListener = function watchListener ( newExpressionValues , oldExpressionValues ) {
var result = this . interpolationParts . getResult ( newExpressionValues ) ;
if ( isFunction ( this . listener ) ) {
this . listener . call ( null , result , newExpressionValues === oldExpressionValues ? result : this . previousResult , this . scope ) ;
}
this . previousResult = result ;
} ;
InterpolationPartsWatcher . prototype . cancelWatch = function cancelWatch ( ) {
this . expressionFnsWatcher ( ) ;
} ;
// NOTE: ADVANCED_OPTIMIZATIONS mode.
//
// This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using
// constructs incompatible with that mode.
/* global $interpolateMinErr: false */
/* global indexToLineAndColumn: false */
/* global InterpolationParts: false */
/* global PluralMessage: false */
/* global SelectMessage: false */
/* global subtractOffset: false */
// The params src and dst are exactly one of two types: NestedParserState or MessageFormatParser.
// This function is fully optimized by V8. (inspect via IRHydra or --trace-deopt.)
// The idea behind writing it this way is to avoid repeating oneself. This is the ONE place where
// the parser state that is saved/restored when parsing nested mustaches is specified.
function copyNestedParserState ( src , dst ) {
dst . expressionFn = src . expressionFn ;
dst . expressionMinusOffsetFn = src . expressionMinusOffsetFn ;
dst . pluralOffset = src . pluralOffset ;
dst . choices = src . choices ;
dst . choiceKey = src . choiceKey ;
dst . interpolationParts = src . interpolationParts ;
dst . ruleChoiceKeyword = src . ruleChoiceKeyword ;
dst . msgStartIndex = src . msgStartIndex ;
dst . expressionStartIndex = src . expressionStartIndex ;
}
function NestedParserState ( parser ) {
copyNestedParserState ( parser , this ) ;
}
/ * *
* @ constructor
* @ private
* /
function MessageFormatParser ( text , startIndex , $parse , pluralCat , stringifier ,
mustHaveExpression , trustedContext , allOrNothing ) {
this . text = text ;
this . index = startIndex || 0 ;
this . $parse = $parse ;
this . pluralCat = pluralCat ;
this . stringifier = stringifier ;
this . mustHaveExpression = ! ! mustHaveExpression ;
this . trustedContext = trustedContext ;
this . allOrNothing = ! ! allOrNothing ;
this . expressionFn = null ;
this . expressionMinusOffsetFn = null ;
this . pluralOffset = null ;
this . choices = null ;
this . choiceKey = null ;
this . interpolationParts = null ;
this . msgStartIndex = null ;
this . nestedStateStack = [ ] ;
this . parsedFn = null ;
this . rule = null ;
this . ruleStack = null ;
this . ruleChoiceKeyword = null ;
this . interpNestLevel = null ;
this . expressionStartIndex = null ;
this . stringStartIndex = null ;
this . stringQuote = null ;
this . stringInterestsRe = null ;
this . angularOperatorStack = null ;
this . textPart = null ;
}
// preserve v8 optimization.
var EMPTY _STATE = new NestedParserState ( new MessageFormatParser (
/* text= */ '' , /* startIndex= */ 0 , /* $parse= */ null , /* pluralCat= */ null , /* stringifier= */ null ,
/* mustHaveExpression= */ false , /* trustedContext= */ null , /* allOrNothing */ false ) ) ;
MessageFormatParser . prototype . pushState = function pushState ( ) {
this . nestedStateStack . push ( new NestedParserState ( this ) ) ;
copyNestedParserState ( EMPTY _STATE , this ) ;
} ;
MessageFormatParser . prototype . popState = function popState ( ) {
if ( this . nestedStateStack . length === 0 ) {
this . errorInParseLogic ( ) ;
}
var previousState = this . nestedStateStack . pop ( ) ;
copyNestedParserState ( previousState , this ) ;
} ;
// Oh my JavaScript! Who knew you couldn't match a regex at a specific
// location in a string but will always search forward?!
// Apparently you'll be growing this ability via the sticky flag (y) in
// ES6. I'll just to work around you for now.
MessageFormatParser . prototype . matchRe = function matchRe ( re , search ) {
re . lastIndex = this . index ;
var match = re . exec ( this . text ) ;
if ( match != null && ( search === true || ( match . index == this . index ) ) ) {
this . index = re . lastIndex ;
return match ;
}
return null ;
} ;
MessageFormatParser . prototype . searchRe = function searchRe ( re ) {
return this . matchRe ( re , true ) ;
} ;
MessageFormatParser . prototype . consumeRe = function consumeRe ( re ) {
// Without the sticky flag, we can't use the .test() method to consume a
// match at the current index. Instead, we'll use the slower .exec() method
// and verify match.index.
return ! ! this . matchRe ( re ) ;
} ;
// Run through our grammar avoiding deeply nested function call chains.
MessageFormatParser . prototype . run = function run ( initialRule ) {
this . ruleStack = [ initialRule ] ;
do {
this . rule = this . ruleStack . pop ( ) ;
while ( this . rule ) {
this . rule ( ) ;
}
this . assertRuleOrNull ( this . rule ) ;
} while ( this . ruleStack . length > 0 ) ;
} ;
MessageFormatParser . prototype . errorInParseLogic = function errorInParseLogic ( ) {
throw $interpolateMinErr ( 'logicbug' ,
'The messageformat parser has encountered an internal error. Please file a github issue against the AngularJS project and provide this message text that triggers the bug. Text: “{0}”' ,
this . text ) ;
} ;
MessageFormatParser . prototype . assertRuleOrNull = function assertRuleOrNull ( rule ) {
if ( rule === void 0 ) {
this . errorInParseLogic ( ) ;
}
} ;
var NEXT _WORD _RE = /\s*(\w+)\s*/g ;
MessageFormatParser . prototype . errorExpecting = function errorExpecting ( ) {
// What was wrong with the syntax? Unsupported type, missing comma, or something else?
var match = this . matchRe ( NEXT _WORD _RE ) , position ;
if ( match == null ) {
position = indexToLineAndColumn ( this . text , this . index ) ;
throw $interpolateMinErr ( 'reqarg' ,
'Expected one of “plural” or “select” at line {0}, column {1} of text “{2}”' ,
position . line , position . column , this . text ) ;
}
var word = match [ 1 ] ;
if ( word == "select" || word == "plural" ) {
position = indexToLineAndColumn ( this . text , this . index ) ;
throw $interpolateMinErr ( 'reqcomma' ,
'Expected a comma after the keyword “{0}” at line {1}, column {2} of text “{3}”' ,
word , position . line , position . column , this . text ) ;
} else {
position = indexToLineAndColumn ( this . text , this . index ) ;
throw $interpolateMinErr ( 'unknarg' ,
'Unsupported keyword “{0}” at line {0}, column {1}. Only “plural” and “select” are currently supported. Text: “{3}”' ,
word , position . line , position . column , this . text ) ;
}
} ;
var STRING _START _RE = /['"]/g ;
MessageFormatParser . prototype . ruleString = function ruleString ( ) {
var match = this . matchRe ( STRING _START _RE ) ;
if ( match == null ) {
var position = indexToLineAndColumn ( this . text , this . index ) ;
throw $interpolateMinErr ( 'wantstring' ,
'Expected the beginning of a string at line {0}, column {1} in text “{2}”' ,
position . line , position . column , this . text ) ;
}
this . startStringAtMatch ( match ) ;
} ;
MessageFormatParser . prototype . startStringAtMatch = function startStringAtMatch ( match ) {
this . stringStartIndex = match . index ;
this . stringQuote = match [ 0 ] ;
this . stringInterestsRe = this . stringQuote == "'" ? SQUOTED _STRING _INTEREST _RE : DQUOTED _STRING _INTEREST _RE ;
this . rule = this . ruleInsideString ;
} ;
var SQUOTED _STRING _INTEREST _RE = /\\(?:\\|'|u[0-9A-Fa-f]{4}|x[0-9A-Fa-f]{2}|[0-7]{3}|\r\n|\n|[\s\S])|'/g ;
var DQUOTED _STRING _INTEREST _RE = /\\(?:\\|"|u[0-9A-Fa-f]{4}|x[0-9A-Fa-f]{2}|[0-7]{3}|\r\n|\n|[\s\S])|"/g ;
MessageFormatParser . prototype . ruleInsideString = function ruleInsideString ( ) {
var match = this . searchRe ( this . stringInterestsRe ) ;
if ( match == null ) {
var position = indexToLineAndColumn ( this . text , this . stringStartIndex ) ;
throw $interpolateMinErr ( 'untermstr' ,
'The string beginning at line {0}, column {1} is unterminated in text “{2}”' ,
position . line , position . column , this . text ) ;
}
var chars = match [ 0 ] ;
if ( match == this . stringQuote ) {
this . rule = null ;
}
} ;
var PLURAL _OR _SELECT _ARG _TYPE _RE = /\s*(plural|select)\s*,\s*/g ;
MessageFormatParser . prototype . rulePluralOrSelect = function rulePluralOrSelect ( ) {
var match = this . searchRe ( PLURAL _OR _SELECT _ARG _TYPE _RE ) ;
if ( match == null ) {
this . errorExpecting ( ) ;
}
var argType = match [ 1 ] ;
switch ( argType ) {
case "plural" : this . rule = this . rulePluralStyle ; break ;
case "select" : this . rule = this . ruleSelectStyle ; break ;
default : this . errorInParseLogic ( ) ;
}
} ;
MessageFormatParser . prototype . rulePluralStyle = function rulePluralStyle ( ) {
this . choices = Object . create ( null ) ;
this . ruleChoiceKeyword = this . rulePluralValueOrKeyword ;
this . rule = this . rulePluralOffset ;
} ;
MessageFormatParser . prototype . ruleSelectStyle = function ruleSelectStyle ( ) {
this . choices = Object . create ( null ) ;
this . ruleChoiceKeyword = this . ruleSelectKeyword ;
this . rule = this . ruleSelectKeyword ;
} ;
var NUMBER _RE = /[0]|(?:[1-9][0-9]*)/g ;
var PLURAL _OFFSET _RE = new RegExp ( "\\s*offset\\s*:\\s*(" + NUMBER _RE . source + ")" , "g" ) ;
MessageFormatParser . prototype . rulePluralOffset = function rulePluralOffset ( ) {
var match = this . matchRe ( PLURAL _OFFSET _RE ) ;
this . pluralOffset = ( match == null ) ? 0 : parseInt ( match [ 1 ] , 10 ) ;
this . expressionMinusOffsetFn = subtractOffset ( this . expressionFn , this . pluralOffset ) ;
this . rule = this . rulePluralValueOrKeyword ;
} ;
MessageFormatParser . prototype . assertChoiceKeyIsNew = function assertChoiceKeyIsNew ( choiceKey , index ) {
if ( this . choices [ choiceKey ] !== void 0 ) {
var position = indexToLineAndColumn ( this . text , index ) ;
throw $interpolateMinErr ( 'dupvalue' ,
'The choice “{0}” is specified more than once. Duplicate key is at line {1}, column {2} in text “{3}”' ,
choiceKey , position . line , position . column , this . text ) ;
}
} ;
var SELECT _KEYWORD = /\s*(\w+)/g ;
MessageFormatParser . prototype . ruleSelectKeyword = function ruleSelectKeyword ( ) {
var match = this . matchRe ( SELECT _KEYWORD ) ;
if ( match == null ) {
this . parsedFn = new SelectMessage ( this . expressionFn , this . choices ) . parsedFn ;
this . rule = null ;
return ;
}
this . choiceKey = match [ 1 ] ;
this . assertChoiceKeyIsNew ( this . choiceKey , match . index ) ;
this . rule = this . ruleMessageText ;
} ;
var EXPLICIT _VALUE _OR _KEYWORD _RE = new RegExp ( "\\s*(?:(?:=(" + NUMBER _RE . source + "))|(\\w+))" , "g" ) ;
MessageFormatParser . prototype . rulePluralValueOrKeyword = function rulePluralValueOrKeyword ( ) {
var match = this . matchRe ( EXPLICIT _VALUE _OR _KEYWORD _RE ) ;
if ( match == null ) {
this . parsedFn = new PluralMessage ( this . expressionFn , this . choices , this . pluralOffset , this . pluralCat ) . parsedFn ;
this . rule = null ;
return ;
}
if ( match [ 1 ] != null ) {
this . choiceKey = parseInt ( match [ 1 ] , 10 ) ;
} else {
this . choiceKey = match [ 2 ] ;
}
this . assertChoiceKeyIsNew ( this . choiceKey , match . index ) ;
this . rule = this . ruleMessageText ;
} ;
var BRACE _OPEN _RE = /\s*{/g ;
var BRACE _CLOSE _RE = /}/g ;
MessageFormatParser . prototype . ruleMessageText = function ruleMessageText ( ) {
if ( ! this . consumeRe ( BRACE _OPEN _RE ) ) {
var position = indexToLineAndColumn ( this . text , this . index ) ;
throw $interpolateMinErr ( 'reqopenbrace' ,
'The plural choice “{0}” must be followed by a message in braces at line {1}, column {2} in text “{3}”' ,
this . choiceKey , position . line , position . column , this . text ) ;
}
this . msgStartIndex = this . index ;
this . interpolationParts = new InterpolationParts ( this . trustedContext , this . allOrNothing ) ;
this . rule = this . ruleInInterpolationOrMessageText ;
} ;
// Note: Since "\" is used as an escape character, don't allow it to be part of the
// startSymbol/endSymbol when I add the feature to allow them to be redefined.
var INTERP _OR _END _MESSAGE _RE = /\\.|{{|}/g ;
var INTERP _OR _PLURALVALUE _OR _END _MESSAGE _RE = /\\.|{{|#|}/g ;
var ESCAPE _OR _MUSTACHE _BEGIN _RE = /\\.|{{/g ;
MessageFormatParser . prototype . advanceInInterpolationOrMessageText = function advanceInInterpolationOrMessageText ( ) {
var currentIndex = this . index , match , re ;
if ( this . ruleChoiceKeyword == null ) { // interpolation
match = this . searchRe ( ESCAPE _OR _MUSTACHE _BEGIN _RE ) ;
if ( match == null ) { // End of interpolation text. Nothing more to process.
this . textPart = this . text . substring ( currentIndex ) ;
this . index = this . text . length ;
return null ;
}
} else {
match = this . searchRe ( this . ruleChoiceKeyword == this . rulePluralValueOrKeyword ?
INTERP _OR _PLURALVALUE _OR _END _MESSAGE _RE : INTERP _OR _END _MESSAGE _RE ) ;
if ( match == null ) {
var position = indexToLineAndColumn ( this . text , this . msgStartIndex ) ;
throw $interpolateMinErr ( 'reqendbrace' ,
'The plural/select choice “{0}” message starting at line {1}, column {2} does not have an ending closing brace. Text “{3}”' ,
this . choiceKey , position . line , position . column , this . text ) ;
}
}
// match is non-null.
var token = match [ 0 ] ;
this . textPart = this . text . substring ( currentIndex , match . index ) ;
return token ;
} ;
MessageFormatParser . prototype . ruleInInterpolationOrMessageText = function ruleInInterpolationOrMessageText ( ) {
var currentIndex = this . index ;
var token = this . advanceInInterpolationOrMessageText ( ) ;
if ( token == null ) {
// End of interpolation text. Nothing more to process.
this . index = this . text . length ;
this . interpolationParts . addText ( this . text . substring ( currentIndex ) ) ;
this . rule = null ;
return ;
}
if ( token [ 0 ] == "\\" ) {
// unescape next character and continue
this . interpolationParts . addText ( this . textPart + token [ 1 ] ) ;
return ;
}
this . interpolationParts . addText ( this . textPart ) ;
if ( token == "{{" ) {
this . pushState ( ) ;
this . ruleStack . push ( this . ruleEndMustacheInInterpolationOrMessage ) ;
this . rule = this . ruleEnteredMustache ;
} else if ( token == "}" ) {
this . choices [ this . choiceKey ] = this . interpolationParts . toParsedFn ( /*mustHaveExpression=*/ false , this . text ) ;
this . rule = this . ruleChoiceKeyword ;
} else if ( token == "#" ) {
this . interpolationParts . addExpressionFn ( this . expressionMinusOffsetFn ) ;
} else {
this . errorInParseLogic ( ) ;
}
} ;
MessageFormatParser . prototype . ruleInterpolate = function ruleInterpolate ( ) {
this . interpolationParts = new InterpolationParts ( this . trustedContext , this . allOrNothing ) ;
this . rule = this . ruleInInterpolation ;
} ;
MessageFormatParser . prototype . ruleInInterpolation = function ruleInInterpolation ( ) {
var currentIndex = this . index ;
var match = this . searchRe ( ESCAPE _OR _MUSTACHE _BEGIN _RE ) ;
if ( match == null ) {
// End of interpolation text. Nothing more to process.
this . index = this . text . length ;
this . interpolationParts . addText ( this . text . substring ( currentIndex ) ) ;
this . parsedFn = this . interpolationParts . toParsedFn ( this . mustHaveExpression , this . text ) ;
this . rule = null ;
return ;
}
var token = match [ 0 ] ;
if ( token [ 0 ] == "\\" ) {
// unescape next character and continue
this . interpolationParts . addText ( this . text . substring ( currentIndex , match . index ) + token [ 1 ] ) ;
return ;
}
this . interpolationParts . addText ( this . text . substring ( currentIndex , match . index ) ) ;
this . pushState ( ) ;
this . ruleStack . push ( this . ruleInterpolationEndMustache ) ;
this . rule = this . ruleEnteredMustache ;
} ;
MessageFormatParser . prototype . ruleInterpolationEndMustache = function ruleInterpolationEndMustache ( ) {
var expressionFn = this . parsedFn ;
this . popState ( ) ;
this . interpolationParts . addExpressionFn ( expressionFn ) ;
this . rule = this . ruleInInterpolation ;
} ;
MessageFormatParser . prototype . ruleEnteredMustache = function ruleEnteredMustache ( ) {
this . parsedFn = null ;
this . ruleStack . push ( this . ruleEndMustache ) ;
this . rule = this . ruleAngularExpression ;
} ;
MessageFormatParser . prototype . ruleEndMustacheInInterpolationOrMessage = function ruleEndMustacheInInterpolationOrMessage ( ) {
var expressionFn = this . parsedFn ;
this . popState ( ) ;
this . interpolationParts . addExpressionFn ( expressionFn ) ;
this . rule = this . ruleInInterpolationOrMessageText ;
} ;
var INTERP _END _RE = /\s*}}/g ;
MessageFormatParser . prototype . ruleEndMustache = function ruleEndMustache ( ) {
var match = this . matchRe ( INTERP _END _RE ) ;
if ( match == null ) {
var position = indexToLineAndColumn ( this . text , this . index ) ;
throw $interpolateMinErr ( 'reqendinterp' ,
'Expecting end of interpolation symbol, “{0}”, at line {1}, column {2} in text “{3}”' ,
'}}' , position . line , position . column , this . text ) ;
}
if ( this . parsedFn == null ) {
// If we parsed a MessageFormat extension, (e.g. select/plural today, maybe more some other
// day), then the result *has* to be a string and those rules would have already set
// this.parsedFn. If there was no MessageFormat extension, then there is no requirement to
// stringify the result and parsedFn isn't set. We set it here. While we could have set it
// unconditionally when exiting the Angular expression, I intend for us to not just replace
// $interpolate, but also to replace $parse in a future version (so ng-bind can work), and in
// such a case we do not want to unnecessarily stringify something if it's not going to be used
// in a string context.
this . parsedFn = this . $parse ( this . expressionFn , this . stringifier ) ;
this . parsedFn [ 'exp' ] = this . expressionFn [ 'exp' ] ; // Needed to pretend to be $interpolate for tests copied from interpolateSpec.js
this . parsedFn [ 'expressions' ] = this . expressionFn [ 'expressions' ] ; // Require this to call $compile.$$addBindingInfo() which allows Protractor to find elements by binding.
}
this . rule = null ;
} ;
MessageFormatParser . prototype . ruleAngularExpression = function ruleAngularExpression ( ) {
this . angularOperatorStack = [ ] ;
this . expressionStartIndex = this . index ;
this . rule = this . ruleInAngularExpression ;
} ;
function getEndOperator ( opBegin ) {
switch ( opBegin ) {
case "{" : return "}" ;
case "[" : return "]" ;
case "(" : return ")" ;
default : return null ;
}
}
function getBeginOperator ( opEnd ) {
switch ( opEnd ) {
case "}" : return "{" ;
case "]" : return "[" ;
case ")" : return "(" ;
default : return null ;
}
}
// TODO(chirayu): The interpolation endSymbol must also be accounted for. It
// just so happens that "}" is an operator so it's in the list below. But we
// should support any other type of start/end interpolation symbol.
var INTERESTING _OPERATORS _RE = /[[\]{}()'",]/g ;
MessageFormatParser . prototype . ruleInAngularExpression = function ruleInAngularExpression ( ) {
var startIndex = this . index ;
var match = this . searchRe ( INTERESTING _OPERATORS _RE ) ;
var position ;
if ( match == null ) {
if ( this . angularOperatorStack . length === 0 ) {
// This is the end of the Angular expression so this is actually a
// success. Note that when inside an interpolation, this means we even
// consumed the closing interpolation symbols if they were curlies. This
// is NOT an error at this point but will become an error further up the
// stack when the part that saw the opening curlies is unable to find the
// closing ones.
this . index = this . text . length ;
this . expressionFn = this . $parse ( this . text . substring ( this . expressionStartIndex , this . index ) ) ;
// Needed to pretend to be $interpolate for tests copied from interpolateSpec.js
this . expressionFn [ 'exp' ] = this . text . substring ( this . expressionStartIndex , this . index ) ;
this . expressionFn [ 'expressions' ] = this . expressionFn [ 'expressions' ] ;
this . rule = null ;
return ;
}
var innermostOperator = this . angularOperatorStack [ 0 ] ;
throw $interpolateMinErr ( 'badexpr' ,
'Unexpected end of Angular expression. Expecting operator “{0}” at the end of the text “{1}”' ,
this . getEndOperator ( innermostOperator ) , this . text ) ;
}
var operator = match [ 0 ] ;
if ( operator == "'" || operator == '"' ) {
this . ruleStack . push ( this . ruleInAngularExpression ) ;
this . startStringAtMatch ( match ) ;
return ;
}
if ( operator == "," ) {
if ( this . trustedContext ) {
position = indexToLineAndColumn ( this . text , this . index ) ;
throw $interpolateMinErr ( 'unsafe' ,
'Use of select/plural MessageFormat syntax is currently disallowed in a secure context ({0}). At line {1}, column {2} of text “{3}”' ,
this . trustedContext , position . line , position . column , this . text ) ;
}
// only the top level comma has relevance.
if ( this . angularOperatorStack . length === 0 ) {
// todo: does this need to be trimmed?
this . expressionFn = this . $parse ( this . text . substring ( this . expressionStartIndex , match . index ) ) ;
// Needed to pretend to be $interpolate for tests copied from interpolateSpec.js
this . expressionFn [ 'exp' ] = this . text . substring ( this . expressionStartIndex , match . index ) ;
this . expressionFn [ 'expressions' ] = this . expressionFn [ 'expressions' ] ;
this . rule = null ;
this . rule = this . rulePluralOrSelect ;
}
return ;
}
if ( getEndOperator ( operator ) != null ) {
this . angularOperatorStack . unshift ( operator ) ;
return ;
}
var beginOperator = getBeginOperator ( operator ) ;
if ( beginOperator == null ) {
this . errorInParseLogic ( ) ;
}
if ( this . angularOperatorStack . length > 0 ) {
if ( beginOperator == this . angularOperatorStack [ 0 ] ) {
this . angularOperatorStack . shift ( ) ;
return ;
}
position = indexToLineAndColumn ( this . text , this . index ) ;
throw $interpolateMinErr ( 'badexpr' ,
'Unexpected operator “{0}” at line {1}, column {2} in text. Was expecting “{3}”. Text: “{4}”' ,
operator , position . line , position . column , getEndOperator ( this . angularOperatorStack [ 0 ] ) , this . text ) ;
}
// We are trying to pop off the operator stack but there really isn't anything to pop off.
this . index = match . index ;
this . expressionFn = this . $parse ( this . text . substring ( this . expressionStartIndex , this . index ) ) ;
// Needed to pretend to be $interpolate for tests copied from interpolateSpec.js
this . expressionFn [ 'exp' ] = this . text . substring ( this . expressionStartIndex , this . index ) ;
this . expressionFn [ 'expressions' ] = this . expressionFn [ 'expressions' ] ;
this . rule = null ;
} ;
// NOTE: ADVANCED_OPTIMIZATIONS mode.
//
// This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using
// constructs incompatible with that mode.
/* global $interpolateMinErr: false */
/* global MessageFormatParser: false */
/* global stringify: false */
/ * *
* @ ngdoc service
* @ name $$messageFormat
*
* @ description
* Angular internal service to recognize MessageFormat extensions in interpolation expressions .
* For more information , see :
* https : //docs.google.com/a/google.com/document/d/1pbtW2yvtmFBikfRrJd8VAsabiFkKezmYZ_PbgdjQOVU/edit
*
* # # Example
*
* < example name = "ngMessageFormat-example" module = "msgFmtExample" deps = "angular-message-format.min.js" >
* < file name = "index.html" >
* < div ng - controller = "AppController" >
* < button ng - click = "decreaseRecipients()" id = "decreaseRecipients" > decreaseRecipients < / b u t t o n > < b r >
* < span > { { recipients . length , plural , offset : 1
* = 0 { { { sender . name } } gave no gifts ( \ # = # ) }
* = 1 { { { sender . name } } gave one gift to { { recipients [ 0 ] . name } } ( \ # = # ) }
* one { { { sender . name } } gave { { recipients [ 0 ] . name } } and one other person a gift ( \ # = # ) }
* other { { { sender . name } } gave { { recipients [ 0 ] . name } } and # other people a gift ( \ # = # ) }
* } } < / s p a n >
* < / d i v >
* < / f i l e >
*
* < file name = "script.js" >
* function Person ( name , gender ) {
* this . name = name ;
* this . gender = gender ;
* }
*
* var alice = new Person ( "Alice" , "female" ) ,
* bob = new Person ( "Bob" , "male" ) ,
* charlie = new Person ( "Charlie" , "male" ) ,
* harry = new Person ( "Harry Potter" , "male" ) ;
*
* angular . module ( 'msgFmtExample' , [ 'ngMessageFormat' ] )
* . controller ( 'AppController' , [ '$scope' , function ( $scope ) {
* $scope . recipients = [ alice , bob , charlie ] ;
* $scope . sender = harry ;
* $scope . decreaseRecipients = function ( ) {
* -- $scope . recipients . length ;
* } ;
* } ] ) ;
* < / f i l e >
*
* < file name = "protractor.js" type = "protractor" >
* describe ( 'MessageFormat plural' , function ( ) {
* it ( 'should pluralize initial values' , function ( ) {
* var messageElem = element ( by . binding ( 'recipients.length' ) ) , decreaseRecipientsBtn = element ( by . id ( 'decreaseRecipients' ) ) ;
* expect ( messageElem . getText ( ) ) . toEqual ( 'Harry Potter gave Alice and 2 other people a gift (#=2)' ) ;
* decreaseRecipientsBtn . click ( ) ;
* expect ( messageElem . getText ( ) ) . toEqual ( 'Harry Potter gave Alice and one other person a gift (#=1)' ) ;
* decreaseRecipientsBtn . click ( ) ;
* expect ( messageElem . getText ( ) ) . toEqual ( 'Harry Potter gave one gift to Alice (#=0)' ) ;
* decreaseRecipientsBtn . click ( ) ;
* expect ( messageElem . getText ( ) ) . toEqual ( 'Harry Potter gave no gifts (#=-1)' ) ;
* } ) ;
* } ) ;
* < / f i l e >
* < / e x a m p l e >
* /
var $$MessageFormatFactory = [ '$parse' , '$locale' , '$sce' , '$exceptionHandler' , function $$messageFormat (
$parse , $locale , $sce , $exceptionHandler ) {
function getStringifier ( trustedContext , allOrNothing , text ) {
return function stringifier ( value ) {
try {
value = trustedContext ? $sce [ 'getTrusted' ] ( trustedContext , value ) : $sce [ 'valueOf' ] ( value ) ;
return allOrNothing && ( value === void 0 ) ? value : stringify ( value ) ;
} catch ( err ) {
$exceptionHandler ( $interpolateMinErr [ 'interr' ] ( text , err ) ) ;
}
} ;
}
function interpolate ( text , mustHaveExpression , trustedContext , allOrNothing ) {
var stringifier = getStringifier ( trustedContext , allOrNothing , text ) ;
var parser = new MessageFormatParser ( text , 0 , $parse , $locale [ 'pluralCat' ] , stringifier ,
mustHaveExpression , trustedContext , allOrNothing ) ;
parser . run ( parser . ruleInterpolate ) ;
return parser . parsedFn ;
}
return {
'interpolate' : interpolate
} ;
} ] ;
var $$interpolateDecorator = [ '$$messageFormat' , '$delegate' , function $$interpolateDecorator ( $$messageFormat , $interpolate ) {
if ( $interpolate [ 'startSymbol' ] ( ) != "{{" || $interpolate [ 'endSymbol' ] ( ) != "}}" ) {
throw $interpolateMinErr ( 'nochgmustache' , 'angular-message-format.js currently does not allow you to use custom start and end symbols for interpolation.' ) ;
}
var interpolate = $$messageFormat [ 'interpolate' ] ;
interpolate [ 'startSymbol' ] = $interpolate [ 'startSymbol' ] ;
interpolate [ 'endSymbol' ] = $interpolate [ 'endSymbol' ] ;
return interpolate ;
} ] ;
/ * *
* @ ngdoc module
* @ name ngMessageFormat
* @ packageName angular - message - format
* @ description
* /
var module = window [ 'angular' ] [ 'module' ] ( 'ngMessageFormat' , [ 'ng' ] ) ;
module [ 'factory' ] ( '$$messageFormat' , $$MessageFormatFactory ) ;
module [ 'config' ] ( [ '$provide' , function ( $provide ) {
$provide [ 'decorator' ] ( '$interpolate' , $$interpolateDecorator ) ;
} ] ) ;
} ) ( window , window . angular ) ;