angular-gem 1.1.5 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/angular-gem/version.rb +1 -1
- data/lib/tasks/copy.rake +22 -11
- data/lib/tasks/tag.rake +2 -11
- data/vendor/assets/javascripts/1.2.0/angular-animate.js +1226 -0
- data/vendor/assets/javascripts/1.2.0/angular-animate.min.js +21 -0
- data/vendor/assets/javascripts/1.2.0/angular-animate.min.js.map +8 -0
- data/vendor/assets/javascripts/{angular-cookies-unstable.js → 1.2.0/angular-cookies.js} +21 -4
- data/vendor/assets/javascripts/1.2.0/angular-cookies.min.js +8 -0
- data/vendor/assets/javascripts/1.2.0/angular-cookies.min.js.map +8 -0
- data/vendor/assets/javascripts/1.2.0/angular-csp.css +24 -0
- data/vendor/assets/javascripts/{angular-loader-unstable.js → 1.2.0/angular-loader.js} +48 -29
- data/vendor/assets/javascripts/1.2.0/angular-loader.min.js +8 -0
- data/vendor/assets/javascripts/1.2.0/angular-loader.min.js.map +8 -0
- data/vendor/assets/javascripts/{angular-mocks-unstable.js → 1.2.0/angular-mocks.js} +460 -216
- data/vendor/assets/javascripts/{angular-resource-unstable.js → 1.2.0/angular-resource.js} +189 -148
- data/vendor/assets/javascripts/1.2.0/angular-resource.min.js +12 -0
- data/vendor/assets/javascripts/1.2.0/angular-resource.min.js.map +8 -0
- data/vendor/assets/javascripts/1.2.0/angular-route.js +880 -0
- data/vendor/assets/javascripts/1.2.0/angular-route.min.js +14 -0
- data/vendor/assets/javascripts/1.2.0/angular-route.min.js.map +8 -0
- data/vendor/assets/javascripts/{angular-sanitize-unstable.js → 1.2.0/angular-sanitize.js} +142 -123
- data/vendor/assets/javascripts/1.2.0/angular-sanitize.min.js +14 -0
- data/vendor/assets/javascripts/1.2.0/angular-sanitize.min.js.map +8 -0
- data/vendor/assets/javascripts/{angular-scenario-unstable.js → 1.2.0/angular-scenario.js} +15978 -12405
- data/vendor/assets/javascripts/{angular-mobile-unstable.js → 1.2.0/angular-touch.js} +214 -111
- data/vendor/assets/javascripts/1.2.0/angular-touch.min.js +13 -0
- data/vendor/assets/javascripts/1.2.0/angular-touch.min.js.map +8 -0
- data/vendor/assets/javascripts/{angular-unstable.js → 1.2.0/angular.js} +10167 -7012
- data/vendor/assets/javascripts/1.2.0/angular.min.js +200 -0
- data/vendor/assets/javascripts/1.2.0/angular.min.js.map +8 -0
- data/vendor/assets/javascripts/1.2.0/errors.json +1 -0
- data/vendor/assets/javascripts/1.2.0/version.json +1 -0
- data/vendor/assets/javascripts/1.2.0/version.txt +1 -0
- data/vendor/assets/javascripts/angular-animate.js +1226 -0
- data/vendor/assets/javascripts/angular-animate.min.js +21 -0
- data/vendor/assets/javascripts/angular-cookies.js +21 -4
- data/vendor/assets/javascripts/angular-cookies.min.js +8 -0
- data/vendor/assets/javascripts/angular-loader.js +63 -17
- data/vendor/assets/javascripts/angular-loader.min.js +8 -0
- data/vendor/assets/javascripts/angular-mocks.js +553 -211
- data/vendor/assets/javascripts/angular-resource.js +268 -147
- data/vendor/assets/javascripts/angular-resource.min.js +12 -0
- data/vendor/assets/javascripts/angular-route.js +880 -0
- data/vendor/assets/javascripts/angular-route.min.js +14 -0
- data/vendor/assets/javascripts/angular-sanitize.js +165 -125
- data/vendor/assets/javascripts/angular-sanitize.min.js +14 -0
- data/vendor/assets/javascripts/angular-scenario.js +16615 -10889
- data/vendor/assets/javascripts/angular-touch.js +563 -0
- data/vendor/assets/javascripts/angular-touch.min.js +13 -0
- data/vendor/assets/javascripts/angular.js +9717 -4533
- data/vendor/assets/javascripts/angular.min.js +200 -0
- metadata +44 -21
- data/test/dummy/log/test.log +0 -2
- data/test/dummy/tmp/cache/assets/D65/250/sprockets%2F54a960d46bb0b354e8bd46fa03f5e0e4 +0 -0
- data/test/dummy/tmp/cache/assets/D6A/FB0/sprockets%2F92721e9941b77adcfdfba3d060622de2 +0 -0
- data/test/dummy/tmp/cache/assets/E07/040/sprockets%2Ff55b8ce9d0f28ce36b768a1c7aeb2ef3 +0 -0
- data/test/tmp/app/assets/javascripts/application.js +0 -5
@@ -0,0 +1,14 @@
|
|
1
|
+
/*
|
2
|
+
AngularJS v1.2.0
|
3
|
+
(c) 2010-2012 Google, Inc. http://angularjs.org
|
4
|
+
License: MIT
|
5
|
+
*/
|
6
|
+
(function(t,c,B){'use strict';function w(s,r,g,a,h){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",compile:function(k,d,A){return function(u,k,d){function v(){l&&(l.$destroy(),l=null);m&&(h.leave(m),m=null)}function x(){var f=s.current&&s.current.locals,y=f&&f.$template;if(y){var z=u.$new();A(z,function(e){e.html(y);h.enter(e,null,m||k,function(){!c.isDefined(n)||n&&!u.$eval(n)||r()});v();var p=g(e.contents()),q=s.current;l=q.scope=z;m=e;if(q.controller){f.$scope=l;var d=a(q.controller,
|
7
|
+
f);q.controllerAs&&(l[q.controllerAs]=d);e.data("$ngControllerController",d);e.children().data("$ngControllerController",d)}p(l);l.$emit("$viewContentLoaded");l.$eval(b)})}else v()}var l,m,n=d.autoscroll,b=d.onload||"";u.$on("$routeChangeSuccess",x);x()}}}}t=c.module("ngRoute",["ng"]).provider("$route",function(){function s(a,h){return c.extend(new (c.extend(function(){},{prototype:a})),h)}function r(a,c){var k=c.caseInsensitiveMatch,d={originalPath:a,regexp:a},g=d.keys=[];a=a.replace(/([().])/g,
|
8
|
+
"\\$1").replace(/(\/)?:(\w+)([\?|\*])?/g,function(a,c,h,d){a="?"===d?d:null;d="*"===d?d:null;g.push({name:h,optional:!!a});c=c||"";return""+(a?"":c)+"(?:"+(a?c:"")+(d&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([\/$\*])/g,"\\$1");d.regexp=RegExp("^"+a+"$",k?"i":"");return d}var g={};this.when=function(a,h){g[a]=c.extend({reloadOnSearch:!0},h,a&&r(a,h));if(a){var k="/"==a[a.length-1]?a.substr(0,a.length-1):a+"/";g[k]=c.extend({redirectTo:a},r(k,h))}return this};this.otherwise=function(a){this.when(null,
|
9
|
+
a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce",function(a,h,k,d,r,u,t,w){function v(){var b=x(),f=n.current;if(b&&f&&b.$$route===f.$$route&&c.equals(b.pathParams,f.pathParams)&&!b.reloadOnSearch&&!m)f.params=b.params,c.copy(f.params,k),a.$broadcast("$routeUpdate",f);else if(b||f)m=!1,a.$broadcast("$routeChangeStart",b,f),(n.current=b)&&b.redirectTo&&(c.isString(b.redirectTo)?h.path(l(b.redirectTo,b.params)).search(b.params).replace():
|
10
|
+
h.url(b.redirectTo(b.pathParams,h.path(),h.search())).replace()),d.when(b).then(function(){if(b){var a=c.extend({},b.resolve),f,e;c.forEach(a,function(b,f){a[f]=c.isString(b)?r.get(b):r.invoke(b)});c.isDefined(f=b.template)?c.isFunction(f)&&(f=f(b.params)):c.isDefined(e=b.templateUrl)&&(c.isFunction(e)&&(e=e(b.params)),e=w.getTrustedResourceUrl(e),c.isDefined(e)&&(b.loadedTemplateUrl=e,f=u.get(e,{cache:t}).then(function(b){return b.data})));c.isDefined(f)&&(a.$template=f);return d.all(a)}}).then(function(d){b==
|
11
|
+
n.current&&(b&&(b.locals=d,c.copy(b.params,k)),a.$broadcast("$routeChangeSuccess",b,f))},function(c){b==n.current&&a.$broadcast("$routeChangeError",b,f,c)})}function x(){var b,a;c.forEach(g,function(d,l){var e;if(e=!a){var p=h.path();e=d.keys;var q={};if(d.regexp)if(p=d.regexp.exec(p)){for(var g=1,k=p.length;g<k;++g){var m=e[g-1],n="string"==typeof p[g]?decodeURIComponent(p[g]):p[g];m&&n&&(q[m.name]=n)}e=q}else e=null;else e=null;e=b=e}e&&(a=s(d,{params:c.extend({},h.search(),b),pathParams:b}),a.$$route=
|
12
|
+
d)});return a||g[null]&&s(g[null],{params:{},pathParams:{}})}function l(a,d){var g=[];c.forEach((a||"").split(":"),function(a,b){if(0===b)g.push(a);else{var c=a.match(/(\w+)(.*)/),h=c[1];g.push(d[h]);g.push(c[2]||"");delete d[h]}});return g.join("")}var m=!1,n={routes:g,reload:function(){m=!0;a.$evalAsync(v)}};a.$on("$locationChangeSuccess",v);return n}]});t.provider("$routeParams",function(){this.$get=function(){return{}}});t.directive("ngView",w);w.$inject=["$route","$anchorScroll","$compile","$controller",
|
13
|
+
"$animate"]})(window,window.angular);
|
14
|
+
//# sourceMappingURL=angular-route.min.js.map
|
@@ -1,15 +1,26 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.0
|
2
|
+
* @license AngularJS v1.2.0
|
3
3
|
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
6
|
-
(function(window, angular, undefined) {
|
7
|
-
|
6
|
+
(function(window, angular, undefined) {'use strict';
|
7
|
+
|
8
|
+
var $sanitizeMinErr = angular.$$minErr('$sanitize');
|
8
9
|
|
9
10
|
/**
|
10
11
|
* @ngdoc overview
|
11
12
|
* @name ngSanitize
|
12
13
|
* @description
|
14
|
+
*
|
15
|
+
* # ngSanitize
|
16
|
+
*
|
17
|
+
* The `ngSanitize` module provides functionality to sanitize HTML.
|
18
|
+
*
|
19
|
+
* {@installModule sanitize}
|
20
|
+
*
|
21
|
+
* <div doc-module-components="ngSanitize"></div>
|
22
|
+
*
|
23
|
+
* See {@link ngSanitize.$sanitize `$sanitize`} for usage.
|
13
24
|
*/
|
14
25
|
|
15
26
|
/*
|
@@ -46,72 +57,80 @@
|
|
46
57
|
*
|
47
58
|
* @example
|
48
59
|
<doc:example module="ngSanitize">
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
60
|
+
<doc:source>
|
61
|
+
<script>
|
62
|
+
function Ctrl($scope, $sce) {
|
63
|
+
$scope.snippet =
|
64
|
+
'<p style="color:blue">an html\n' +
|
65
|
+
'<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' +
|
66
|
+
'snippet</p>';
|
67
|
+
$scope.deliberatelyTrustDangerousSnippet = function() {
|
68
|
+
return $sce.trustAsHtml($scope.snippet);
|
69
|
+
};
|
70
|
+
}
|
71
|
+
</script>
|
72
|
+
<div ng-controller="Ctrl">
|
73
|
+
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
|
74
|
+
<table>
|
75
|
+
<tr>
|
76
|
+
<td>Directive</td>
|
77
|
+
<td>How</td>
|
78
|
+
<td>Source</td>
|
79
|
+
<td>Rendered</td>
|
80
|
+
</tr>
|
81
|
+
<tr id="bind-html-with-sanitize">
|
82
|
+
<td>ng-bind-html</td>
|
83
|
+
<td>Automatically uses $sanitize</td>
|
84
|
+
<td><pre><div ng-bind-html="snippet"><br/></div></pre></td>
|
85
|
+
<td><div ng-bind-html="snippet"></div></td>
|
86
|
+
</tr>
|
87
|
+
<tr id="bind-html-with-trust">
|
88
|
+
<td>ng-bind-html</td>
|
89
|
+
<td>Bypass $sanitize by explicitly trusting the dangerous value</td>
|
90
|
+
<td>
|
91
|
+
<pre><div ng-bind-html="deliberatelyTrustDangerousSnippet()">
|
92
|
+
</div></pre>
|
93
|
+
</td>
|
94
|
+
<td><div ng-bind-html="deliberatelyTrustDangerousSnippet()"></div></td>
|
95
|
+
</tr>
|
96
|
+
<tr id="bind-default">
|
97
|
+
<td>ng-bind</td>
|
98
|
+
<td>Automatically escapes</td>
|
99
|
+
<td><pre><div ng-bind="snippet"><br/></div></pre></td>
|
100
|
+
<td><div ng-bind="snippet"></div></td>
|
101
|
+
</tr>
|
102
|
+
</table>
|
103
|
+
</div>
|
104
|
+
</doc:source>
|
105
|
+
<doc:scenario>
|
106
|
+
it('should sanitize the html snippet by default', function() {
|
107
|
+
expect(using('#bind-html-with-sanitize').element('div').html()).
|
108
|
+
toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
|
109
|
+
});
|
110
|
+
|
111
|
+
it('should inline raw snippet if bound to a trusted value', function() {
|
112
|
+
expect(using('#bind-html-with-trust').element("div").html()).
|
113
|
+
toBe("<p style=\"color:blue\">an html\n" +
|
114
|
+
"<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
|
115
|
+
"snippet</p>");
|
116
|
+
});
|
117
|
+
|
118
|
+
it('should escape snippet without any filter', function() {
|
119
|
+
expect(using('#bind-default').element('div').html()).
|
120
|
+
toBe("<p style=\"color:blue\">an html\n" +
|
121
|
+
"<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
|
122
|
+
"snippet</p>");
|
123
|
+
});
|
124
|
+
|
125
|
+
it('should update', function() {
|
126
|
+
input('snippet').enter('new <b onclick="alert(1)">text</b>');
|
127
|
+
expect(using('#bind-html-with-sanitize').element('div').html()).toBe('new <b>text</b>');
|
128
|
+
expect(using('#bind-html-with-trust').element('div').html()).toBe(
|
129
|
+
'new <b onclick="alert(1)">text</b>');
|
130
|
+
expect(using('#bind-default').element('div').html()).toBe(
|
131
|
+
"new <b onclick=\"alert(1)\">text</b>");
|
132
|
+
});
|
133
|
+
</doc:scenario>
|
115
134
|
</doc:example>
|
116
135
|
*/
|
117
136
|
var $sanitize = function(html) {
|
@@ -122,15 +141,18 @@ var $sanitize = function(html) {
|
|
122
141
|
|
123
142
|
|
124
143
|
// Regular Expressions for parsing tags and attributes
|
125
|
-
var START_TAG_REGEXP =
|
144
|
+
var START_TAG_REGEXP =
|
145
|
+
/^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/,
|
126
146
|
END_TAG_REGEXP = /^<\s*\/\s*([\w:-]+)[^>]*>/,
|
127
147
|
ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,
|
128
148
|
BEGIN_TAG_REGEXP = /^</,
|
129
149
|
BEGING_END_TAGE_REGEXP = /^<\s*\//,
|
130
150
|
COMMENT_REGEXP = /<!--(.*?)-->/g,
|
151
|
+
DOCTYPE_REGEXP = /<!DOCTYPE([^>]*?)>/i,
|
131
152
|
CDATA_REGEXP = /<!\[CDATA\[(.*?)]]>/g,
|
132
|
-
URI_REGEXP = /^((ftp|https?):\/\/|mailto:|#)
|
133
|
-
|
153
|
+
URI_REGEXP = /^((ftp|https?):\/\/|mailto:|tel:|#)/i,
|
154
|
+
// Match everything outside of normal chars and " (quote character)
|
155
|
+
NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g;
|
134
156
|
|
135
157
|
|
136
158
|
// Good source of info about elements and attributes
|
@@ -145,23 +167,29 @@ var voidElements = makeMap("area,br,col,hr,img,wbr");
|
|
145
167
|
// http://dev.w3.org/html5/spec/Overview.html#optional-tags
|
146
168
|
var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),
|
147
169
|
optionalEndTagInlineElements = makeMap("rp,rt"),
|
148
|
-
optionalEndTagElements = angular.extend({},
|
170
|
+
optionalEndTagElements = angular.extend({},
|
171
|
+
optionalEndTagInlineElements,
|
172
|
+
optionalEndTagBlockElements);
|
149
173
|
|
150
174
|
// Safe Block Elements - HTML5
|
151
|
-
var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("address,article,
|
152
|
-
"blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,
|
153
|
-
"header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul"));
|
175
|
+
var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("address,article," +
|
176
|
+
"aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5," +
|
177
|
+
"h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul"));
|
154
178
|
|
155
179
|
// Inline Elements - HTML5
|
156
|
-
var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b,
|
157
|
-
"big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,
|
158
|
-
"span,strike,strong,sub,sup,time,tt,u,var"));
|
180
|
+
var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b," +
|
181
|
+
"bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," +
|
182
|
+
"samp,small,span,strike,strong,sub,sup,time,tt,u,var"));
|
159
183
|
|
160
184
|
|
161
185
|
// Special Elements (can contain anything)
|
162
186
|
var specialElements = makeMap("script,style");
|
163
187
|
|
164
|
-
var validElements = angular.extend({},
|
188
|
+
var validElements = angular.extend({},
|
189
|
+
voidElements,
|
190
|
+
blockElements,
|
191
|
+
inlineElements,
|
192
|
+
optionalEndTagElements);
|
165
193
|
|
166
194
|
//Attributes that have href and hence need to be sanitized
|
167
195
|
var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap");
|
@@ -203,14 +231,22 @@ function htmlParser( html, handler ) {
|
|
203
231
|
|
204
232
|
// Comment
|
205
233
|
if ( html.indexOf("<!--") === 0 ) {
|
206
|
-
|
234
|
+
// comments containing -- are not allowed unless they terminate the comment
|
235
|
+
index = html.indexOf("--", 4);
|
207
236
|
|
208
|
-
if ( index >= 0 ) {
|
237
|
+
if ( index >= 0 && html.lastIndexOf("-->", index) === index) {
|
209
238
|
if (handler.comment) handler.comment( html.substring( 4, index ) );
|
210
239
|
html = html.substring( index + 3 );
|
211
240
|
chars = false;
|
212
241
|
}
|
242
|
+
// DOCTYPE
|
243
|
+
} else if ( DOCTYPE_REGEXP.test(html) ) {
|
244
|
+
match = html.match( DOCTYPE_REGEXP );
|
213
245
|
|
246
|
+
if ( match ) {
|
247
|
+
html = html.replace( match[0] , '');
|
248
|
+
chars = false;
|
249
|
+
}
|
214
250
|
// end tag
|
215
251
|
} else if ( BEGING_END_TAGE_REGEXP.test(html) ) {
|
216
252
|
match = html.match( END_TAG_REGEXP );
|
@@ -242,21 +278,21 @@ function htmlParser( html, handler ) {
|
|
242
278
|
}
|
243
279
|
|
244
280
|
} else {
|
245
|
-
html = html.replace(new RegExp("(.*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'),
|
246
|
-
|
247
|
-
replace(COMMENT_REGEXP, "$1").
|
248
|
-
replace(CDATA_REGEXP, "$1");
|
281
|
+
html = html.replace(new RegExp("(.*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'),
|
282
|
+
function(all, text){
|
283
|
+
text = text.replace(COMMENT_REGEXP, "$1").replace(CDATA_REGEXP, "$1");
|
249
284
|
|
250
|
-
|
285
|
+
if (handler.chars) handler.chars( decodeEntities(text) );
|
251
286
|
|
252
|
-
|
287
|
+
return "";
|
253
288
|
});
|
254
289
|
|
255
290
|
parseEndTag( "", stack.last() );
|
256
291
|
}
|
257
292
|
|
258
293
|
if ( html == last ) {
|
259
|
-
throw "
|
294
|
+
throw $sanitizeMinErr('badparse', "The sanitizer was unable to parse the following block " +
|
295
|
+
"of html: {0}", html);
|
260
296
|
}
|
261
297
|
last = html;
|
262
298
|
}
|
@@ -283,13 +319,14 @@ function htmlParser( html, handler ) {
|
|
283
319
|
|
284
320
|
var attrs = {};
|
285
321
|
|
286
|
-
rest.replace(ATTR_REGEXP,
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
322
|
+
rest.replace(ATTR_REGEXP,
|
323
|
+
function(match, name, doubleQuotedValue, singleQuotedValue, unquotedValue) {
|
324
|
+
var value = doubleQuotedValue
|
325
|
+
|| singleQuotedValue
|
326
|
+
|| unquotedValue
|
327
|
+
|| '';
|
291
328
|
|
292
|
-
|
329
|
+
attrs[name] = decodeEntities(value);
|
293
330
|
});
|
294
331
|
if (handler.start) handler.start( tagName, attrs, unary );
|
295
332
|
}
|
@@ -361,12 +398,12 @@ function htmlSanitizeWriter(buf){
|
|
361
398
|
if (!ignore && specialElements[tag]) {
|
362
399
|
ignore = tag;
|
363
400
|
}
|
364
|
-
if (!ignore && validElements[tag]
|
401
|
+
if (!ignore && validElements[tag] === true) {
|
365
402
|
out('<');
|
366
403
|
out(tag);
|
367
404
|
angular.forEach(attrs, function(value, key){
|
368
405
|
var lkey=angular.lowercase(key);
|
369
|
-
if (validAttrs[lkey]
|
406
|
+
if (validAttrs[lkey]===true && (uriAttrs[lkey]!==true || value.match(URI_REGEXP))) {
|
370
407
|
out(' ');
|
371
408
|
out(key);
|
372
409
|
out('="');
|
@@ -379,7 +416,7 @@ function htmlSanitizeWriter(buf){
|
|
379
416
|
},
|
380
417
|
end: function(tag){
|
381
418
|
tag = angular.lowercase(tag);
|
382
|
-
if (!ignore && validElements[tag]
|
419
|
+
if (!ignore && validElements[tag] === true) {
|
383
420
|
out('</');
|
384
421
|
out(tag);
|
385
422
|
out('>');
|
@@ -400,28 +437,7 @@ function htmlSanitizeWriter(buf){
|
|
400
437
|
// define ngSanitize module and register $sanitize service
|
401
438
|
angular.module('ngSanitize', []).value('$sanitize', $sanitize);
|
402
439
|
|
403
|
-
|
404
|
-
* @ngdoc directive
|
405
|
-
* @name ngSanitize.directive:ngBindHtml
|
406
|
-
*
|
407
|
-
* @description
|
408
|
-
* Creates a binding that will sanitize the result of evaluating the `expression` with the
|
409
|
-
* {@link ngSanitize.$sanitize $sanitize} service and innerHTML the result into the current element.
|
410
|
-
*
|
411
|
-
* See {@link ngSanitize.$sanitize $sanitize} docs for examples.
|
412
|
-
*
|
413
|
-
* @element ANY
|
414
|
-
* @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
|
415
|
-
*/
|
416
|
-
angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($sanitize) {
|
417
|
-
return function(scope, element, attr) {
|
418
|
-
element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
|
419
|
-
scope.$watch(attr.ngBindHtml, function ngBindHtmlWatchAction(value) {
|
420
|
-
value = $sanitize(value);
|
421
|
-
element.html(value || '');
|
422
|
-
});
|
423
|
-
};
|
424
|
-
}]);
|
440
|
+
/* global htmlSanitizeWriter: false */
|
425
441
|
|
426
442
|
/**
|
427
443
|
* @ngdoc filter
|
@@ -429,10 +445,13 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
|
|
429
445
|
* @function
|
430
446
|
*
|
431
447
|
* @description
|
432
|
-
*
|
433
|
-
*
|
448
|
+
* Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and
|
449
|
+
* plain email address links.
|
450
|
+
*
|
451
|
+
* Requires the {@link ngSanitize `ngSanitize`} module to be installed.
|
434
452
|
*
|
435
453
|
* @param {string} text Input text.
|
454
|
+
* @param {string} target Window (_blank|_self|_parent|_top) or named frame to open links in.
|
436
455
|
* @returns {string} Html-linkified text.
|
437
456
|
*
|
438
457
|
* @usage
|
@@ -449,6 +468,7 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
|
|
449
468
|
'mailto:us@somewhere.org,\n'+
|
450
469
|
'another@somewhere.org,\n'+
|
451
470
|
'and one more: ftp://127.0.0.1/.';
|
471
|
+
$scope.snippetWithTarget = 'http://angularjs.org/';
|
452
472
|
}
|
453
473
|
</script>
|
454
474
|
<div ng-controller="Ctrl">
|
@@ -468,6 +488,15 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
|
|
468
488
|
<div ng-bind-html="snippet | linky"></div>
|
469
489
|
</td>
|
470
490
|
</tr>
|
491
|
+
<tr id="linky-target">
|
492
|
+
<td>linky target</td>
|
493
|
+
<td>
|
494
|
+
<pre><div ng-bind-html="snippetWithTarget | linky:'_blank'"><br></div></pre>
|
495
|
+
</td>
|
496
|
+
<td>
|
497
|
+
<div ng-bind-html="snippetWithTarget | linky:'_blank'"></div>
|
498
|
+
</td>
|
499
|
+
</tr>
|
471
500
|
<tr id="escaped-html">
|
472
501
|
<td>no filter</td>
|
473
502
|
<td><pre><div ng-bind="snippet"><br></div></pre></td>
|
@@ -500,14 +529,20 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
|
|
500
529
|
toBe('new <a href="http://link">http://link</a>.');
|
501
530
|
expect(using('#escaped-html').binding('snippet')).toBe('new http://link.');
|
502
531
|
});
|
532
|
+
|
533
|
+
it('should work with the target property', function() {
|
534
|
+
expect(using('#linky-target').binding("snippetWithTarget | linky:'_blank'")).
|
535
|
+
toBe('<a target="_blank" href="http://angularjs.org/">http://angularjs.org/</a>');
|
536
|
+
});
|
503
537
|
</doc:scenario>
|
504
538
|
</doc:example>
|
505
539
|
*/
|
506
540
|
angular.module('ngSanitize').filter('linky', function() {
|
507
|
-
var LINKY_URL_REGEXP =
|
541
|
+
var LINKY_URL_REGEXP =
|
542
|
+
/((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>]/,
|
508
543
|
MAILTO_REGEXP = /^mailto:/;
|
509
544
|
|
510
|
-
return function(text) {
|
545
|
+
return function(text, target) {
|
511
546
|
if (!text) return text;
|
512
547
|
var match;
|
513
548
|
var raw = text;
|
@@ -516,6 +551,10 @@ angular.module('ngSanitize').filter('linky', function() {
|
|
516
551
|
var writer = htmlSanitizeWriter(html);
|
517
552
|
var url;
|
518
553
|
var i;
|
554
|
+
var properties = {};
|
555
|
+
if (angular.isDefined(target)) {
|
556
|
+
properties.target = target;
|
557
|
+
}
|
519
558
|
while ((match = raw.match(LINKY_URL_REGEXP))) {
|
520
559
|
// We can not end in these as they are sometimes found at the end of the sentence
|
521
560
|
url = match[0];
|
@@ -523,7 +562,8 @@ angular.module('ngSanitize').filter('linky', function() {
|
|
523
562
|
if (match[2] == match[3]) url = 'mailto:' + url;
|
524
563
|
i = match.index;
|
525
564
|
writer.chars(raw.substr(0, i));
|
526
|
-
|
565
|
+
properties.href = url;
|
566
|
+
writer.start('a', properties);
|
527
567
|
writer.chars(match[0].replace(MAILTO_REGEXP, ''));
|
528
568
|
writer.end('a');
|
529
569
|
raw = raw.substring(i + match[0].length);
|