/**
* @workInProgress
* @ngdoc filter
* @name angular.filter.currency
* @function
*
* @description
* Formats a number as a currency (ie $1,234.56).
*
* @param {number} amount Input to filter.
* @returns {string} Formated number.
*
* @css ng-format-negative
* When the value is negative, this css class is applied to the binding making it by default red.
*
* @example
{{amount | currency}}
*
* @scenario
it('should init with 1234.56', function(){
expect(binding('amount | currency')).toBe('$1,234.56');
});
it('should update', function(){
input('amount').enter('-1234');
expect(binding('amount | currency')).toBe('$-1,234.00');
expect(element('.doc-example-live .ng-binding').attr('className')).
toMatch(/ng-format-negative/);
});
*/
angularFilter.currency = function(amount){
this.$element.toggleClass('ng-format-negative', amount < 0);
return '$' + angularFilter['number'].apply(this, [amount, 2]);
};
/**
* @workInProgress
* @ngdoc filter
* @name angular.filter.number
* @function
*
* @description
* Formats a number as text.
*
* If the input is not a number empty string is returned.
*
* @param {number|string} number Number to format.
* @param {(number|string)=} [fractionSize=2] Number of decimal places to round the number to.
* @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
*
* @example
Enter number:
Default formatting: {{val | number}}
No fractions: {{val | number:0}}
Negative number: {{-val | number:4}}
* @scenario
it('should format numbers', function(){
expect(binding('val | number')).toBe('1,234.57');
expect(binding('val | number:0')).toBe('1,235');
expect(binding('-val | number:4')).toBe('-1,234.5679');
});
it('should update', function(){
input('val').enter('3374.333');
expect(binding('val | number')).toBe('3,374.33');
expect(binding('val | number:0')).toBe('3,374');
expect(binding('-val | number:4')).toBe('-3,374.3330');
});
*/
angularFilter.number = function(number, fractionSize){
if (isNaN(number) || !isFinite(number)) {
return '';
}
fractionSize = typeof fractionSize == $undefined ? 2 : fractionSize;
var isNegative = number < 0;
number = Math.abs(number);
var pow = Math.pow(10, fractionSize);
var text = "" + Math.round(number * pow);
var whole = text.substring(0, text.length - fractionSize);
whole = whole || '0';
var frc = text.substring(text.length - fractionSize);
text = isNegative ? '-' : '';
for (var i = 0; i < whole.length; i++) {
if ((whole.length - i)%3 === 0 && i !== 0) {
text += ',';
}
text += whole.charAt(i);
}
if (fractionSize > 0) {
for (var j = frc.length; j < fractionSize; j++) {
frc += '0';
}
text += '.' + frc.substring(0, fractionSize);
}
return text;
};
function padNumber(num, digits, trim) {
var neg = '';
if (num < 0) {
neg = '-';
num = -num;
}
num = '' + num;
while(num.length < digits) num = '0' + num;
if (trim)
num = num.substr(num.length - digits);
return neg + num;
}
function dateGetter(name, size, offset, trim) {
return function(date) {
var value = date['get' + name]();
if (offset > 0 || value > -offset)
value += offset;
if (value === 0 && offset == -12 ) value = 12;
return padNumber(value, size, trim);
};
}
var DATE_FORMATS = {
yyyy: dateGetter('FullYear', 4),
yy: dateGetter('FullYear', 2, 0, true),
MM: dateGetter('Month', 2, 1),
M: dateGetter('Month', 1, 1),
dd: dateGetter('Date', 2),
d: dateGetter('Date', 1),
HH: dateGetter('Hours', 2),
H: dateGetter('Hours', 1),
hh: dateGetter('Hours', 2, -12),
h: dateGetter('Hours', 1, -12),
mm: dateGetter('Minutes', 2),
m: dateGetter('Minutes', 1),
ss: dateGetter('Seconds', 2),
s: dateGetter('Seconds', 1),
a: function(date){return date.getHours() < 12 ? 'am' : 'pm';},
Z: function(date){
var offset = date.getTimezoneOffset();
return padNumber(offset / 60, 2) + padNumber(Math.abs(offset % 60), 2);
}
};
var DATE_FORMATS_SPLIT = /([^yMdHhmsaZ]*)(y+|M+|d+|H+|h+|m+|s+|a|Z)(.*)/;
var NUMBER_STRING = /^\d+$/;
/**
* @workInProgress
* @ngdoc filter
* @name angular.filter.date
* @function
*
* @description
* Formats `date` to a string based on the requested `format`.
*
* `format` string can be composed of the following elements:
*
* * `'yyyy'`: 4 digit representation of year e.g. 2010
* * `'yy'`: 2 digit representation of year, padded (00-99)
* * `'MM'`: Month in year, padded (01‒12)
* * `'M'`: Month in year (1‒12)
* * `'dd'`: Day in month, padded (01‒31)
* * `'d'`: Day in month (1-31)
* * `'HH'`: Hour in day, padded (00‒23)
* * `'H'`: Hour in day (0-23)
* * `'hh'`: Hour in am/pm, padded (01‒12)
* * `'h'`: Hour in am/pm, (1-12)
* * `'mm'`: Minute in hour, padded (00‒59)
* * `'m'`: Minute in hour (0-59)
* * `'ss'`: Second in minute, padded (00‒59)
* * `'s'`: Second in minute (0‒59)
* * `'a'`: am/pm marker
* * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200‒1200)
*
* @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
* number) or ISO 8601 extended datetime string (yyyy-MM-ddTHH:mm:ss.SSSZ).
* @param {string=} format Formatting rules. If not specified, Date#toLocaleDateString is used.
* @returns {string} Formatted string or the input if input is not recognized as date/millis.
*
* @example
{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}:
{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}
{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}:
{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}
*
* @scenario
it('should format date', function(){
expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).
toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} \-?\d{4}/);
expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).
toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(am|pm)/);
});
*
*/
angularFilter.date = function(date, format) {
if (isString(date)) {
if (NUMBER_STRING.test(date)) {
date = parseInt(date, 10);
} else {
date = angularString.toDate(date);
}
}
if (isNumber(date)) {
date = new Date(date);
}
if (!isDate(date)) {
return date;
}
var text = date.toLocaleDateString(), fn;
if (format && isString(format)) {
text = '';
var parts = [];
while(format) {
parts = concat(parts, DATE_FORMATS_SPLIT.exec(format), 1);
format = parts.pop();
}
foreach(parts, function(value){
fn = DATE_FORMATS[value];
text += fn ? fn(date) : value;
});
}
return text;
};
/**
* @workInProgress
* @ngdoc filter
* @name angular.filter.json
* @function
*
* @description
* Allows you to convert a JavaScript object into JSON string.
*
* This filter is mostly useful for debugging. When using the double curly {{value}} notation
* the binding is automatically converted to JSON.
*
* @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
* @returns {string} JSON string.
*
* @css ng-monospace Always applied to the encapsulating element.
*
* @example:
{{ obj | json }}* * @scenario it('should jsonify filtered objects', function() { expect(binding('obj | json')).toBe('{\n "a":1,\n "b":[]}'); }); it('should update', function() { input('objTxt').enter('[1, 2, 3]'); expect(binding('obj | json')).toBe('[1,2,3]'); }); * */ angularFilter.json = function(object) { this.$element.addClass("ng-monospace"); return toJson(object, true); }; /** * @workInProgress * @ngdoc filter * @name angular.filter.lowercase * @function * * @see angular.lowercase */ angularFilter.lowercase = lowercase; /** * @workInProgress * @ngdoc filter * @name angular.filter.uppercase * @function * * @see angular.uppercase */ angularFilter.uppercase = uppercase; /** * @workInProgress * @ngdoc filter * @name angular.filter.html * @function * * @description * Prevents the input from getting escaped by angular. By default the input is sanitized and * inserted into the DOM as is. * * The input is sanitized by parsing the html into tokens. All safe tokens (from a whitelist) are * then serialized back to properly escaped html string. This means that no unsafe input can make * it into the returned string, however since our parser is more strict than a typical browser * parser, it's possible that some obscure input, which would be recognized as valid HTML by a * browser, won't make it through the sanitizer. * * If you hate your users, you may call the filter with optional 'unsafe' argument, which bypasses * the html sanitizer, but makes your application vulnerable to XSS and other attacks. Using this * option is strongly discouraged and should be used only if you absolutely trust the input being * filtered and you can't get the content through the sanitizer. * * @param {string} html Html input. * @param {string=} option If 'unsafe' then do not sanitize the HTML input. * @returns {string} Sanitized or raw html. * * @example Snippet:
Filter | Source | Rendered |
html filter |
<div ng:bind="snippet | html"> |
|
no filter | <div ng:bind="snippet"> |
|
unsafe html filter | <div ng:bind="snippet | html:'unsafe'"> |
an html\nclick here\nsnippet
'); }); it ('should escape snippet without any filter', function() { expect(using('#escaped-html').binding('snippet')). toBe("<p style=\"color:blue\">an html\n" + "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + "snippet</p>"); }); it ('should inline raw snippet if filtered as unsafe', function() { expect(using('#html-unsafe-filter').binding("snippet | html:'unsafe'")). toBe("an html\n" + "click here\n" + "snippet
"); }); it('should update', function(){ input('snippet').enter('new text'); expect(using('#html-filter').binding('snippet | html')).toBe('new text'); expect(using('#escaped-html').binding('snippet')).toBe("new <b>text</b>"); expect(using('#html-unsafe-filter').binding("snippet | html:'unsafe'")).toBe('new text'); }); */ angularFilter.html = function(html, option){ return new HTML(html, option); }; /** * @workInProgress * @ngdoc filter * @name angular.filter.linky * @function * * @description * Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and * plane email address links. * * @param {string} text Input text. * @returns {string} Html-linkified text. * * @example Snippet:Filter | Source | Rendered |
linky filter |
<div ng:bind="snippet | linky"> |
|
no filter | <div ng:bind="snippet"> |