Version 1.2.1 of Angular-Sanitize
This commit is contained in:
		
							
								
								
									
										9
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
*.pyc
 | 
			
		||||
*.sw?
 | 
			
		||||
*.sqlite3
 | 
			
		||||
.DS_STORE
 | 
			
		||||
*.egg-info
 | 
			
		||||
.venv
 | 
			
		||||
.tox
 | 
			
		||||
build
 | 
			
		||||
dist
 | 
			
		||||
							
								
								
									
										8
									
								
								MANIFEST.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								MANIFEST.in
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
include README.txt
 | 
			
		||||
recursive-include xstatic/pkg/angular_sanitize *
 | 
			
		||||
 | 
			
		||||
global-exclude *.pyc
 | 
			
		||||
global-exclude *.pyo
 | 
			
		||||
global-exclude *.orig
 | 
			
		||||
global-exclude *.rej
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								README.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								README.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
XStatic-Angular-Sanitize
 | 
			
		||||
------------------------
 | 
			
		||||
 | 
			
		||||
Angular-Sanitize JavaScript library packaged for setuptools (easy_install) / pip.
 | 
			
		||||
 | 
			
		||||
This package is intended to be used by **any** project that needs these files.
 | 
			
		||||
 | 
			
		||||
It intentionally does **not** provide any extra code except some metadata
 | 
			
		||||
**nor** has any extra requirements. You MAY use some minimal support code from
 | 
			
		||||
the XStatic base package, if you like.
 | 
			
		||||
 | 
			
		||||
You can find more info about the xstatic packaging way in the package `XStatic`.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										27
									
								
								setup.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								setup.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
from xstatic.pkg import angular_sanitize as xs
 | 
			
		||||
 | 
			
		||||
# The README.txt file should be written in reST so that PyPI can use
 | 
			
		||||
# it to generate your project's PyPI page. 
 | 
			
		||||
long_description = open('README.txt').read()
 | 
			
		||||
 | 
			
		||||
from setuptools import setup, find_packages
 | 
			
		||||
 | 
			
		||||
