Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
A
angular-sanitize
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Custom Issue Tracker
Custom Issue Tracker
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
angularjs
angular-sanitize
Commits
68fa4f84
Commit
68fa4f84
authored
Aug 03, 2018
by
bingchuan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[dev] version 1.5.7
parents
Pipeline
#47
failed with stages
Changes
2
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
727 additions
and
0 deletions
+727
-0
angular-sanitize.js
angular-sanitize.js
+717
-0
bower.json
bower.json
+10
-0
No files found.
angular-sanitize.js
0 → 100644
View file @
68fa4f84
/**
* @license AngularJS v1.5.7
* (c) 2010-2016 Google, Inc. http://angularjs.org
* License: MIT
*/
(
function
(
window
,
angular
)
{
'use strict'
;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Any commits to this file should be reviewed with security in mind. *
* Changes to this file can potentially create security vulnerabilities. *
* An approval from 2 Core members with history of modifying *
* this file is required. *
* *
* Does the change somehow allow for arbitrary javascript to be executed? *
* Or allows for someone to change the prototype of built-in objects? *
* Or gives undesired access to variables likes document or window? *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
var
$sanitizeMinErr
=
angular
.
$$minErr
(
'$sanitize'
);
/**
* @ngdoc module
* @name ngSanitize
* @description
*
* # ngSanitize
*
* The `ngSanitize` module provides functionality to sanitize HTML.
*
*
* <div doc-module-components="ngSanitize"></div>
*
* See {@link ngSanitize.$sanitize `$sanitize`} for usage.
*/
/**
* @ngdoc service
* @name $sanitize
* @kind function
*
* @description
* Sanitizes an html string by stripping all potentially dangerous tokens.
*
* 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.
*
* The whitelist for URL sanitization of attribute values is configured using the functions
* `aHrefSanitizationWhitelist` and `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider
* `$compileProvider`}.
*
* The input may also contain SVG markup if this is enabled via {@link $sanitizeProvider}.
*
* @param {string} html HTML input.
* @returns {string} Sanitized HTML.
*
* @example
<example module="sanitizeExample" deps="angular-sanitize.js">
<file name="index.html">
<script>
angular.module('sanitizeExample', ['ngSanitize'])
.controller('ExampleController', ['$scope', '$sce', function($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="ExampleController">
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>
</file>
<file name="protractor.js" type="protractor">
it('should sanitize the html snippet by default', function() {
expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
});
it('should inline raw snippet if bound to a trusted value', function() {
expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).
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(element(by.css('#bind-default div')).getInnerHtml()).
toBe("<p style=\"color:blue\">an html\n" +
"<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
"snippet</p>");
});
it('should update', function() {
element(by.model('snippet')).clear();
element(by.model('snippet')).sendKeys('new <b onclick="alert(1)">text</b>');
expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
toBe('new <b>text</b>');
expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).toBe(
'new <b onclick="alert(1)">text</b>');
expect(element(by.css('#bind-default div')).getInnerHtml()).toBe(
"new <b onclick=\"alert(1)\">text</b>");
});
</file>
</example>
*/
/**
* @ngdoc provider
* @name $sanitizeProvider
*
* @description
* Creates and configures {@link $sanitize} instance.
*/
function
$SanitizeProvider
()
{
var
svgEnabled
=
false
;
this
.
$get
=
[
'$$sanitizeUri'
,
function
(
$$sanitizeUri
)
{
if
(
svgEnabled
)
{
angular
.
extend
(
validElements
,
svgElements
);
}
return
function
(
html
)
{
var
buf
=
[];
htmlParser
(
html
,
htmlSanitizeWriter
(
buf
,
function
(
uri
,
isImage
)
{
return
!
/^unsafe:/
.
test
(
$$sanitizeUri
(
uri
,
isImage
));
}));
return
buf
.
join
(
''
);
};
}];
/**
* @ngdoc method
* @name $sanitizeProvider#enableSvg
* @kind function
*
* @description
* Enables a subset of svg to be supported by the sanitizer.
*
* <div class="alert alert-warning">
* <p>By enabling this setting without taking other precautions, you might expose your
* application to click-hijacking attacks. In these attacks, sanitized svg elements could be positioned
* outside of the containing element and be rendered over other elements on the page (e.g. a login
* link). Such behavior can then result in phishing incidents.</p>
*
* <p>To protect against these, explicitly setup `overflow: hidden` css rule for all potential svg
* tags within the sanitized content:</p>
*
* <br>
*
* <pre><code>
* .rootOfTheIncludedContent svg {
* overflow: hidden !important;
* }
* </code></pre>
* </div>
*
* @param {boolean=} flag Enable or disable SVG support in the sanitizer.
* @returns {boolean|ng.$sanitizeProvider} Returns the currently configured value if called
* without an argument or self for chaining otherwise.
*/
this
.
enableSvg
=
function
(
enableSvg
)
{
if
(
angular
.
isDefined
(
enableSvg
))
{
svgEnabled
=
enableSvg
;
return
this
;
}
else
{
return
svgEnabled
;
}
};
}
function
sanitizeText
(
chars
)
{
var
buf
=
[];
var
writer
=
htmlSanitizeWriter
(
buf
,
angular
.
noop
);
writer
.
chars
(
chars
);
return
buf
.
join
(
''
);
}
// Regular Expressions for parsing tags and attributes
var
SURROGATE_PAIR_REGEXP
=
/
[\u
D800-
\u
DBFF
][\u
DC00-
\u
DFFF
]
/g
,
// 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
=
toMap
(
"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
=
toMap
(
"colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"
),
optionalEndTagInlineElements
=
toMap
(
"rp,rt"
),
optionalEndTagElements
=
angular
.
extend
({},
optionalEndTagInlineElements
,
optionalEndTagBlockElements
);
// Safe Block Elements - HTML5
var
blockElements
=
angular
.
extend
({},
optionalEndTagBlockElements
,
toMap
(
"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,section,table,ul"
));
// Inline Elements - HTML5
var
inlineElements
=
angular
.
extend
({},
optionalEndTagInlineElements
,
toMap
(
"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"
));
// SVG Elements
// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements
// Note: the elements animate,animateColor,animateMotion,animateTransform,set are intentionally omitted.
// They can potentially allow for arbitrary javascript to be executed. See #11290
var
svgElements
=
toMap
(
"circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,"
+
"hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,"
+
"radialGradient,rect,stop,svg,switch,text,title,tspan"
);
// Blocked Elements (will be stripped)
var
blockedElements
=
toMap
(
"script,style"
);
var
validElements
=
angular
.
extend
({},
voidElements
,
blockElements
,
inlineElements
,
optionalEndTagElements
);
//Attributes that have href and hence need to be sanitized
var
uriAttrs
=
toMap
(
"background,cite,href,longdesc,src,xlink:href"
);
var
htmlAttrs
=
toMap
(
'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,size,span,start,summary,tabindex,target,title,type,'
+
'valign,value,vspace,width'
);
// SVG attributes (without "id" and "name" attributes)
// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes
var
svgAttrs
=
toMap
(
'accent-height,accumulate,additive,alphabetic,arabic-form,ascent,'
+
'baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,'
+
'cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,'
+
'font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,'
+
'height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,'
+
'marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,'
+
'max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,'
+
'path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,'
+
'requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,'
+
'stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,'
+
'stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,'
+
'stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,'
+
'underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,'
+
'width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,'
+
'xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan'
,
true
);
var
validAttrs
=
angular
.
extend
({},
uriAttrs
,
svgAttrs
,
htmlAttrs
);
function
toMap
(
str
,
lowercaseKeys
)
{
var
obj
=
{},
items
=
str
.
split
(
','
),
i
;
for
(
i
=
0
;
i
<
items
.
length
;
i
++
)
{
obj
[
lowercaseKeys
?
angular
.
lowercase
(
items
[
i
])
:
items
[
i
]]
=
true
;
}
return
obj
;
}
var
inertBodyElement
;
(
function
(
window
)
{
var
doc
;
if
(
window
.
document
&&
window
.
document
.
implementation
)
{
doc
=
window
.
document
.
implementation
.
createHTMLDocument
(
"inert"
);
}
else
{
throw
$sanitizeMinErr
(
'noinert'
,
"Can't create an inert html document"
);
}
var
docElement
=
doc
.
documentElement
||
doc
.
getDocumentElement
();
var
bodyElements
=
docElement
.
getElementsByTagName
(
'body'
);
// usually there should be only one body element in the document, but IE doesn't have any, so we need to create one
if
(
bodyElements
.
length
===
1
)
{
inertBodyElement
=
bodyElements
[
0
];
}
else
{
var
html
=
doc
.
createElement
(
'html'
);
inertBodyElement
=
doc
.
createElement
(
'body'
);
html
.
appendChild
(
inertBodyElement
);
doc
.
appendChild
(
html
);
}
})(
window
);
/**
* @example
* htmlParser(htmlString, {
* start: function(tag, attrs) {},
* end: function(tag) {},
* chars: function(text) {},
* comment: function(text) {}
* });
*
* @param {string} html string
* @param {object} handler
*/
function
htmlParser
(
html
,
handler
)
{
if
(
html
===
null
||
html
===
undefined
)
{
html
=
''
;
}
else
if
(
typeof
html
!==
'string'
)
{
html
=
''
+
html
;
}
inertBodyElement
.
innerHTML
=
html
;
//mXSS protection
var
mXSSAttempts
=
5
;
do
{
if
(
mXSSAttempts
===
0
)
{
throw
$sanitizeMinErr
(
'uinput'
,
"Failed to sanitize html because the input is unstable"
);
}
mXSSAttempts
--
;
// strip custom-namespaced attributes on IE<=11
if
(
window
.
document
.
documentMode
)
{
stripCustomNsAttrs
(
inertBodyElement
);
}
html
=
inertBodyElement
.
innerHTML
;
//trigger mXSS
inertBodyElement
.
innerHTML
=
html
;
}
while
(
html
!==
inertBodyElement
.
innerHTML
);
var
node
=
inertBodyElement
.
firstChild
;
while
(
node
)
{
switch
(
node
.
nodeType
)
{
case
1
:
// ELEMENT_NODE
handler
.
start
(
node
.
nodeName
.
toLowerCase
(),
attrToMap
(
node
.
attributes
));
break
;
case
3
:
// TEXT NODE
handler
.
chars
(
node
.
textContent
);
break
;
}
var
nextNode
;
if
(
!
(
nextNode
=
node
.
firstChild
))
{
if
(
node
.
nodeType
==
1
)
{
handler
.
end
(
node
.
nodeName
.
toLowerCase
());
}
nextNode
=
node
.
nextSibling
;
if
(
!
nextNode
)
{
while
(
nextNode
==
null
)
{
node
=
node
.
parentNode
;
if
(
node
===
inertBodyElement
)
break
;
nextNode
=
node
.
nextSibling
;
if
(
node
.
nodeType
==
1
)
{
handler
.
end
(
node
.
nodeName
.
toLowerCase
());
}
}
}
}
node
=
nextNode
;
}
while
(
node
=
inertBodyElement
.
firstChild
)
{
inertBodyElement
.
removeChild
(
node
);
}
}
function
attrToMap
(
attrs
)
{
var
map
=
{};
for
(
var
i
=
0
,
ii
=
attrs
.
length
;
i
<
ii
;
i
++
)
{
var
attr
=
attrs
[
i
];
map
[
attr
.
name
]
=
attr
.
value
;
}
return
map
;
}
/**
* Escapes all potentially dangerous characters, so that the
* resulting string can be safely inserted into attribute or
* element text.
* @param value
* @returns {string} escaped text
*/
function
encodeEntities
(
value
)
{
return
value
.
replace
(
/&/g
,
'&'
).
replace
(
SURROGATE_PAIR_REGEXP
,
function
(
value
)
{
var
hi
=
value
.
charCodeAt
(
0
);
var
low
=
value
.
charCodeAt
(
1
);
return
'&#'
+
(((
hi
-
0xD800
)
*
0x400
)
+
(
low
-
0xDC00
)
+
0x10000
)
+
';'
;
}).
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.join('') to get out sanitized html string
* @returns {object} in the form of {
* start: function(tag, attrs) {},
* end: function(tag) {},
* chars: function(text) {},
* comment: function(text) {}
* }
*/
function
htmlSanitizeWriter
(
buf
,
uriValidator
)
{
var
ignoreCurrentElement
=
false
;
var
out
=
angular
.
bind
(
buf
,
buf
.
push
);
return
{
start
:
function
(
tag
,
attrs
)
{
tag
=
angular
.
lowercase
(
tag
);
if
(
!
ignoreCurrentElement
&&
blockedElements
[
tag
])
{
ignoreCurrentElement
=
tag
;
}
if
(
!
ignoreCurrentElement
&&
validElements
[
tag
]
===
true
)
{
out
(
'<'
);
out
(
tag
);
angular
.
forEach
(
attrs
,
function
(
value
,
key
)
{
var
lkey
=
angular
.
lowercase
(
key
);
var
isImage
=
(
tag
===
'img'
&&
lkey
===
'src'
)
||
(
lkey
===
'background'
);
if
(
validAttrs
[
lkey
]
===
true
&&
(
uriAttrs
[
lkey
]
!==
true
||
uriValidator
(
value
,
isImage
)))
{
out
(
' '
);
out
(
key
);
out
(
'="'
);
out
(
encodeEntities
(
value
));
out
(
'"'
);
}
});
out
(
'>'
);
}
},
end
:
function
(
tag
)
{
tag
=
angular
.
lowercase
(
tag
);
if
(
!
ignoreCurrentElement
&&
validElements
[
tag
]
===
true
&&
voidElements
[
tag
]
!==
true
)
{
out
(
'</'
);
out
(
tag
);
out
(
'>'
);
}
if
(
tag
==
ignoreCurrentElement
)
{
ignoreCurrentElement
=
false
;
}
},
chars
:
function
(
chars
)
{
if
(
!
ignoreCurrentElement
)
{
out
(
encodeEntities
(
chars
));
}
}
};
}
/**
* When IE9-11 comes across an unknown namespaced attribute e.g. 'xlink:foo' it adds 'xmlns:ns1' attribute to declare
* ns1 namespace and prefixes the attribute with 'ns1' (e.g. 'ns1:xlink:foo'). This is undesirable since we don't want
* to allow any of these custom attributes. This method strips them all.
*
* @param node Root element to process
*/
function
stripCustomNsAttrs
(
node
)
{
if
(
node
.
nodeType
===
window
.
Node
.
ELEMENT_NODE
)
{
var
attrs
=
node
.
attributes
;
for
(
var
i
=
0
,
l
=
attrs
.
length
;
i
<
l
;
i
++
)
{
var
attrNode
=
attrs
[
i
];
var
attrName
=
attrNode
.
name
.
toLowerCase
();
if
(
attrName
===
'xmlns:ns1'
||
attrName
.
lastIndexOf
(
'ns1:'
,
0
)
===
0
)
{
node
.
removeAttributeNode
(
attrNode
);
i
--
;
l
--
;
}
}
}
var
nextNode
=
node
.
firstChild
;
if
(
nextNode
)
{
stripCustomNsAttrs
(
nextNode
);
}
nextNode
=
node
.
nextSibling
;
if
(
nextNode
)
{
stripCustomNsAttrs
(
nextNode
);
}
}
// define ngSanitize module and register $sanitize service
angular
.
module
(
'ngSanitize'
,
[]).
provider
(
'$sanitize'
,
$SanitizeProvider
);
/* global sanitizeText: false */
/**
* @ngdoc filter
* @name linky
* @kind 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.
* @param {object|function(url)} [attributes] Add custom attributes to the link element.
*
* Can be one of:
*
* - `object`: A map of attributes
* - `function`: Takes the url as a parameter and returns a map of attributes
*
* If the map of attributes contains a value for `target`, it overrides the value of
* the target parameter.
*
*
* @returns {string} Html-linkified and {@link $sanitize sanitized} text.
*
* @usage
<span ng-bind-html="linky_expression | linky"></span>
*
* @example
<example module="linkyExample" deps="angular-sanitize.js">
<file name="index.html">
<div ng-controller="ExampleController">
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
<table>
<tr>
<th>Filter</th>
<th>Source</th>
<th>Rendered</th>
</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="snippetWithSingleURL | linky:'_blank'"><br></div></pre>
</td>
<td>
<div ng-bind-html="snippetWithSingleURL | linky:'_blank'"></div>
</td>
</tr>
<tr id="linky-custom-attributes">
<td>linky custom attributes</td>
<td>
<pre><div ng-bind-html="snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}"><br></div></pre>
</td>
<td>
<div ng-bind-html="snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}"></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>
</file>
<file name="script.js">
angular.module('linkyExample', ['ngSanitize'])
.controller('ExampleController', ['$scope', function($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.snippetWithSingleURL = 'http://angularjs.org/';
}]);
</file>
<file name="protractor.js" type="protractor">
it('should linkify the snippet with urls', function() {
expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' +
'another@somewhere.org, and one more: ftp://127.0.0.1/.');
expect(element.all(by.css('#linky-filter a')).count()).toEqual(4);
});
it('should not linkify snippet without the linky filter', function() {
expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()).
toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' +
'another@somewhere.org, and one more: ftp://127.0.0.1/.');
expect(element.all(by.css('#escaped-html a')).count()).toEqual(0);
});
it('should update', function() {
element(by.model('snippet')).clear();
element(by.model('snippet')).sendKeys('new http://link.');
expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
toBe('new http://link.');
expect(element.all(by.css('#linky-filter a')).count()).toEqual(1);
expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText())
.toBe('new http://link.');
});
it('should work with the target property', function() {
expect(element(by.id('linky-target')).
element(by.binding("snippetWithSingleURL | linky:'_blank'")).getText()).
toBe('http://angularjs.org/');
expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank');
});
it('should optionally add custom attributes', function() {
expect(element(by.id('linky-custom-attributes')).
element(by.binding("snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}")).getText()).
toBe('http://angularjs.org/');
expect(element(by.css('#linky-custom-attributes a')).getAttribute('rel')).toEqual('nofollow');
});
</file>
</example>
*/
angular
.
module
(
'ngSanitize'
).
filter
(
'linky'
,
[
'$sanitize'
,
function
(
$sanitize
)
{
var
LINKY_URL_REGEXP
=
/
((
ftp|https
?)
:
\/\/
|
(
www
\.)
|
(
mailto:
)?[
A-Za-z0-9._%+-
]
+@
)\S
*
[^\s
.;,(){}<>"
\u
201d
\u
2019
]
/i
,
MAILTO_REGEXP
=
/^mailto:/i
;
var
linkyMinErr
=
angular
.
$$minErr
(
'linky'
);
var
isString
=
angular
.
isString
;
return
function
(
text
,
target
,
attributes
)
{
if
(
text
==
null
||
text
===
''
)
return
text
;
if
(
!
isString
(
text
))
throw
linkyMinErr
(
'notstring'
,
'Expected string but received: {0}'
,
text
);
var
attributesFn
=
angular
.
isFunction
(
attributes
)
?
attributes
:
angular
.
isObject
(
attributes
)
?
function
getAttributesObject
()
{
return
attributes
;}
:
function
getEmptyAttributesObject
()
{
return
{};};
var
match
;
var
raw
=
text
;
var
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/www/mailto then assume mailto
if
(
!
match
[
2
]
&&
!
match
[
4
])
{
url
=
(
match
[
3
]
?
'http://'
:
'mailto:'
)
+
url
;
}
i
=
match
.
index
;
addText
(
raw
.
substr
(
0
,
i
));
addLink
(
url
,
match
[
0
].
replace
(
MAILTO_REGEXP
,
''
));
raw
=
raw
.
substring
(
i
+
match
[
0
].
length
);
}
addText
(
raw
);
return
$sanitize
(
html
.
join
(
''
));
function
addText
(
text
)
{
if
(
!
text
)
{
return
;
}
html
.
push
(
sanitizeText
(
text
));
}
function
addLink
(
url
,
text
)
{
var
key
,
linkAttributes
=
attributesFn
(
url
);
html
.
push
(
'<a '
);
for
(
key
in
linkAttributes
)
{
html
.
push
(
key
+
'="'
+
linkAttributes
[
key
]
+
'" '
);
}
if
(
angular
.
isDefined
(
target
)
&&
!
(
'target'
in
linkAttributes
))
{
html
.
push
(
'target="'
,
target
,
'" '
);
}
html
.
push
(
'href="'
,
url
.
replace
(
/"/g
,
'"'
),
'">'
);
addText
(
text
);
html
.
push
(
'</a>'
);
}
};
}]);
})(
window
,
window
.
angular
);
bower.json
0 → 100644
View file @
68fa4f84
{
"name"
:
"angular-sanitize"
,
"version"
:
"1.5.7"
,
"license"
:
"MIT"
,
"main"
:
"./angular-sanitize.js"
,
"ignore"
:
[],
"dependencies"
:
{
"angular"
:
"1.5.7"
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment