190 lines
6.2 KiB
JavaScript
190 lines
6.2 KiB
JavaScript
import ngModule from '../module';
|
|
import {ng} from '../vendor';
|
|
|
|
function stringify(value) {
|
|
if (value === null) { // null || undefined
|
|
return '';
|
|
}
|
|
switch (typeof value) {
|
|
case 'string':
|
|
break;
|
|
case 'number':
|
|
value = String(value);
|
|
break;
|
|
default:
|
|
value = angular.toJson(value);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
var $interpolateMinErr = ng.$interpolateMinErr = ng.$$minErr('$interpolate');
|
|
|
|
$interpolateMinErr.throwNoconcat = function(text) {
|
|
throw $interpolateMinErr('noconcat',
|
|
'Error while interpolating: {0}\nStrict Contextual Escaping disallows ' +
|
|
'interpolations that concatenate multiple expressions when a trusted value is ' +
|
|
'required. See http://docs.angularjs.org/api/ng.$sce', text);
|
|
};
|
|
|
|
$interpolateMinErr.interr = function(text, err) {
|
|
return $interpolateMinErr('interr', 'Can\'t interpolate: {0}\n{1}', text, err.toString());
|
|
};
|
|
|
|
function $get($parse, $exceptionHandler, $sce) {
|
|
let startSymbolLength = this._startSymbol.length;
|
|
let endSymbolLength = this._endSymbol.length;
|
|
let escapedStartRegexp = new RegExp(this._startSymbol.replace(/./g, escape), 'g');
|
|
let escapedEndRegexp = new RegExp(this._endSymbol.replace(/./g, escape), 'g');
|
|
let self = this;
|
|
|
|
function escape(ch) {
|
|
return '\\\\\\' + ch;
|
|
}
|
|
|
|
function unescapeText(text) {
|
|
return text.replace(escapedStartRegexp, self._startSymbol)
|
|
.replace(escapedEndRegexp, self._endSymbol);
|
|
}
|
|
|
|
// TODO: this is the same as the constantWatchDelegate in parse.js
|
|
function constantWatchDelegate(scope, listener, objectEquality, constantInterp) {
|
|
var unwatch = scope.$watch(function constantInterpolateWatch(scope) {
|
|
unwatch();
|
|
return constantInterp(scope);
|
|
}, listener, objectEquality);
|
|
return unwatch;
|
|
}
|
|
|
|
function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
|
|
// Provide a quick exit and simplified result function for text with no interpolation
|
|
if (!text.length || text.indexOf(self._startSymbol) === -1) {
|
|
var constantInterp;
|
|
if (!mustHaveExpression) {
|
|
var unescapedText = unescapeText(text);
|
|
constantInterp = valueFn(unescapedText);
|
|
constantInterp.exp = text;
|
|
constantInterp.expressions = [];
|
|
constantInterp.$$watchDelegate = constantWatchDelegate;
|
|
}
|
|
return constantInterp;
|
|
}
|
|
|
|
allOrNothing = Boolean(allOrNothing);
|
|
let startIndex;
|
|
let endIndex;
|
|
let index = 0;
|
|
let expressions = [];
|
|
let parseFns = [];
|
|
let textLength = text.length;
|
|
let exp;
|
|
let concat = [];
|
|
let expressionPositions = [];
|
|
|
|
while (index < textLength) {
|
|
if (((startIndex = text.indexOf(self._startSymbol, index)) !== -1) &&
|
|
((endIndex = text.indexOf(self._endSymbol, startIndex + startSymbolLength)) !== -1)) {
|
|
if (index !== startIndex)
|
|
concat.push(unescapeText(text.substring(index, startIndex)));
|
|
exp = text.substring(startIndex + startSymbolLength, endIndex);
|
|
expressions.push(exp);
|
|
parseFns.push($parse(exp, parseStringifyInterceptor));
|
|
index = endIndex + endSymbolLength;
|
|
expressionPositions.push(concat.length);
|
|
concat.push('');
|
|
} else {
|
|
// we did not find an interpolation, so we have to add the remainder to the separators array
|
|
if (index !== textLength)
|
|
concat.push(unescapeText(text.substring(index)));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (trustedContext && concat.length > 1) {
|
|
$interpolateMinErr.throwNoconcat(text);
|
|
}
|
|
|
|
var getValue = function(value) {
|
|
return trustedContext ?
|
|
$sce.getTrusted(trustedContext, value) :
|
|
$sce.valueOf(value);
|
|
};
|
|
|
|
if (!mustHaveExpression || expressions.length) {
|
|
var compute = function(values) {
|
|
for (var i = 0, ii = expressions.length; i < ii; i++) {
|
|
if (allOrNothing && isUndefined(values[i])) return;
|
|
concat[expressionPositions[i]] = values[i];
|
|
}
|
|
return concat.join('');
|
|
};
|
|
|
|
return angular.extend(function interpolationFn(context) {
|
|
var i = 0;
|
|
var ii = expressions.length;
|
|
var values = new Array(ii);
|
|
|
|
try {
|
|
for (; i < ii; i++) {
|
|
values[i] = parseFns[i](context);
|
|
}
|
|
|
|
return compute(values);
|
|
} catch (err) {
|
|
$exceptionHandler($interpolateMinErr.interr(text, err));
|
|
}
|
|
}, {
|
|
// all of these properties are undocumented for now
|
|
exp: text, // just for compatibility with regular watchers created via $watch
|
|
expressions: expressions
|
|
});
|
|
}
|
|
|
|
function parseStringifyInterceptor(value) {
|
|
try {
|
|
value = getValue(value);
|
|
return allOrNothing && !isDefined(value) ? value : stringify(value);
|
|
} catch (err) {
|
|
$exceptionHandler($interpolateMinErr.interr(text, err));
|
|
}
|
|
}
|
|
}
|
|
|
|
$interpolate.startSymbol = function() {
|
|
return startSymbol;
|
|
};
|
|
|
|
$interpolate.endSymbol = function() {
|
|
return endSymbol;
|
|
};
|
|
|
|
return $interpolate;
|
|
}
|
|
|
|
$get.$inject = ['$parse', '$exceptionHandler', '$sce'];
|
|
|
|
export class Interpolate {
|
|
constructor() {
|
|
this._startSymbol = '*[';
|
|
this._endSymbol = ']*';
|
|
}
|
|
set startSymbol(value) {
|
|
if (value) {
|
|
this._startSymbol = value;
|
|
return this;
|
|
}
|
|
return this._startSymbol;
|
|
}
|
|
set endSymbol(value) {
|
|
if (value) {
|
|
this._endSymbol = value;
|
|
return this;
|
|
}
|
|
return this._endSymbol;
|
|
}
|
|
}
|
|
|
|
Interpolate.prototype.$get = $get;
|
|
var interpolate = new Interpolate();
|
|
ngModule.provider('vnInterpolate', () => interpolate);
|