setup(
 | 
			
		||||
    name=xs.PACKAGE_NAME,
 | 
			
		||||
    version=xs.PACKAGE_VERSION,
 | 
			
		||||
    description=xs.DESCRIPTION,
 | 
			
		||||
    long_description=long_description,
 | 
			
		||||
    classifiers=xs.CLASSIFIERS,
 | 
			
		||||
    keywords=xs.KEYWORDS,
 | 
			
		||||
    maintainer=xs.MAINTAINER,
 | 
			
		||||
    maintainer_email=xs.MAINTAINER_EMAIL,
 | 
			
		||||
    license=xs.LICENSE,
 | 
			
		||||
    url=xs.HOMEPAGE,
 | 
			
		||||
    platforms=xs.PLATFORMS,
 | 
			
		||||
    packages=find_packages(),
 | 
			
		||||
    namespace_packages=['xstatic', 'xstatic.pkg', ],
 | 
			
		||||
    include_package_data=True,
 | 
			
		||||
    zip_safe=False,
 | 
			
		||||
    install_requires=[],  # nothing! :)
 | 
			
		||||
                          # if you like, you MAY use the 'XStatic' package.
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										1
									
								
								xstatic/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								xstatic/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
__import__('pkg_resources').declare_namespace(__name__)
 | 
			
		||||
							
								
								
									
										1
									
								
								xstatic/pkg/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								xstatic/pkg/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
__import__('pkg_resources').declare_namespace(__name__)
 | 
			
		||||
							
								
								
									
										49
									
								
								xstatic/pkg/angular_sanitize/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								xstatic/pkg/angular_sanitize/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
"""
 | 
			
		||||
XStatic resource package
 | 
			
		||||
 | 
			
		||||
See package 'XStatic' for documentation and basic tools.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
DISPLAY_NAME = 'Angular-Sanitize' # official name, upper/lowercase allowed, no spaces
 | 
			
		||||
PACKAGE_NAME = 'XStatic-%s' % DISPLAY_NAME # name used for PyPi
 | 
			
		||||
 | 
			
		||||
NAME = __name__.split('.')[-1] # package name (e.g. 'foo' or 'foo_bar')
 | 
			
		||||
                               # please use a all-lowercase valid python
 | 
			
		||||
                               # package name
 | 
			
		||||
 | 
			
		||||
VERSION = '1.2.1' # version of the packaged files, please use the upstream
 | 
			
		||||
                  # version number
 | 
			
		||||
BUILD = '1' # our package build number, so we can release new builds
 | 
			
		||||
             # with fixes for xstatic stuff.
 | 
			
		||||
PACKAGE_VERSION = VERSION + '.' + BUILD # version used for PyPi
 | 
			
		||||
 | 
			
		||||
DESCRIPTION = "%s %s (XStatic packaging standard)" % (DISPLAY_NAME, VERSION)
 | 
			
		||||
 | 
			
		||||
PLATFORMS = 'any'
 | 
			
		||||
CLASSIFIERS = []
 | 
			
		||||
KEYWORDS = '%s xstatic' % NAME
 | 
			
		||||
 | 
			
		||||
# XStatic-* package maintainer:
 | 
			
		||||
MAINTAINER = 'Maxime Vidori'
 | 
			
		||||
MAINTAINER_EMAIL = 'maxime.vidori@enovance.com'
 | 
			
		||||
 | 
			
		||||
# this refers to the project homepage of the stuff we packaged:
 | 
			
		||||
HOMEPAGE = 'http://angularjs.org'
 | 
			
		||||
 | 
			
		||||
# this refers to all files:
 | 
			
		||||
LICENSE = '(same as %s)' % DISPLAY_NAME
 | 
			
		||||
 | 
			
		||||
from os.path import join, dirname
 | 
			
		||||
BASE_DIR = join(dirname(__file__), 'data')
 | 
			
		||||
# linux package maintainers just can point to their file locations like this:
 | 
			
		||||
#BASE_DIR = '/usr/share/javascript/angular_cookies'
 | 
			
		||||
 | 
			
		||||
LOCATIONS = {
 | 
			
		||||
    # CDN locations (if no public CDN exists, use an empty dict)
 | 
			
		||||
    # if value is a string, it is a base location, just append relative
 | 
			
		||||
    # path/filename. if value is a dict, do another lookup using the
 | 
			
		||||
    # relative path/filename you want.
 | 
			
		||||
    # your relative path/filenames should usually be without version
 | 
			
		||||
    # information, because either the base dir/url is exactly for this
 | 
			
		||||
    # version or the mapping will care for accessing this version.
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										577
									
								
								xstatic/pkg/angular_sanitize/data/angular-sanitize.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										577
									
								
								xstatic/pkg/angular_sanitize/data/angular-sanitize.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							@@ -0,0 +1,577 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @license AngularJS v1.2.1
 | 
			
		||||
 * (c) 2010-2012 Google, Inc. http://angularjs.org
 | 
			
		||||
 * License: MIT
 | 
			
		||||
 */
 | 
			
		||||
(function(window, angular, undefined) {'use strict';
 | 
			
		||||
 | 
			
		||||
var $sanitizeMinErr = angular.$$minErr('$sanitize');
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @ngdoc overview
 | 
			
		||||
 * @name ngSanitize
 | 
			
		||||
 * @description
 | 
			
		||||
 *
 | 
			
		||||
 * # ngSanitize
 | 
			
		||||
 *
 | 
			
		||||
 * The `ngSanitize` module provides functionality to sanitize HTML.
 | 
			
		||||
 *
 | 
			
		||||
 * {@installModule sanitize}
 | 
			
		||||
 *
 | 
			
		||||
 * <div doc-module-components="ngSanitize"></div>
 | 
			
		||||
 *
 | 
			
		||||
 * See {@link ngSanitize.$sanitize `$sanitize`} for usage.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * HTML Parser By Misko Hevery (misko@hevery.com)
 | 
			
		||||
 * based on:  HTML Parser By John Resig (ejohn.org)
 | 
			
		||||
 * Original code by Erik Arvidsson, Mozilla Public License
 | 
			
		||||
 * http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
 | 
			
		||||
 *
 | 
			
		||||
 * // Use like so:
 | 
			
		||||
 * htmlParser(htmlString, {
 | 
			
		||||
 *     start: function(tag, attrs, unary) {},
 | 
			
		||||
 *     end: function(tag) {},
 | 
			
		||||
 *     chars: function(text) {},
 | 
			
		||||
 *     comment: function(text) {}
 | 
			
		||||
 * });
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @ngdoc service
 | 
			
		||||
 * @name ngSanitize.$sanitize
 | 
			
		||||
 * @function
 | 
			
		||||
 *
 | 
			
		||||
 * @description
 | 
			
		||||
 *   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.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {string} html Html input.
 | 
			
		||||
 * @returns {string} Sanitized html.
 | 
			
		||||
 *
 | 
			
		||||
 * @example
 | 
			
		||||
   <doc:example module="ngSanitize">
 | 
			
		||||
   <doc:source>
 | 
			
		||||
     <script>
 | 
			
		||||
       function Ctrl($scope, $sce) {
 | 
			
		||||
         $scope.snippet =
 | 
			
		||||
           '<p style="color:blue">an html\n' +
 | 
			
		||||
           '<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' +
 | 
			
		||||
           'snippet</p>';
 | 
			
		||||
         $scope.deliberatelyTrustDangerousSnippet = function() {
 | 
			
		||||
           return $sce.trustAsHtml($scope.snippet);
 | 
			
		||||
         };
 | 
			
		||||
       }
 | 
			
		||||
     </script>
 | 
			
		||||
     <div ng-controller="Ctrl">
 | 
			
		||||
        Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
 | 
			
		||||
       <table>
 | 
			
		||||
         <tr>
 | 
			
		||||
           <td>Directive</td>
 | 
			
		||||
           <td>How</td>
 | 
			
		||||
           <td>Source</td>
 | 
			
		||||
           <td>Rendered</td>
 | 
			
		||||
         </tr>
 | 
			
		||||
         <tr id="bind-html-with-sanitize">
 | 
			
		||||
           <td>ng-bind-html</td>
 | 
			
		||||
           <td>Automatically uses $sanitize</td>
 | 
			
		||||
           <td><pre><div ng-bind-html="snippet"><br/></div></pre></td>
 | 
			
		||||
           <td><div ng-bind-html="snippet"></div></td>
 | 
			
		||||
         </tr>
 | 
			
		||||
         <tr id="bind-html-with-trust">
 | 
			
		||||
           <td>ng-bind-html</td>
 | 
			
		||||
           <td>Bypass $sanitize by explicitly trusting the dangerous value</td>
 | 
			
		||||
           <td>
 | 
			
		||||
           <pre><div ng-bind-html="deliberatelyTrustDangerousSnippet()">
 | 
			
		||||
</div></pre>
 | 
			
		||||
           </td>
 | 
			
		||||
           <td><div ng-bind-html="deliberatelyTrustDangerousSnippet()"></div></td>
 | 
			
		||||
         </tr>
 | 
			
		||||
         <tr id="bind-default">
 | 
			
		||||
           <td>ng-bind</td>
 | 
			
		||||
           <td>Automatically escapes</td>
 | 
			
		||||
           <td><pre><div ng-bind="snippet"><br/></div></pre></td>
 | 
			
		||||
           <td><div ng-bind="snippet"></div></td>
 | 
			
		||||
         </tr>
 | 
			
		||||
       </table>
 | 
			
		||||
       </div>
 | 
			
		||||
   </doc:source>
 | 
			
		||||
   <doc:scenario>
 | 
			
		||||
     it('should sanitize the html snippet by default', function() {
 | 
			
		||||
       expect(using('#bind-html-with-sanitize').element('div').html()).
 | 
			
		||||
         toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
 | 
			
		||||
     });
 | 
			
		||||
 | 
			
		||||
     it('should inline raw snippet if bound to a trusted value', function() {
 | 
			
		||||
       expect(using('#bind-html-with-trust').element("div").html()).
 | 
			
		||||
         toBe("<p style=\"color:blue\">an html\n" +
 | 
			
		||||
              "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
 | 
			
		||||
              "snippet</p>");
 | 
			
		||||
     });
 | 
			
		||||
 | 
			
		||||
     it('should escape snippet without any filter', function() {
 | 
			
		||||
       expect(using('#bind-default').element('div').html()).
 | 
			
		||||
         toBe("<p style=\"color:blue\">an html\n" +
 | 
			
		||||
              "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
 | 
			
		||||
              "snippet</p>");
 | 
			
		||||
     });
 | 
			
		||||
 | 
			
		||||
     it('should update', function() {
 | 
			
		||||
       input('snippet').enter('new <b onclick="alert(1)">text</b>');
 | 
			
		||||
       expect(using('#bind-html-with-sanitize').element('div').html()).toBe('new <b>text</b>');
 | 
			
		||||
       expect(using('#bind-html-with-trust').element('div').html()).toBe(
 | 
			
		||||
         'new <b onclick="alert(1)">text</b>');
 | 
			
		||||
       expect(using('#bind-default').element('div').html()).toBe(
 | 
			
		||||
         "new <b onclick=\"alert(1)\">text</b>");
 | 
			
		||||
     });
 | 
			
		||||
   </doc:scenario>
 | 
			
		||||
   </doc:example>
 | 
			
		||||
 */
 | 
			
		||||
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*>/,
 | 
			
		||||
  END_TAG_REGEXP = /^<\s*\/\s*([\w:-]+)[^>]*>/,
 | 
			
		||||
  ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,
 | 
			
		||||
  BEGIN_TAG_REGEXP = /^</,
 | 
			
		||||
  BEGING_END_TAGE_REGEXP = /^<\s*\//,
 | 
			
		||||
  COMMENT_REGEXP = /<!--(.*?)-->/g,
 | 
			
		||||
  DOCTYPE_REGEXP = /<!DOCTYPE([^>]*?)>/i,
 | 
			
		||||
  CDATA_REGEXP = /<!\[CDATA\[(.*?)]]>/g,
 | 
			
		||||
  URI_REGEXP = /^((ftp|https?):\/\/|mailto:|tel:|#)/i,
 | 
			
		||||
  // Match everything outside of normal chars and " (quote character)
 | 
			
		||||
  NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Good source of info about elements and attributes
 | 
			
		||||
// http://dev.w3.org/html5/spec/Overview.html#semantics
 | 
			
		||||
// http://simon.html5.org/html-elements
 | 
			
		||||
 | 
			
		||||
// Safe Void Elements - HTML5
 | 
			
		||||
// http://dev.w3.org/html5/spec/Overview.html#void-elements
 | 
			
		||||
var voidElements = makeMap("area,br,col,hr,img,wbr");
 | 
			
		||||
 | 
			
		||||
// Elements that you can, intentionally, leave open (and which close themselves)
 | 
			
		||||
// 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 = angular.extend({},
 | 
			
		||||
                                            optionalEndTagInlineElements,
 | 
			
		||||
                                            optionalEndTagBlockElements);
 | 
			
		||||
 | 
			
		||||
// Safe Block Elements - HTML5
 | 
			
		||||
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 = 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"));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Special Elements (can contain anything)
 | 
			
		||||
var specialElements = makeMap("script,style");
 | 
			
		||||
 | 
			
		||||
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 = 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, {
 | 
			
		||||
 *     start: function(tag, attrs, unary) {},
 | 
			
		||||
 *     end: function(tag) {},
 | 
			
		||||
 *     chars: function(text) {},
 | 
			
		||||
 *     comment: function(text) {}
 | 
			
		||||
 * });
 | 
			
		||||
 *
 | 
			
		||||
 * @param {string} html string
 | 
			
		||||
 * @param {object} handler
 | 
			
		||||
 */
 | 
			
		||||
function htmlParser( html, handler ) {
 | 
			
		||||
  var index, chars, match, stack = [], last = html;
 | 
			
		||||
  stack.last = function() { return stack[ stack.length - 1 ]; };
 | 
			
		||||
 | 
			
		||||
  while ( html ) {
 | 
			
		||||
    chars = true;
 | 
			
		||||
 | 
			
		||||
    // Make sure we're not in a script or style element
 | 
			
		||||
    if ( !stack.last() || !specialElements[ stack.last() ] ) {
 | 
			
		||||
 | 
			
		||||
      // Comment
 | 
			
		||||
      if ( html.indexOf("<!--") === 0 ) {
 | 
			
		||||
        // comments containing -- are not allowed unless they terminate the comment
 | 
			
		||||
        index = html.indexOf("--", 4);
 | 
			
		||||
 | 
			
		||||
        if ( index >= 0 && html.lastIndexOf("-->", index) === index) {
 | 
			
		||||
          if (handler.comment) handler.comment( html.substring( 4, index ) );
 | 
			
		||||
          html = html.substring( index + 3 );
 | 
			
		||||
          chars = false;
 | 
			
		||||
        }
 | 
			
		||||
      // DOCTYPE
 | 
			
		||||
      } else if ( DOCTYPE_REGEXP.test(html) ) {
 | 
			
		||||
        match = html.match( DOCTYPE_REGEXP );
 | 
			
		||||
 | 
			
		||||
        if ( match ) {
 | 
			
		||||
          html = html.replace( match[0] , '');
 | 
			
		||||
          chars = false;
 | 
			
		||||
        }
 | 
			
		||||
      // end tag
 | 
			
		||||
      } else if ( BEGING_END_TAGE_REGEXP.test(html) ) {
 | 
			
		||||
        match = html.match( END_TAG_REGEXP );
 | 
			
		||||
 | 
			
		||||
        if ( match ) {
 | 
			
		||||
          html = html.substring( match[0].length );
 | 
			
		||||
          match[0].replace( END_TAG_REGEXP, parseEndTag );
 | 
			
		||||
          chars = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      // start tag
 | 
			
		||||
      } else if ( BEGIN_TAG_REGEXP.test(html) ) {
 | 
			
		||||
        match = html.match( START_TAG_REGEXP );
 | 
			
		||||
 | 
			
		||||
        if ( match ) {
 | 
			
		||||
          html = html.substring( match[0].length );
 | 
			
		||||
          match[0].replace( START_TAG_REGEXP, parseStartTag );
 | 
			
		||||
          chars = false;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if ( chars ) {
 | 
			
		||||
        index = html.indexOf("<");
 | 
			
		||||
 | 
			
		||||
        var text = index < 0 ? html : html.substring( 0, index );
 | 
			
		||||
        html = index < 0 ? "" : html.substring( index );
 | 
			
		||||
 | 
			
		||||
        if (handler.chars) handler.chars( decodeEntities(text) );
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
      html = html.replace(new RegExp("(.*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'),
 | 
			
		||||
        function(all, text){
 | 
			
		||||
          text = text.replace(COMMENT_REGEXP, "$1").replace(CDATA_REGEXP, "$1");
 | 
			
		||||
 | 
			
		||||
          if (handler.chars) handler.chars( decodeEntities(text) );
 | 
			
		||||
 | 
			
		||||
          return "";
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      parseEndTag( "", stack.last() );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ( html == last ) {
 | 
			
		||||
      throw $sanitizeMinErr('badparse', "The sanitizer was unable to parse the following block " +
 | 
			
		||||
                                        "of html: {0}", html);
 | 
			
		||||
    }
 | 
			
		||||
    last = html;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Clean up any remaining tags
 | 
			
		||||
  parseEndTag();
 | 
			
		||||
 | 
			
		||||
  function parseStartTag( tag, tagName, rest, unary ) {
 | 
			
		||||
    tagName = angular.lowercase(tagName);
 | 
			
		||||
    if ( blockElements[ tagName ] ) {
 | 
			
		||||
      while ( stack.last() && inlineElements[ stack.last() ] ) {
 | 
			
		||||
        parseEndTag( "", stack.last() );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ( optionalEndTagElements[ tagName ] && stack.last() == tagName ) {
 | 
			
		||||
      parseEndTag( "", tagName );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unary = voidElements[ tagName ] || !!unary;
 | 
			
		||||
 | 
			
		||||
    if ( !unary )
 | 
			
		||||
      stack.push( tagName );
 | 
			
		||||
 | 
			
		||||
    var attrs = {};
 | 
			
		||||
 | 
			
		||||
    rest.replace(ATTR_REGEXP,
 | 
			
		||||
      function(match, name, doubleQuotedValue, singleQuotedValue, unquotedValue) {
 | 
			
		||||
        var value = doubleQuotedValue
 | 
			
		||||
          || singleQuotedValue
 | 
			
		||||
          || unquotedValue
 | 
			
		||||
          || '';
 | 
			
		||||
 | 
			
		||||
        attrs[name] = decodeEntities(value);
 | 
			
		||||
    });
 | 
			
		||||
    if (handler.start) handler.start( tagName, attrs, unary );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function parseEndTag( tag, tagName ) {
 | 
			
		||||
    var pos = 0, i;
 | 
			
		||||
    tagName = angular.lowercase(tagName);
 | 
			
		||||
    if ( tagName )
 | 
			
		||||
      // Find the closest opened tag of the same type
 | 
			
		||||
      for ( pos = stack.length - 1; pos >= 0; pos-- )
 | 
			
		||||
        if ( stack[ pos ] == tagName )
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
    if ( pos >= 0 ) {
 | 
			
		||||
      // Close all the open elements, up the stack
 | 
			
		||||
      for ( i = stack.length - 1; i >= pos; i-- )
 | 
			
		||||
        if (handler.end) handler.end( stack[ i ] );
 | 
			
		||||
 | 
			
		||||
      // Remove the open elements from the stack
 | 
			
		||||
      stack.length = pos;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * decodes all entities into regular string
 | 
			
		||||
 * @param value
 | 
			
		||||
 * @returns {string} A string with decoded entities.
 | 
			
		||||
 */
 | 
			
		||||
var hiddenPre=document.createElement("pre");
 | 
			
		||||
function decodeEntities(value) {
 | 
			
		||||
  hiddenPre.innerHTML=value.replace(/</g,"<");
 | 
			
		||||
  return hiddenPre.innerText || hiddenPre.textContent || '';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Escapes all potentially dangerous characters, so that the
 | 
			
		||||
 * resulting string can be safely inserted into attribute or
 | 
			
		||||
 * element text.
 | 
			
		||||
 * @param value
 | 
			
		||||
 * @returns escaped text
 | 
			
		||||
 */
 | 
			
		||||
function encodeEntities(value) {
 | 
			
		||||
  return value.
 | 
			
		||||
    replace(/&/g, '&').
 | 
			
		||||
    replace(NON_ALPHANUMERIC_REGEXP, function(value){
 | 
			
		||||
      return '&#' + value.charCodeAt(0) + ';';
 | 
			
		||||
    }).
 | 
			
		||||
    replace(/</g, '<').
 | 
			
		||||
    replace(/>/g, '>');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * create an HTML/XML writer which writes to buffer
 | 
			
		||||
 * @param {Array} buf use buf.jain('') to get out sanitized html string
 | 
			
		||||
 * @returns {object} in the form of {
 | 
			
		||||
 *     start: function(tag, attrs, unary) {},
 | 
			
		||||
 *     end: function(tag) {},
 | 
			
		||||
 *     chars: function(text) {},
 | 
			
		||||
 *     comment: function(text) {}
 | 
			
		||||
 * }
 | 
			
		||||
 */
 | 
			
		||||
function htmlSanitizeWriter(buf){
 | 
			
		||||
  var ignore = false;
 | 
			
		||||
  var out = angular.bind(buf, buf.push);
 | 
			
		||||
  return {
 | 
			
		||||
    start: function(tag, attrs, unary){
 | 
			
		||||
      tag = angular.lowercase(tag);
 | 
			
		||||
      if (!ignore && specialElements[tag]) {
 | 
			
		||||
        ignore = tag;
 | 
			
		||||
      }
 | 
			
		||||
      if (!ignore && validElements[tag] === true) {
 | 
			
		||||
        out('<');
 | 
			
		||||
        out(tag);
 | 
			
		||||
        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);
 | 
			
		||||
            out('="');
 | 
			
		||||
            out(encodeEntities(value));
 | 
			
		||||
            out('"');
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
        out(unary ? '/>' : '>');
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    end: function(tag){
 | 
			
		||||
        tag = angular.lowercase(tag);
 | 
			
		||||
        if (!ignore && validElements[tag] === true) {
 | 
			
		||||
          out('</');
 | 
			
		||||
          out(tag);
 | 
			
		||||
          out('>');
 | 
			
		||||
        }
 | 
			
		||||
        if (tag == ignore) {
 | 
			
		||||
          ignore = false;
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
    chars: function(chars){
 | 
			
		||||
        if (!ignore) {
 | 
			
		||||
          out(encodeEntities(chars));
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// define ngSanitize module and register $sanitize service
 | 
			
		||||
angular.module('ngSanitize', []).value('$sanitize', $sanitize);
 | 
			
		||||
 | 
			
		||||
/* global htmlSanitizeWriter: false */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @ngdoc filter
 | 
			
		||||
 * @name 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.
 | 
			
		||||
 *
 | 
			
		||||
 * Requires the {@link ngSanitize `ngSanitize`} module to be installed.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {string} text Input text.
 | 
			
		||||
 * @param {string} target Window (_blank|_self|_parent|_top) or named frame to open links in.
 | 
			
		||||
 * @returns {string} Html-linkified text.
 | 
			
		||||
 *
 | 
			
		||||
 * @usage
 | 
			
		||||
   <span ng-bind-html="linky_expression | linky"></span>
 | 
			
		||||
 *
 | 
			
		||||
 * @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/.';
 | 
			
		||||
           $scope.snippetWithTarget = 'http://angularjs.org/';
 | 
			
		||||
         }
 | 
			
		||||
       </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="linky-target">
 | 
			
		||||
          <td>linky target</td>
 | 
			
		||||
          <td>
 | 
			
		||||
            <pre><div ng-bind-html="snippetWithTarget | linky:'_blank'"><br></div></pre>
 | 
			
		||||
          </td>
 | 
			
		||||
          <td>
 | 
			
		||||
            <div ng-bind-html="snippetWithTarget | linky:'_blank'"></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.');
 | 
			
		||||
       });
 | 
			
		||||
 | 
			
		||||
       it('should work with the target property', function() {
 | 
			
		||||
        expect(using('#linky-target').binding("snippetWithTarget | linky:'_blank'")).
 | 
			
		||||
          toBe('<a target="_blank" href="http://angularjs.org/">http://angularjs.org/</a>');
 | 
			
		||||
       });
 | 
			
		||||
     </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, target) {
 | 
			
		||||
    if (!text) return text;
 | 
			
		||||
    var match;
 | 
			
		||||
    var raw = text;
 | 
			
		||||
    var html = [];
 | 
			
		||||
    // TODO(vojta): use $sanitize instead
 | 
			
		||||
    var writer = htmlSanitizeWriter(html);
 | 
			
		||||
    var url;
 | 
			
		||||
    var i;
 | 
			
		||||
    var properties = {};
 | 
			
		||||
    if (angular.isDefined(target)) {
 | 
			
		||||
      properties.target = target;
 | 
			
		||||
    }
 | 
			
		||||
    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));
 | 
			
		||||
      properties.href = url;
 | 
			
		||||
      writer.start('a', properties);
 | 
			
		||||
      writer.chars(match[0].replace(MAILTO_REGEXP, ''));
 | 
			
		||||
      writer.end('a');
 | 
			
		||||
      raw = raw.substring(i + match[0].length);
 | 
			
		||||
    }
 | 
			
		||||
    writer.chars(raw);
 | 
			
		||||
    return html.join('');
 | 
			
		||||
  };
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
})(window, window.angular);
 | 
			
		||||
		Reference in New Issue
	
	Block a user