mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-04-18 05:41:01 +00:00
chore(ngSanitize): extract $sanitize, ngBindHtml, linkyFilter into a module
Create build for other modules as well (ngResource, ngCookies):
- wrap into a function
- add license
- add version
Breaks `$sanitize` service, `ngBindHtml` directive and `linky` filter were moved to the `ngSanitize` module. Apps that depend on any of these will need to load `angular-sanitize.js` and include `ngSanitize` in their dependency list: `var myApp = angular.module('myApp', ['ngSanitize']);`
This commit is contained in:
parent
e1743cc837
commit
5bcd719866
20 changed files with 301 additions and 244 deletions
24
Rakefile
24
Rakefile
|
|
@ -82,15 +82,23 @@ task :compile => [:init, :compile_scenario, :compile_jstd_scenario_adapter] do
|
||||||
'src/loader.js',
|
'src/loader.js',
|
||||||
'src/loader.suffix'])
|
'src/loader.suffix'])
|
||||||
|
|
||||||
FileUtils.cp 'src/ngMock/angular-mocks.js', path_to('angular-mocks.js')
|
|
||||||
FileUtils.cp 'src/ngResource/resource.js', path_to('angular-resource.js')
|
|
||||||
FileUtils.cp 'src/ngCookies/cookies.js', path_to('angular-cookies.js')
|
|
||||||
|
|
||||||
|
concat_module('sanitize', [
|
||||||
|
'src/ngSanitize/sanitize.js',
|
||||||
|
'src/ngSanitize/directive/ngBindHtml.js',
|
||||||
|
'src/ngSanitize/filter/linky.js'])
|
||||||
|
|
||||||
|
concat_module('resource', ['src/ngResource/resource.js'])
|
||||||
|
concat_module('cookies', ['src/ngCookies/cookies.js'])
|
||||||
|
|
||||||
|
|
||||||
|
FileUtils.cp 'src/ngMock/angular-mocks.js', path_to('angular-mocks.js')
|
||||||
|
|
||||||
closure_compile('angular.js')
|
closure_compile('angular.js')
|
||||||
closure_compile('angular-cookies.js')
|
closure_compile('angular-cookies.js')
|
||||||
closure_compile('angular-loader.js')
|
closure_compile('angular-loader.js')
|
||||||
closure_compile('angular-resource.js')
|
closure_compile('angular-resource.js')
|
||||||
|
closure_compile('angular-sanitize.js')
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -121,6 +129,8 @@ task :package => [:clean, :compile, :docs] do
|
||||||
path_to('angular-cookies.min.js'),
|
path_to('angular-cookies.min.js'),
|
||||||
path_to('angular-resource.js'),
|
path_to('angular-resource.js'),
|
||||||
path_to('angular-resource.min.js'),
|
path_to('angular-resource.min.js'),
|
||||||
|
path_to('angular-sanitize.js'),
|
||||||
|
path_to('angular-sanitize.min.js'),
|
||||||
path_to('angular-scenario.js'),
|
path_to('angular-scenario.js'),
|
||||||
path_to('jstd-scenario-adapter.js'),
|
path_to('jstd-scenario-adapter.js'),
|
||||||
path_to('jstd-scenario-adapter-config.js'),
|
path_to('jstd-scenario-adapter-config.js'),
|
||||||
|
|
@ -147,7 +157,8 @@ task :package => [:clean, :compile, :docs] do
|
||||||
rewrite_file(src) do |content|
|
rewrite_file(src) do |content|
|
||||||
content.sub!('angular.js', "angular-#{NG_VERSION.full}.js").
|
content.sub!('angular.js', "angular-#{NG_VERSION.full}.js").
|
||||||
sub!('angular-resource.js', "angular-resource-#{NG_VERSION.full}.js").
|
sub!('angular-resource.js', "angular-resource-#{NG_VERSION.full}.js").
|
||||||
sub!('angular-cookies.js', "angular-cookies-#{NG_VERSION.full}.js")
|
sub!('angular-cookies.js', "angular-cookies-#{NG_VERSION.full}.js").
|
||||||
|
sub!('angular-sanitize.js', "angular-sanitize-#{NG_VERSION.full}.js")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -290,6 +301,11 @@ def concat_file(filename, deps, footer='')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def concat_module(name, files)
|
||||||
|
concat_file('angular-' + name + '.js', ['src/module.prefix'] + files + ['src/module.suffix'])
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
def rewrite_file(filename)
|
def rewrite_file(filename)
|
||||||
File.open(filename, File::RDWR) do |f|
|
File.open(filename, File::RDWR) do |f|
|
||||||
content = f.read
|
content = f.read
|
||||||
|
|
|
||||||
15
angularFiles.js
vendored
15
angularFiles.js
vendored
|
|
@ -24,7 +24,6 @@ angularFiles = {
|
||||||
'src/ng/route.js',
|
'src/ng/route.js',
|
||||||
'src/ng/routeParams.js',
|
'src/ng/routeParams.js',
|
||||||
'src/ng/rootScope.js',
|
'src/ng/rootScope.js',
|
||||||
'src/ng/sanitize.js',
|
|
||||||
'src/ng/sniffer.js',
|
'src/ng/sniffer.js',
|
||||||
'src/ng/window.js',
|
'src/ng/window.js',
|
||||||
'src/ng/http.js',
|
'src/ng/http.js',
|
||||||
|
|
@ -65,6 +64,9 @@ angularFiles = {
|
||||||
'angularSrcModules': [
|
'angularSrcModules': [
|
||||||
'src/ngCookies/cookies.js',
|
'src/ngCookies/cookies.js',
|
||||||
'src/ngResource/resource.js',
|
'src/ngResource/resource.js',
|
||||||
|
'src/ngSanitize/sanitize.js',
|
||||||
|
'src/ngSanitize/directive/ngBindHtml.js',
|
||||||
|
'src/ngSanitize/filter/linky.js',
|
||||||
'src/ngMock/angular-mocks.js'
|
'src/ngMock/angular-mocks.js'
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
@ -98,6 +100,9 @@ angularFiles = {
|
||||||
'test/ng/filter/*.js',
|
'test/ng/filter/*.js',
|
||||||
'test/ngCookies/*.js',
|
'test/ngCookies/*.js',
|
||||||
'test/ngResource/*.js',
|
'test/ngResource/*.js',
|
||||||
|
'test/ngSanitize/*.js',
|
||||||
|
'test/ngSanitize/directive/*.js',
|
||||||
|
'test/ngSanitize/filter/*.js',
|
||||||
'test/ngMock/*.js'
|
'test/ngMock/*.js'
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
@ -136,10 +141,16 @@ angularFiles = {
|
||||||
'src/ngMock/angular-mocks.js',
|
'src/ngMock/angular-mocks.js',
|
||||||
'src/ngCookies/cookies.js',
|
'src/ngCookies/cookies.js',
|
||||||
'src/ngResource/resource.js',
|
'src/ngResource/resource.js',
|
||||||
|
'src/ngSanitize/sanitize.js',
|
||||||
|
'src/ngSanitize/directive/ngBindHtml.js',
|
||||||
|
'src/ngSanitize/filter/linky.js',
|
||||||
'test/matchers.js',
|
'test/matchers.js',
|
||||||
'test/ngMock/*.js',
|
'test/ngMock/*.js',
|
||||||
'test/ngCookies/*.js',
|
'test/ngCookies/*.js',
|
||||||
'test/ngResource/*.js'
|
'test/ngResource/*.js',
|
||||||
|
'test/ngSanitize/*.js',
|
||||||
|
'test/ngSanitize/directive/*.js',
|
||||||
|
'test/ngSanitize/filter/*.js'
|
||||||
],
|
],
|
||||||
|
|
||||||
'jstdPerf': [
|
'jstdPerf': [
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ The two partials are defined in the following URLs:
|
||||||
<doc:example module="deepLinking">
|
<doc:example module="deepLinking">
|
||||||
<doc:source jsfiddle="false">
|
<doc:source jsfiddle="false">
|
||||||
<script>
|
<script>
|
||||||
angular.module('deepLinking', [])
|
angular.module('deepLinking', ['ngSanitize'])
|
||||||
.config(function($routeProvider) {
|
.config(function($routeProvider) {
|
||||||
$routeProvider.when("/welcome", {template:'./examples/welcome.html', controller:WelcomeCntl});
|
$routeProvider.when("/welcome", {template:'./examples/welcome.html', controller:WelcomeCntl});
|
||||||
$routeProvider.when("/settings", {template:'./examples/settings.html', controller:SettingsCntl});
|
$routeProvider.when("/settings", {template:'./examples/settings.html', controller:SettingsCntl});
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,8 @@ function TutorialInstructionsCtrl($scope, $cookieStore) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
angular.module('ngdocs', ['ngdocs.directives', 'ngResource', 'ngCookies'], function($locationProvider, $filterProvider, $compileProvider) {
|
angular.module('ngdocs', ['ngdocs.directives', 'ngResource', 'ngCookies', 'ngSanitize'],
|
||||||
|
function($locationProvider, $filterProvider, $compileProvider) {
|
||||||
$locationProvider.html5Mode(true).hashPrefix('!');
|
$locationProvider.html5Mode(true).hashPrefix('!');
|
||||||
|
|
||||||
$filterProvider.register('title', function(){
|
$filterProvider.register('title', function(){
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
addTag('script', {src: path('angular.js')}, sync);
|
addTag('script', {src: path('angular.js')}, sync);
|
||||||
addTag('script', {src: path('angular-resource.js') }, sync);
|
addTag('script', {src: path('angular-resource.js') }, sync);
|
||||||
addTag('script', {src: path('angular-cookies.js') }, sync);
|
addTag('script', {src: path('angular-cookies.js') }, sync);
|
||||||
|
addTag('script', {src: path('angular-sanitize.js') }, sync);
|
||||||
addTag('script', {src: 'docs-combined.js'}, sync);
|
addTag('script', {src: 'docs-combined.js'}, sync);
|
||||||
addTag('script', {src: 'docs-keywords.js'}, sync);
|
addTag('script', {src: 'docs-keywords.js'}, sync);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,6 @@ function publishExternalAPI(angular){
|
||||||
style: styleDirective,
|
style: styleDirective,
|
||||||
option: optionDirective,
|
option: optionDirective,
|
||||||
ngBind: ngBindDirective,
|
ngBind: ngBindDirective,
|
||||||
ngBindHtml: ngBindHtmlDirective,
|
|
||||||
ngBindHtmlUnsafe: ngBindHtmlUnsafeDirective,
|
ngBindHtmlUnsafe: ngBindHtmlUnsafeDirective,
|
||||||
ngBindTemplate: ngBindTemplateDirective,
|
ngBindTemplate: ngBindTemplateDirective,
|
||||||
ngClass: ngClassDirective,
|
ngClass: ngClassDirective,
|
||||||
|
|
@ -123,7 +122,6 @@ function publishExternalAPI(angular){
|
||||||
$routeParams: $RouteParamsProvider,
|
$routeParams: $RouteParamsProvider,
|
||||||
$rootScope: $RootScopeProvider,
|
$rootScope: $RootScopeProvider,
|
||||||
$q: $QProvider,
|
$q: $QProvider,
|
||||||
$sanitize: $SanitizeProvider,
|
|
||||||
$sniffer: $SnifferProvider,
|
$sniffer: $SnifferProvider,
|
||||||
$templateCache: $TemplateCacheProvider,
|
$templateCache: $TemplateCacheProvider,
|
||||||
$window: $WindowProvider
|
$window: $WindowProvider
|
||||||
|
|
|
||||||
6
src/module.prefix
Normal file
6
src/module.prefix
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
/**
|
||||||
|
* @license AngularJS v"NG_VERSION_FULL"
|
||||||
|
* (c) 2010-2012 AngularJS http://angularjs.org
|
||||||
|
* License: MIT
|
||||||
|
*/
|
||||||
|
(function(angular) {
|
||||||
2
src/module.suffix
Normal file
2
src/module.suffix
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
})(window.angular);
|
||||||
|
|
@ -55,54 +55,6 @@ var ngBindDirective = ngDirective(function(scope, element, attr) {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc directive
|
|
||||||
* @name angular.module.ng.$compileProvider.directive.ngBindHtmlUnsafe
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Creates a binding that will innerHTML the result of evaluating the `expression` into the current
|
|
||||||
* element. *The innerHTML-ed content will not be sanitized!* You should use this directive only if
|
|
||||||
* {@link angular.module.ng.$compileProvider.directive.ngBindHtml ngBindHtml} directive is too
|
|
||||||
* restrictive and when you absolutely trust the source of the content you are binding to.
|
|
||||||
*
|
|
||||||
* See {@link angular.module.ng.$sanitize $sanitize} docs for examples.
|
|
||||||
*
|
|
||||||
* @element ANY
|
|
||||||
* @param {expression} ngBindHtmlUnsafe {@link guide/dev_guide.expressions Expression} to evaluate.
|
|
||||||
*/
|
|
||||||
var ngBindHtmlUnsafeDirective = ngDirective(function(scope, element, attr) {
|
|
||||||
element.addClass('ng-binding').data('$binding', attr.ngBindHtmlUnsafe);
|
|
||||||
scope.$watch(attr.ngBindHtmlUnsafe, function(value) {
|
|
||||||
element.html(value || '');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc directive
|
|
||||||
* @name angular.module.ng.$compileProvider.directive.ngBindHtml
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Creates a binding that will sanitize the result of evaluating the `expression` with the
|
|
||||||
* {@link angular.module.ng.$sanitize $sanitize} service and innerHTML the result into the current
|
|
||||||
* element.
|
|
||||||
*
|
|
||||||
* See {@link angular.module.ng.$sanitize $sanitize} docs for examples.
|
|
||||||
*
|
|
||||||
* @element ANY
|
|
||||||
* @param {expression} ngBindHtml {@link guide/dev_guide.expressions Expression} to evaluate.
|
|
||||||
*/
|
|
||||||
var ngBindHtmlDirective = ['$sanitize', function($sanitize) {
|
|
||||||
return function(scope, element, attr) {
|
|
||||||
element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
|
|
||||||
scope.$watch(attr.ngBindHtml, function(value) {
|
|
||||||
value = $sanitize(value);
|
|
||||||
element.html(value || '');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc directive
|
* @ngdoc directive
|
||||||
* @name angular.module.ng.$compileProvider.directive.ngBindTemplate
|
* @name angular.module.ng.$compileProvider.directive.ngBindTemplate
|
||||||
|
|
@ -160,3 +112,28 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc directive
|
||||||
|
* @name angular.module.ng.$compileProvider.directive.ngBindHtmlUnsafe
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Creates a binding that will innerHTML the result of evaluating the `expression` into the current
|
||||||
|
* element. *The innerHTML-ed content will not be sanitized!* You should use this directive only if
|
||||||
|
* {@link angular.module.ng.$compileProvider.directive.ngBindHtml ngBindHtml} directive is too
|
||||||
|
* restrictive and when you absolutely trust the source of the content you are binding to.
|
||||||
|
*
|
||||||
|
* See {@link angular.module.ng.$sanitize $sanitize} docs for examples.
|
||||||
|
*
|
||||||
|
* @element ANY
|
||||||
|
* @param {expression} ngBindHtmlUnsafe {@link guide/dev_guide.expressions Expression} to evaluate.
|
||||||
|
*/
|
||||||
|
var ngBindHtmlUnsafeDirective = [function() {
|
||||||
|
return function(scope, element, attr) {
|
||||||
|
element.addClass('ng-binding').data('$binding', attr.ngBindHtmlUnsafe);
|
||||||
|
scope.$watch(attr.ngBindHtmlUnsafe, function(value) {
|
||||||
|
element.html(value || '');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}];
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,6 @@ function $FilterProvider($provide) {
|
||||||
register('filter', filterFilter);
|
register('filter', filterFilter);
|
||||||
register('json', jsonFilter);
|
register('json', jsonFilter);
|
||||||
register('limitTo', limitToFilter);
|
register('limitTo', limitToFilter);
|
||||||
register('linky', linkyFilter);
|
|
||||||
register('lowercase', lowercaseFilter);
|
register('lowercase', lowercaseFilter);
|
||||||
register('number', numberFilter);
|
register('number', numberFilter);
|
||||||
register('orderBy', orderByFilter);
|
register('orderBy', orderByFilter);
|
||||||
|
|
|
||||||
|
|
@ -439,110 +439,3 @@ var lowercaseFilter = valueFn(lowercase);
|
||||||
* @see angular.uppercase
|
* @see angular.uppercase
|
||||||
*/
|
*/
|
||||||
var uppercaseFilter = valueFn(uppercase);
|
var uppercaseFilter = valueFn(uppercase);
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc filter
|
|
||||||
* @name angular.module.ng.$filter.linky
|
|
||||||
* @function
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and
|
|
||||||
* plain email address links.
|
|
||||||
*
|
|
||||||
* @param {string} text Input text.
|
|
||||||
* @returns {string} Html-linkified text.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
<doc:example>
|
|
||||||
<doc:source>
|
|
||||||
<script>
|
|
||||||
function Ctrl($scope) {
|
|
||||||
$scope.snippet =
|
|
||||||
'Pretty text with some links:\n'+
|
|
||||||
'http://angularjs.org/,\n'+
|
|
||||||
'mailto:us@somewhere.org,\n'+
|
|
||||||
'another@somewhere.org,\n'+
|
|
||||||
'and one more: ftp://127.0.0.1/.';
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<div ng-controller="Ctrl">
|
|
||||||
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>Filter</td>
|
|
||||||
<td>Source</td>
|
|
||||||
<td>Rendered</td>
|
|
||||||
</tr>
|
|
||||||
<tr id="linky-filter">
|
|
||||||
<td>linky filter</td>
|
|
||||||
<td>
|
|
||||||
<pre><div ng-bind-html="snippet | linky"><br></div></pre>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div ng-bind-html="snippet | linky"></div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr id="escaped-html">
|
|
||||||
<td>no filter</td>
|
|
||||||
<td><pre><div ng-bind="snippet"><br></div></pre></td>
|
|
||||||
<td><div ng-bind="snippet"></div></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</doc:source>
|
|
||||||
<doc:scenario>
|
|
||||||
it('should linkify the snippet with urls', function() {
|
|
||||||
expect(using('#linky-filter').binding('snippet | linky')).
|
|
||||||
toBe('Pretty text with some links: ' +
|
|
||||||
'<a href="http://angularjs.org/">http://angularjs.org/</a>, ' +
|
|
||||||
'<a href="mailto:us@somewhere.org">us@somewhere.org</a>, ' +
|
|
||||||
'<a href="mailto:another@somewhere.org">another@somewhere.org</a>, ' +
|
|
||||||
'and one more: <a href="ftp://127.0.0.1/">ftp://127.0.0.1/</a>.');
|
|
||||||
});
|
|
||||||
|
|
||||||
it ('should not linkify snippet without the linky filter', function() {
|
|
||||||
expect(using('#escaped-html').binding('snippet')).
|
|
||||||
toBe("Pretty text with some links:\n" +
|
|
||||||
"http://angularjs.org/,\n" +
|
|
||||||
"mailto:us@somewhere.org,\n" +
|
|
||||||
"another@somewhere.org,\n" +
|
|
||||||
"and one more: ftp://127.0.0.1/.");
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update', function() {
|
|
||||||
input('snippet').enter('new http://link.');
|
|
||||||
expect(using('#linky-filter').binding('snippet | linky')).
|
|
||||||
toBe('new <a href="http://link">http://link</a>.');
|
|
||||||
expect(using('#escaped-html').binding('snippet')).toBe('new http://link.');
|
|
||||||
});
|
|
||||||
</doc:scenario>
|
|
||||||
</doc:example>
|
|
||||||
*/
|
|
||||||
function linkyFilter() {
|
|
||||||
var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}\<\>]/,
|
|
||||||
MAILTO_REGEXP = /^mailto:/;
|
|
||||||
|
|
||||||
return function(text) {
|
|
||||||
if (!text) return text;
|
|
||||||
var match;
|
|
||||||
var raw = text;
|
|
||||||
var html = [];
|
|
||||||
var writer = htmlSanitizeWriter(html);
|
|
||||||
var url;
|
|
||||||
var i;
|
|
||||||
while ((match = raw.match(LINKY_URL_REGEXP))) {
|
|
||||||
// We can not end in these as they are sometimes found at the end of the sentence
|
|
||||||
url = match[0];
|
|
||||||
// if we did not match ftp/http/mailto then assume mailto
|
|
||||||
if (match[2] == match[3]) url = 'mailto:' + url;
|
|
||||||
i = match.index;
|
|
||||||
writer.chars(raw.substr(0, i));
|
|
||||||
writer.start('a', {href:url});
|
|
||||||
writer.chars(match[0].replace(MAILTO_REGEXP, ''));
|
|
||||||
writer.end('a');
|
|
||||||
raw = raw.substring(i + match[0].length);
|
|
||||||
}
|
|
||||||
writer.chars(raw);
|
|
||||||
return html.join('');
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
||||||
26
src/ngSanitize/directive/ngBindHtml.js
Normal file
26
src/ngSanitize/directive/ngBindHtml.js
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc directive
|
||||||
|
* @name angular.module.ngSanitize.directive.ngBindHtml
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Creates a binding that will sanitize the result of evaluating the `expression` with the
|
||||||
|
* {@link angular.module.ng.$sanitize $sanitize} service and innerHTML the result into the current
|
||||||
|
* element.
|
||||||
|
*
|
||||||
|
* See {@link angular.module.ng.$sanitize $sanitize} docs for examples.
|
||||||
|
*
|
||||||
|
* @element ANY
|
||||||
|
* @param {expression} ngBindHtml {@link guide/dev_guide.expressions Expression} to evaluate.
|
||||||
|
*/
|
||||||
|
angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($sanitize) {
|
||||||
|
return function(scope, element, attr) {
|
||||||
|
element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
|
||||||
|
scope.$watch(attr.ngBindHtml, function(value) {
|
||||||
|
value = $sanitize(value);
|
||||||
|
element.html(value || '');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}]);
|
||||||
106
src/ngSanitize/filter/linky.js
Normal file
106
src/ngSanitize/filter/linky.js
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
/**
|
||||||
|
* @ngdoc filter
|
||||||
|
* @name angular.module.ngSanitize.filter.linky
|
||||||
|
* @function
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and
|
||||||
|
* plain email address links.
|
||||||
|
*
|
||||||
|
* @param {string} text Input text.
|
||||||
|
* @returns {string} Html-linkified text.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
<doc:example module="ngSanitize">
|
||||||
|
<doc:source>
|
||||||
|
<script>
|
||||||
|
function Ctrl($scope) {
|
||||||
|
$scope.snippet =
|
||||||
|
'Pretty text with some links:\n'+
|
||||||
|
'http://angularjs.org/,\n'+
|
||||||
|
'mailto:us@somewhere.org,\n'+
|
||||||
|
'another@somewhere.org,\n'+
|
||||||
|
'and one more: ftp://127.0.0.1/.';
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<div ng-controller="Ctrl">
|
||||||
|
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>Filter</td>
|
||||||
|
<td>Source</td>
|
||||||
|
<td>Rendered</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="linky-filter">
|
||||||
|
<td>linky filter</td>
|
||||||
|
<td>
|
||||||
|
<pre><div ng-bind-html="snippet | linky"><br></div></pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div ng-bind-html="snippet | linky"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="escaped-html">
|
||||||
|
<td>no filter</td>
|
||||||
|
<td><pre><div ng-bind="snippet"><br></div></pre></td>
|
||||||
|
<td><div ng-bind="snippet"></div></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</doc:source>
|
||||||
|
<doc:scenario>
|
||||||
|
it('should linkify the snippet with urls', function() {
|
||||||
|
expect(using('#linky-filter').binding('snippet | linky')).
|
||||||
|
toBe('Pretty text with some links: ' +
|
||||||
|
'<a href="http://angularjs.org/">http://angularjs.org/</a>, ' +
|
||||||
|
'<a href="mailto:us@somewhere.org">us@somewhere.org</a>, ' +
|
||||||
|
'<a href="mailto:another@somewhere.org">another@somewhere.org</a>, ' +
|
||||||
|
'and one more: <a href="ftp://127.0.0.1/">ftp://127.0.0.1/</a>.');
|
||||||
|
});
|
||||||
|
|
||||||
|
it ('should not linkify snippet without the linky filter', function() {
|
||||||
|
expect(using('#escaped-html').binding('snippet')).
|
||||||
|
toBe("Pretty text with some links:\n" +
|
||||||
|
"http://angularjs.org/,\n" +
|
||||||
|
"mailto:us@somewhere.org,\n" +
|
||||||
|
"another@somewhere.org,\n" +
|
||||||
|
"and one more: ftp://127.0.0.1/.");
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update', function() {
|
||||||
|
input('snippet').enter('new http://link.');
|
||||||
|
expect(using('#linky-filter').binding('snippet | linky')).
|
||||||
|
toBe('new <a href="http://link">http://link</a>.');
|
||||||
|
expect(using('#escaped-html').binding('snippet')).toBe('new http://link.');
|
||||||
|
});
|
||||||
|
</doc:scenario>
|
||||||
|
</doc:example>
|
||||||
|
*/
|
||||||
|
angular.module('ngSanitize').filter('linky', function() {
|
||||||
|
var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}\<\>]/,
|
||||||
|
MAILTO_REGEXP = /^mailto:/;
|
||||||
|
|
||||||
|
return function(text) {
|
||||||
|
if (!text) return text;
|
||||||
|
var match;
|
||||||
|
var raw = text;
|
||||||
|
var html = [];
|
||||||
|
// TODO(vojta): use $sanitize instead
|
||||||
|
var writer = htmlSanitizeWriter(html);
|
||||||
|
var url;
|
||||||
|
var i;
|
||||||
|
while ((match = raw.match(LINKY_URL_REGEXP))) {
|
||||||
|
// We can not end in these as they are sometimes found at the end of the sentence
|
||||||
|
url = match[0];
|
||||||
|
// if we did not match ftp/http/mailto then assume mailto
|
||||||
|
if (match[2] == match[3]) url = 'mailto:' + url;
|
||||||
|
i = match.index;
|
||||||
|
writer.chars(raw.substr(0, i));
|
||||||
|
writer.start('a', {href:url});
|
||||||
|
writer.chars(match[0].replace(MAILTO_REGEXP, ''));
|
||||||
|
writer.end('a');
|
||||||
|
raw = raw.substring(i + match[0].length);
|
||||||
|
}
|
||||||
|
writer.chars(raw);
|
||||||
|
return html.join('');
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc overview
|
||||||
|
* @name angular.module.ngSanitize
|
||||||
|
* @description
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HTML Parser By Misko Hevery (misko@hevery.com)
|
* HTML Parser By Misko Hevery (misko@hevery.com)
|
||||||
* based on: HTML Parser By John Resig (ejohn.org)
|
* based on: HTML Parser By John Resig (ejohn.org)
|
||||||
|
|
@ -17,10 +23,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc service
|
* @ngdoc service
|
||||||
* @name angular.module.ng.$sanitize
|
* @name angular.module.ngSanitize.$sanitize
|
||||||
* @function
|
* @function
|
||||||
*
|
*
|
||||||
* @description
|
* @description
|
||||||
|
|
@ -34,7 +39,7 @@
|
||||||
* @returns {string} Sanitized html.
|
* @returns {string} Sanitized html.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
<doc:example>
|
<doc:example module="ngSanitize">
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<script>
|
<script>
|
||||||
function Ctrl($scope) {
|
function Ctrl($scope) {
|
||||||
|
|
@ -103,14 +108,12 @@
|
||||||
</doc:scenario>
|
</doc:scenario>
|
||||||
</doc:example>
|
</doc:example>
|
||||||
*/
|
*/
|
||||||
|
var $sanitize = function(html) {
|
||||||
function $SanitizeProvider() {
|
var buf = [];
|
||||||
this.$get = valueFn(function(html) {
|
|
||||||
var buf = [];
|
|
||||||
htmlParser(html, htmlSanitizeWriter(buf));
|
htmlParser(html, htmlSanitizeWriter(buf));
|
||||||
return buf.join('');
|
return buf.join('');
|
||||||
});
|
};
|
||||||
}
|
|
||||||
|
|
||||||
// Regular Expressions for parsing tags and attributes
|
// Regular Expressions for parsing tags and attributes
|
||||||
var START_TAG_REGEXP = /^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/,
|
var START_TAG_REGEXP = /^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/,
|
||||||
|
|
@ -136,15 +139,15 @@ var voidElements = makeMap("area,br,col,hr,img,wbr");
|
||||||
// http://dev.w3.org/html5/spec/Overview.html#optional-tags
|
// http://dev.w3.org/html5/spec/Overview.html#optional-tags
|
||||||
var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),
|
var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),
|
||||||
optionalEndTagInlineElements = makeMap("rp,rt"),
|
optionalEndTagInlineElements = makeMap("rp,rt"),
|
||||||
optionalEndTagElements = extend({}, optionalEndTagInlineElements, optionalEndTagBlockElements);
|
optionalEndTagElements = angular.extend({}, optionalEndTagInlineElements, optionalEndTagBlockElements);
|
||||||
|
|
||||||
// Safe Block Elements - HTML5
|
// Safe Block Elements - HTML5
|
||||||
var blockElements = extend({}, optionalEndTagBlockElements, makeMap("address,article,aside," +
|
var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("address,article,aside," +
|
||||||
"blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6," +
|
"blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6," +
|
||||||
"header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul"));
|
"header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul"));
|
||||||
|
|
||||||
// Inline Elements - HTML5
|
// Inline Elements - HTML5
|
||||||
var inlineElements = extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b,bdi,bdo," +
|
var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b,bdi,bdo," +
|
||||||
"big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small," +
|
"big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small," +
|
||||||
"span,strike,strong,sub,sup,time,tt,u,var"));
|
"span,strike,strong,sub,sup,time,tt,u,var"));
|
||||||
|
|
||||||
|
|
@ -152,17 +155,24 @@ var inlineElements = extend({}, optionalEndTagInlineElements, makeMap("a,abbr,ac
|
||||||
// Special Elements (can contain anything)
|
// Special Elements (can contain anything)
|
||||||
var specialElements = makeMap("script,style");
|
var specialElements = makeMap("script,style");
|
||||||
|
|
||||||
var validElements = extend({}, voidElements, blockElements, inlineElements, optionalEndTagElements);
|
var validElements = angular.extend({}, voidElements, blockElements, inlineElements, optionalEndTagElements);
|
||||||
|
|
||||||
//Attributes that have href and hence need to be sanitized
|
//Attributes that have href and hence need to be sanitized
|
||||||
var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap");
|
var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap");
|
||||||
var validAttrs = extend({}, uriAttrs, makeMap(
|
var validAttrs = angular.extend({}, uriAttrs, makeMap(
|
||||||
'abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'+
|
'abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'+
|
||||||
'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,'+
|
'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,'+
|
||||||
'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,'+
|
'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,'+
|
||||||
'scope,scrolling,shape,span,start,summary,target,title,type,'+
|
'scope,scrolling,shape,span,start,summary,target,title,type,'+
|
||||||
'valign,value,vspace,width'));
|
'valign,value,vspace,width'));
|
||||||
|
|
||||||
|
function makeMap(str) {
|
||||||
|
var obj = {}, items = str.split(','), i;
|
||||||
|
for (i = 0; i < items.length; i++) obj[items[i]] = true;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @example
|
* @example
|
||||||
* htmlParser(htmlString, {
|
* htmlParser(htmlString, {
|
||||||
|
|
@ -249,7 +259,7 @@ function htmlParser( html, handler ) {
|
||||||
parseEndTag();
|
parseEndTag();
|
||||||
|
|
||||||
function parseStartTag( tag, tagName, rest, unary ) {
|
function parseStartTag( tag, tagName, rest, unary ) {
|
||||||
tagName = lowercase(tagName);
|
tagName = angular.lowercase(tagName);
|
||||||
if ( blockElements[ tagName ] ) {
|
if ( blockElements[ tagName ] ) {
|
||||||
while ( stack.last() && inlineElements[ stack.last() ] ) {
|
while ( stack.last() && inlineElements[ stack.last() ] ) {
|
||||||
parseEndTag( "", stack.last() );
|
parseEndTag( "", stack.last() );
|
||||||
|
|
@ -280,7 +290,7 @@ function htmlParser( html, handler ) {
|
||||||
|
|
||||||
function parseEndTag( tag, tagName ) {
|
function parseEndTag( tag, tagName ) {
|
||||||
var pos = 0, i;
|
var pos = 0, i;
|
||||||
tagName = lowercase(tagName);
|
tagName = angular.lowercase(tagName);
|
||||||
if ( tagName )
|
if ( tagName )
|
||||||
// Find the closest opened tag of the same type
|
// Find the closest opened tag of the same type
|
||||||
for ( pos = stack.length - 1; pos >= 0; pos-- )
|
for ( pos = stack.length - 1; pos >= 0; pos-- )
|
||||||
|
|
@ -338,18 +348,18 @@ function encodeEntities(value) {
|
||||||
*/
|
*/
|
||||||
function htmlSanitizeWriter(buf){
|
function htmlSanitizeWriter(buf){
|
||||||
var ignore = false;
|
var ignore = false;
|
||||||
var out = bind(buf, buf.push);
|
var out = angular.bind(buf, buf.push);
|
||||||
return {
|
return {
|
||||||
start: function(tag, attrs, unary){
|
start: function(tag, attrs, unary){
|
||||||
tag = lowercase(tag);
|
tag = angular.lowercase(tag);
|
||||||
if (!ignore && specialElements[tag]) {
|
if (!ignore && specialElements[tag]) {
|
||||||
ignore = tag;
|
ignore = tag;
|
||||||
}
|
}
|
||||||
if (!ignore && validElements[tag] == true) {
|
if (!ignore && validElements[tag] == true) {
|
||||||
out('<');
|
out('<');
|
||||||
out(tag);
|
out(tag);
|
||||||
forEach(attrs, function(value, key){
|
angular.forEach(attrs, function(value, key){
|
||||||
var lkey=lowercase(key);
|
var lkey=angular.lowercase(key);
|
||||||
if (validAttrs[lkey]==true && (uriAttrs[lkey]!==true || value.match(URI_REGEXP))) {
|
if (validAttrs[lkey]==true && (uriAttrs[lkey]!==true || value.match(URI_REGEXP))) {
|
||||||
out(' ');
|
out(' ');
|
||||||
out(key);
|
out(key);
|
||||||
|
|
@ -362,7 +372,7 @@ function htmlSanitizeWriter(buf){
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
end: function(tag){
|
end: function(tag){
|
||||||
tag = lowercase(tag);
|
tag = angular.lowercase(tag);
|
||||||
if (!ignore && validElements[tag] == true) {
|
if (!ignore && validElements[tag] == true) {
|
||||||
out('</');
|
out('</');
|
||||||
out(tag);
|
out(tag);
|
||||||
|
|
@ -379,3 +389,7 @@ function htmlSanitizeWriter(buf){
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// define ngSanitize module and register $sanitize service
|
||||||
|
angular.module('ngSanitize', []).value('$sanitize', $sanitize);
|
||||||
|
|
@ -67,39 +67,13 @@ describe('ngBind*', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('ngBindHtml', function() {
|
|
||||||
|
|
||||||
it('should set html', inject(function($rootScope, $compile) {
|
|
||||||
element = $compile('<div ng-bind-html="html"></div>')($rootScope);
|
|
||||||
$rootScope.html = '<div unknown>hello</div>';
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(lowercase(element.html())).toEqual('<div>hello</div>');
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
it('should reset html when value is null or undefined', inject(function($compile, $rootScope) {
|
|
||||||
element = $compile('<div ng-bind-html="html"></div>')($rootScope);
|
|
||||||
|
|
||||||
forEach([null, undefined, ''], function(val) {
|
|
||||||
$rootScope.html = 'some val';
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(lowercase(element.html())).toEqual('some val');
|
|
||||||
|
|
||||||
$rootScope.html = val;
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(lowercase(element.html())).toEqual('');
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('ngBindHtmlUnsafe', function() {
|
describe('ngBindHtmlUnsafe', function() {
|
||||||
|
|
||||||
it('should set unsafe html', inject(function($rootScope, $compile) {
|
it('should set unsafe html', inject(function($rootScope, $compile) {
|
||||||
element = $compile('<div ng-bind-html-unsafe="html"></div>')($rootScope);
|
element = $compile('<div ng-bind-html-unsafe="html"></div>')($rootScope);
|
||||||
$rootScope.html = '<div onclick="">hello</div>';
|
$rootScope.html = '<div onclick="">hello</div>';
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect(lowercase(element.html())).toEqual('<div onclick="">hello</div>');
|
expect(angular.lowercase(element.html())).toEqual('<div onclick="">hello</div>');
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -153,32 +153,6 @@ describe('filters', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('linky', function() {
|
|
||||||
var linky;
|
|
||||||
|
|
||||||
beforeEach(inject(function($filter){
|
|
||||||
linky = $filter('linky')
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should do basic filter', function() {
|
|
||||||
expect(linky("http://ab/ (http://a/) <http://a/> http://1.2/v:~-123. c")).
|
|
||||||
toEqual('<a href="http://ab/">http://ab/</a> ' +
|
|
||||||
'(<a href="http://a/">http://a/</a>) ' +
|
|
||||||
'<<a href="http://a/">http://a/</a>> ' +
|
|
||||||
'<a href="http://1.2/v:~-123">http://1.2/v:~-123</a>. c');
|
|
||||||
expect(linky(undefined)).not.toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should handle mailto:', function() {
|
|
||||||
expect(linky("mailto:me@example.com")).
|
|
||||||
toEqual('<a href="mailto:me@example.com">me@example.com</a>');
|
|
||||||
expect(linky("me@example.com")).
|
|
||||||
toEqual('<a href="mailto:me@example.com">me@example.com</a>');
|
|
||||||
expect(linky("send email to me@example.com, but")).
|
|
||||||
toEqual('send email to <a href="mailto:me@example.com">me@example.com</a>, but');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('date', function() {
|
describe('date', function() {
|
||||||
|
|
||||||
var morning = new angular.mock.TzDate(+5, '2010-09-03T12:05:08.000Z'); //7am
|
var morning = new angular.mock.TzDate(+5, '2010-09-03T12:05:08.000Z'); //7am
|
||||||
|
|
|
||||||
25
test/ngSanitize/directive/ngBindHtmlSpec.js
Normal file
25
test/ngSanitize/directive/ngBindHtmlSpec.js
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
describe('ngBindHtml', function() {
|
||||||
|
beforeEach(module('ngSanitize'));
|
||||||
|
|
||||||
|
it('should set html', inject(function($rootScope, $compile) {
|
||||||
|
element = $compile('<div ng-bind-html="html"></div>')($rootScope);
|
||||||
|
$rootScope.html = '<div unknown>hello</div>';
|
||||||
|
$rootScope.$digest();
|
||||||
|
expect(angular.lowercase(element.html())).toEqual('<div>hello</div>');
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should reset html when value is null or undefined', inject(function($compile, $rootScope) {
|
||||||
|
element = $compile('<div ng-bind-html="html"></div>')($rootScope);
|
||||||
|
|
||||||
|
angular.forEach([null, undefined, ''], function(val) {
|
||||||
|
$rootScope.html = 'some val';
|
||||||
|
$rootScope.$digest();
|
||||||
|
expect(angular.lowercase(element.html())).toEqual('some val');
|
||||||
|
|
||||||
|
$rootScope.html = val;
|
||||||
|
$rootScope.$digest();
|
||||||
|
expect(angular.lowercase(element.html())).toEqual('');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
});
|
||||||
27
test/ngSanitize/filter/linkySpec.js
Normal file
27
test/ngSanitize/filter/linkySpec.js
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
describe('linky', function() {
|
||||||
|
var linky;
|
||||||
|
|
||||||
|
beforeEach(module('ngSanitize'));
|
||||||
|
|
||||||
|
beforeEach(inject(function($filter){
|
||||||
|
linky = $filter('linky');
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should do basic filter', function() {
|
||||||
|
expect(linky("http://ab/ (http://a/) <http://a/> http://1.2/v:~-123. c")).
|
||||||
|
toEqual('<a href="http://ab/">http://ab/</a> ' +
|
||||||
|
'(<a href="http://a/">http://a/</a>) ' +
|
||||||
|
'<<a href="http://a/">http://a/</a>> ' +
|
||||||
|
'<a href="http://1.2/v:~-123">http://1.2/v:~-123</a>. c');
|
||||||
|
expect(linky(undefined)).not.toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle mailto:', function() {
|
||||||
|
expect(linky("mailto:me@example.com")).
|
||||||
|
toEqual('<a href="mailto:me@example.com">me@example.com</a>');
|
||||||
|
expect(linky("me@example.com")).
|
||||||
|
toEqual('<a href="mailto:me@example.com">me@example.com</a>');
|
||||||
|
expect(linky("send email to me@example.com, but")).
|
||||||
|
toEqual('send email to <a href="mailto:me@example.com">me@example.com</a>, but');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -4,6 +4,8 @@ describe('HTML', function() {
|
||||||
|
|
||||||
var expectHTML;
|
var expectHTML;
|
||||||
|
|
||||||
|
beforeEach(module('ngSanitize'));
|
||||||
|
|
||||||
beforeEach(inject(function($sanitize) {
|
beforeEach(inject(function($sanitize) {
|
||||||
expectHTML = function(html){
|
expectHTML = function(html){
|
||||||
return expect($sanitize(html));
|
return expect($sanitize(html));
|
||||||
|
|
@ -11,6 +13,8 @@ describe('HTML', function() {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('htmlParser', function() {
|
describe('htmlParser', function() {
|
||||||
|
if (angular.isUndefined(window.htmlParser)) return;
|
||||||
|
|
||||||
var handler, start, text;
|
var handler, start, text;
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
handler = {
|
handler = {
|
||||||
|
|
@ -22,8 +26,8 @@ describe('HTML', function() {
|
||||||
};
|
};
|
||||||
// Since different browsers handle newlines differenttly we trim
|
// Since different browsers handle newlines differenttly we trim
|
||||||
// so that it is easier to write tests.
|
// so that it is easier to write tests.
|
||||||
forEach(attrs, function(value, key){
|
angular.forEach(attrs, function(value, key) {
|
||||||
attrs[key] = trim(value);
|
attrs[key] = value.replace(/^\s*/, '').replace(/\s*$/, '')
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
chars: function(text_){
|
chars: function(text_){
|
||||||
|
|
@ -64,9 +68,9 @@ describe('HTML', function() {
|
||||||
expect(start).toEqual({tag:'option', attrs:{selected:'', value:''}, unary:false});
|
expect(start).toEqual({tag:'option', attrs:{selected:'', value:''}, unary:false});
|
||||||
expect(text).toEqual('abc');
|
expect(text).toEqual('abc');
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// THESE TESTS ARE EXECUTED WITH COMPILED ANGULAR
|
||||||
it('should echo html', function() {
|
it('should echo html', function() {
|
||||||
expectHTML('hello<b class="1\'23" align=\'""\'>world</b>.').
|
expectHTML('hello<b class="1\'23" align=\'""\'>world</b>.').
|
||||||
toEqual('hello<b class="1\'23" align="""">world</b>.');
|
toEqual('hello<b class="1\'23" align="""">world</b>.');
|
||||||
|
|
@ -141,6 +145,8 @@ describe('HTML', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('htmlSanitizerWriter', function() {
|
describe('htmlSanitizerWriter', function() {
|
||||||
|
if (angular.isUndefined(window.htmlSanitizeWriter)) return;
|
||||||
|
|
||||||
var writer, html;
|
var writer, html;
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
html = '';
|
html = '';
|
||||||
|
|
@ -277,5 +283,4 @@ describe('HTML', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
@ -9,6 +9,8 @@ describe("angular.scenario.dsl", function() {
|
||||||
dealoc(element);
|
dealoc(element);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
beforeEach(module('ngSanitize'));
|
||||||
|
|
||||||
beforeEach(inject(function($injector) {
|
beforeEach(inject(function($injector) {
|
||||||
eventLog = [];
|
eventLog = [];
|
||||||
$window = {
|
$window = {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue