mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-01-13 08:59:54 +08: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:
24
Rakefile
24
Rakefile
@@ -82,15 +82,23 @@ task :compile => [:init, :compile_scenario, :compile_jstd_scenario_adapter] do
|
||||
'src/loader.js',
|
||||
'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-cookies.js')
|
||||
closure_compile('angular-loader.js')
|
||||
closure_compile('angular-resource.js')
|
||||
closure_compile('angular-sanitize.js')
|
||||
|
||||
end
|
||||
|
||||
@@ -121,6 +129,8 @@ task :package => [:clean, :compile, :docs] do
|
||||
path_to('angular-cookies.min.js'),
|
||||
path_to('angular-resource.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('jstd-scenario-adapter.js'),
|
||||
path_to('jstd-scenario-adapter-config.js'),
|
||||
@@ -147,7 +157,8 @@ task :package => [:clean, :compile, :docs] do
|
||||
rewrite_file(src) do |content|
|
||||
content.sub!('angular.js', "angular-#{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
|
||||
|
||||
@@ -290,6 +301,11 @@ def concat_file(filename, deps, footer='')
|
||||
end
|
||||
|
||||
|
||||
def concat_module(name, files)
|
||||
concat_file('angular-' + name + '.js', ['src/module.prefix'] + files + ['src/module.suffix'])
|
||||
end
|
||||
|
||||
|
||||
def rewrite_file(filename)
|
||||
File.open(filename, File::RDWR) do |f|
|
||||
content = f.read
|
||||
|
||||
15
angularFiles.js
vendored
15
angularFiles.js
vendored
@@ -24,7 +24,6 @@ angularFiles = {
|
||||
'src/ng/route.js',
|
||||
'src/ng/routeParams.js',
|
||||
'src/ng/rootScope.js',
|
||||
'src/ng/sanitize.js',
|
||||
'src/ng/sniffer.js',
|
||||
'src/ng/window.js',
|
||||
'src/ng/http.js',
|
||||
@@ -65,6 +64,9 @@ angularFiles = {
|
||||
'angularSrcModules': [
|
||||
'src/ngCookies/cookies.js',
|
||||
'src/ngResource/resource.js',
|
||||
'src/ngSanitize/sanitize.js',
|
||||
'src/ngSanitize/directive/ngBindHtml.js',
|
||||
'src/ngSanitize/filter/linky.js',
|
||||
'src/ngMock/angular-mocks.js'
|
||||
],
|
||||
|
||||
@@ -98,6 +100,9 @@ angularFiles = {
|
||||
'test/ng/filter/*.js',
|
||||
'test/ngCookies/*.js',
|
||||
'test/ngResource/*.js',
|
||||
'test/ngSanitize/*.js',
|
||||
'test/ngSanitize/directive/*.js',
|
||||
'test/ngSanitize/filter/*.js',
|
||||
'test/ngMock/*.js'
|
||||
],
|
||||
|
||||
@@ -136,10 +141,16 @@ angularFiles = {
|
||||
'src/ngMock/angular-mocks.js',
|
||||
'src/ngCookies/cookies.js',
|
||||
'src/ngResource/resource.js',
|
||||
'src/ngSanitize/sanitize.js',
|
||||
'src/ngSanitize/directive/ngBindHtml.js',
|
||||
'src/ngSanitize/filter/linky.js',
|
||||
'test/matchers.js',
|
||||
'test/ngMock/*.js',
|
||||
'test/ngCookies/*.js',
|
||||
'test/ngResource/*.js'
|
||||
'test/ngResource/*.js',
|
||||
'test/ngSanitize/*.js',
|
||||
'test/ngSanitize/directive/*.js',
|
||||
'test/ngSanitize/filter/*.js'
|
||||
],
|
||||
|
||||
'jstdPerf': [
|
||||
|
||||
@@ -39,7 +39,7 @@ The two partials are defined in the following URLs:
|
||||
<doc:example module="deepLinking">
|
||||
<doc:source jsfiddle="false">
|
||||
<script>
|
||||
angular.module('deepLinking', [])
|
||||
angular.module('deepLinking', ['ngSanitize'])
|
||||
.config(function($routeProvider) {
|
||||
$routeProvider.when("/welcome", {template:'./examples/welcome.html', controller:WelcomeCntl});
|
||||
$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('!');
|
||||
|
||||
$filterProvider.register('title', function(){
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
addTag('script', {src: path('angular.js')}, sync);
|
||||
addTag('script', {src: path('angular-resource.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-keywords.js'}, sync);
|
||||
|
||||
|
||||
@@ -71,7 +71,6 @@ function publishExternalAPI(angular){
|
||||
style: styleDirective,
|
||||
option: optionDirective,
|
||||
ngBind: ngBindDirective,
|
||||
ngBindHtml: ngBindHtmlDirective,
|
||||
ngBindHtmlUnsafe: ngBindHtmlUnsafeDirective,
|
||||
ngBindTemplate: ngBindTemplateDirective,
|
||||
ngClass: ngClassDirective,
|
||||
@@ -123,7 +122,6 @@ function publishExternalAPI(angular){
|
||||
$routeParams: $RouteParamsProvider,
|
||||
$rootScope: $RootScopeProvider,
|
||||
$q: $QProvider,
|
||||
$sanitize: $SanitizeProvider,
|
||||
$sniffer: $SnifferProvider,
|
||||
$templateCache: $TemplateCacheProvider,
|
||||
$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
|
||||
* @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('json', jsonFilter);
|
||||
register('limitTo', limitToFilter);
|
||||
register('linky', linkyFilter);
|
||||
register('lowercase', lowercaseFilter);
|
||||
register('number', numberFilter);
|
||||
register('orderBy', orderByFilter);
|
||||
|
||||
@@ -439,110 +439,3 @@ var lowercaseFilter = valueFn(lowercase);
|
||||
* @see angular.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';
|
||||
|
||||
/**
|
||||
* @ngdoc overview
|
||||
* @name angular.module.ngSanitize
|
||||
* @description
|
||||
*/
|
||||
|
||||
/*
|
||||
* HTML Parser By Misko Hevery (misko@hevery.com)
|
||||
* based on: HTML Parser By John Resig (ejohn.org)
|
||||
@@ -17,10 +23,9 @@
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name angular.module.ng.$sanitize
|
||||
* @name angular.module.ngSanitize.$sanitize
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
@@ -34,7 +39,7 @@
|
||||
* @returns {string} Sanitized html.
|
||||
*
|
||||
* @example
|
||||
<doc:example>
|
||||
<doc:example module="ngSanitize">
|
||||
<doc:source>
|
||||
<script>
|
||||
function Ctrl($scope) {
|
||||
@@ -103,14 +108,12 @@
|
||||
</doc:scenario>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
function $SanitizeProvider() {
|
||||
this.$get = valueFn(function(html) {
|
||||
var buf = [];
|
||||
var $sanitize = function(html) {
|
||||
var buf = [];
|
||||
htmlParser(html, htmlSanitizeWriter(buf));
|
||||
return buf.join('');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Regular Expressions for parsing tags and attributes
|
||||
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
|
||||
var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),
|
||||
optionalEndTagInlineElements = makeMap("rp,rt"),
|
||||
optionalEndTagElements = extend({}, optionalEndTagInlineElements, optionalEndTagBlockElements);
|
||||
optionalEndTagElements = angular.extend({}, optionalEndTagInlineElements, optionalEndTagBlockElements);
|
||||
|
||||
// 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," +
|
||||
"header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul"));
|
||||
|
||||
// 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," +
|
||||
"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)
|
||||
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
|
||||
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,'+
|
||||
'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,'+
|
||||
'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,'+
|
||||
'scope,scrolling,shape,span,start,summary,target,title,type,'+
|
||||
'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
|
||||
* htmlParser(htmlString, {
|
||||
@@ -249,7 +259,7 @@ function htmlParser( html, handler ) {
|
||||
parseEndTag();
|
||||
|
||||
function parseStartTag( tag, tagName, rest, unary ) {
|
||||
tagName = lowercase(tagName);
|
||||
tagName = angular.lowercase(tagName);
|
||||
if ( blockElements[ tagName ] ) {
|
||||
while ( stack.last() && inlineElements[ stack.last() ] ) {
|
||||
parseEndTag( "", stack.last() );
|
||||
@@ -280,7 +290,7 @@ function htmlParser( html, handler ) {
|
||||
|
||||
function parseEndTag( tag, tagName ) {
|
||||
var pos = 0, i;
|
||||
tagName = lowercase(tagName);
|
||||
tagName = angular.lowercase(tagName);
|
||||
if ( tagName )
|
||||
// Find the closest opened tag of the same type
|
||||
for ( pos = stack.length - 1; pos >= 0; pos-- )
|
||||
@@ -338,18 +348,18 @@ function encodeEntities(value) {
|
||||
*/
|
||||
function htmlSanitizeWriter(buf){
|
||||
var ignore = false;
|
||||
var out = bind(buf, buf.push);
|
||||
var out = angular.bind(buf, buf.push);
|
||||
return {
|
||||
start: function(tag, attrs, unary){
|
||||
tag = lowercase(tag);
|
||||
tag = angular.lowercase(tag);
|
||||
if (!ignore && specialElements[tag]) {
|
||||
ignore = tag;
|
||||
}
|
||||
if (!ignore && validElements[tag] == true) {
|
||||
out('<');
|
||||
out(tag);
|
||||
forEach(attrs, function(value, key){
|
||||
var lkey=lowercase(key);
|
||||
angular.forEach(attrs, function(value, key){
|
||||
var lkey=angular.lowercase(key);
|
||||
if (validAttrs[lkey]==true && (uriAttrs[lkey]!==true || value.match(URI_REGEXP))) {
|
||||
out(' ');
|
||||
out(key);
|
||||
@@ -362,7 +372,7 @@ function htmlSanitizeWriter(buf){
|
||||
}
|
||||
},
|
||||
end: function(tag){
|
||||
tag = lowercase(tag);
|
||||
tag = angular.lowercase(tag);
|
||||
if (!ignore && validElements[tag] == true) {
|
||||
out('</');
|
||||
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() {
|
||||
|
||||
it('should set unsafe html', inject(function($rootScope, $compile) {
|
||||
element = $compile('<div ng-bind-html-unsafe="html"></div>')($rootScope);
|
||||
$rootScope.html = '<div onclick="">hello</div>';
|
||||
$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() {
|
||||
|
||||
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;
|
||||
|
||||
beforeEach(module('ngSanitize'));
|
||||
|
||||
beforeEach(inject(function($sanitize) {
|
||||
expectHTML = function(html){
|
||||
return expect($sanitize(html));
|
||||
@@ -11,6 +13,8 @@ describe('HTML', function() {
|
||||
}));
|
||||
|
||||
describe('htmlParser', function() {
|
||||
if (angular.isUndefined(window.htmlParser)) return;
|
||||
|
||||
var handler, start, text;
|
||||
beforeEach(function() {
|
||||
handler = {
|
||||
@@ -22,8 +26,8 @@ describe('HTML', function() {
|
||||
};
|
||||
// Since different browsers handle newlines differenttly we trim
|
||||
// so that it is easier to write tests.
|
||||
forEach(attrs, function(value, key){
|
||||
attrs[key] = trim(value);
|
||||
angular.forEach(attrs, function(value, key) {
|
||||
attrs[key] = value.replace(/^\s*/, '').replace(/\s*$/, '')
|
||||
});
|
||||
},
|
||||
chars: function(text_){
|
||||
@@ -64,9 +68,9 @@ describe('HTML', function() {
|
||||
expect(start).toEqual({tag:'option', attrs:{selected:'', value:''}, unary:false});
|
||||
expect(text).toEqual('abc');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// THESE TESTS ARE EXECUTED WITH COMPILED ANGULAR
|
||||
it('should echo html', function() {
|
||||
expectHTML('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() {
|
||||
if (angular.isUndefined(window.htmlSanitizeWriter)) return;
|
||||
|
||||
var writer, html;
|
||||
beforeEach(function() {
|
||||
html = '';
|
||||
@@ -277,5 +283,4 @@ describe('HTML', function() {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -9,6 +9,8 @@ describe("angular.scenario.dsl", function() {
|
||||
dealoc(element);
|
||||
});
|
||||
|
||||
beforeEach(module('ngSanitize'));
|
||||
|
||||
beforeEach(inject(function($injector) {
|
||||
eventLog = [];
|
||||
$window = {
|
||||
|
||||
Reference in New Issue
Block a user