diff --git a/Rakefile b/Rakefile index 3033d62d7044..7b5872d3b37d 100644 --- a/Rakefile +++ b/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 diff --git a/angularFiles.js b/angularFiles.js index c819b629df69..d8be657aed0a 100644 --- a/angularFiles.js +++ b/angularFiles.js @@ -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': [ diff --git a/docs/content/cookbook/deeplinking.ngdoc b/docs/content/cookbook/deeplinking.ngdoc index 10af8a2d1d62..4343ded2240c 100644 --- a/docs/content/cookbook/deeplinking.ngdoc +++ b/docs/content/cookbook/deeplinking.ngdoc @@ -39,7 +39,7 @@ The two partials are defined in the following URLs: -
- Snippet: - - - - - - - - - - - - - - - - -
FilterSourceRendered
linky filter -
<div ng-bind-html="snippet | linky">
</div>
-
-
-
no filter
<div ng-bind="snippet">
</div>
- - - it('should linkify the snippet with urls', function() { - expect(using('#linky-filter').binding('snippet | linky')). - toBe('Pretty text with some links: ' + - 'http://angularjs.org/, ' + - 'us@somewhere.org, ' + - 'another@somewhere.org, ' + - 'and one more: ftp://127.0.0.1/.'); - }); - - 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 http://link.'); - expect(using('#escaped-html').binding('snippet')).toBe('new http://link.'); - }); - - - */ -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(''); - }; -} diff --git a/src/ngSanitize/directive/ngBindHtml.js b/src/ngSanitize/directive/ngBindHtml.js new file mode 100644 index 000000000000..f8ccef187b4c --- /dev/null +++ b/src/ngSanitize/directive/ngBindHtml.js @@ -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 || ''); + }); + }; +}]); diff --git a/src/ngSanitize/filter/linky.js b/src/ngSanitize/filter/linky.js new file mode 100644 index 000000000000..c30665a2d68d --- /dev/null +++ b/src/ngSanitize/filter/linky.js @@ -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 + + + +
+ Snippet: + + + + + + + + + + + + + + + + +
FilterSourceRendered
linky filter +
<div ng-bind-html="snippet | linky">
</div>
+
+
+
no filter
<div ng-bind="snippet">
</div>
+ + + it('should linkify the snippet with urls', function() { + expect(using('#linky-filter').binding('snippet | linky')). + toBe('Pretty text with some links: ' + + 'http://angularjs.org/, ' + + 'us@somewhere.org, ' + + 'another@somewhere.org, ' + + 'and one more: ftp://127.0.0.1/.'); + }); + + 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 http://link.'); + expect(using('#escaped-html').binding('snippet')).toBe('new http://link.'); + }); + + + */ +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(''); + }; +}); diff --git a/src/ng/sanitize.js b/src/ngSanitize/sanitize.js similarity index 90% rename from src/ng/sanitize.js rename to src/ngSanitize/sanitize.js index 6a7a2be422c9..c8d28315c27e 100644 --- a/src/ng/sanitize.js +++ b/src/ngSanitize/sanitize.js @@ -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 - +