angularjs-rails-resource 1.0.0.pre.4 → 1.0.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.
- checksums.yaml +4 -4
- data/bower.json +1 -1
- data/lib/angularjs-rails-resource/version.rb +1 -1
- data/package.json +1 -1
- data/test/lib/angular/angular-cookies.js +24 -6
- data/test/lib/angular/angular-loader.js +138 -32
- data/test/lib/angular/angular-mocks.js +666 -396
- data/test/lib/angular/angular-route.js +911 -0
- data/test/lib/angular/angular-sanitize.js +212 -148
- data/test/lib/angular/angular-scenario.js +17060 -12378
- data/test/lib/angular/angular.js +10869 -6644
- metadata +6 -14
- data/test/lib/angular/angular-bootstrap-prettify.js +0 -1838
- data/test/lib/angular/angular-bootstrap.js +0 -167
- data/test/lib/angular/angular-locale_en-us.js +0 -4
- data/test/lib/angular/angular-mobile.js +0 -267
- data/test/lib/angular/angular-resource.js +0 -521
@@ -1,15 +1,26 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.
|
3
|
-
* (c) 2010-
|
2
|
+
* @license AngularJS v1.2.6
|
3
|
+
* (c) 2010-2014 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
|
/*
|
@@ -40,97 +51,122 @@
|
|
40
51
|
* it into the returned string, however, since our parser is more strict than a typical browser
|
41
52
|
* parser, it's possible that some obscure input, which would be recognized as valid HTML by a
|
42
53
|
* browser, won't make it through the sanitizer.
|
54
|
+
* The whitelist is configured using the functions `aHrefSanitizationWhitelist` and
|
55
|
+
* `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider `$compileProvider`}.
|
43
56
|
*
|
44
57
|
* @param {string} html Html input.
|
45
58
|
* @returns {string} Sanitized html.
|
46
59
|
*
|
47
60
|
* @example
|
48
61
|
<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
|
-
|
62
|
+
<doc:source>
|
63
|
+
<script>
|
64
|
+
function Ctrl($scope, $sce) {
|
65
|
+
$scope.snippet =
|
66
|
+
'<p style="color:blue">an html\n' +
|
67
|
+
'<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' +
|
68
|
+
'snippet</p>';
|
69
|
+
$scope.deliberatelyTrustDangerousSnippet = function() {
|
70
|
+
return $sce.trustAsHtml($scope.snippet);
|
71
|
+
};
|
72
|
+
}
|
73
|
+
</script>
|
74
|
+
<div ng-controller="Ctrl">
|
75
|
+
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
|
76
|
+
<table>
|
77
|
+
<tr>
|
78
|
+
<td>Directive</td>
|
79
|
+
<td>How</td>
|
80
|
+
<td>Source</td>
|
81
|
+
<td>Rendered</td>
|
82
|
+
</tr>
|
83
|
+
<tr id="bind-html-with-sanitize">
|
84
|
+
<td>ng-bind-html</td>
|
85
|
+
<td>Automatically uses $sanitize</td>
|
86
|
+
<td><pre><div ng-bind-html="snippet"><br/></div></pre></td>
|
87
|
+
<td><div ng-bind-html="snippet"></div></td>
|
88
|
+
</tr>
|
89
|
+
<tr id="bind-html-with-trust">
|
90
|
+
<td>ng-bind-html</td>
|
91
|
+
<td>Bypass $sanitize by explicitly trusting the dangerous value</td>
|
92
|
+
<td>
|
93
|
+
<pre><div ng-bind-html="deliberatelyTrustDangerousSnippet()">
|
94
|
+
</div></pre>
|
95
|
+
</td>
|
96
|
+
<td><div ng-bind-html="deliberatelyTrustDangerousSnippet()"></div></td>
|
97
|
+
</tr>
|
98
|
+
<tr id="bind-default">
|
99
|
+
<td>ng-bind</td>
|
100
|
+
<td>Automatically escapes</td>
|
101
|
+
<td><pre><div ng-bind="snippet"><br/></div></pre></td>
|
102
|
+
<td><div ng-bind="snippet"></div></td>
|
103
|
+
</tr>
|
104
|
+
</table>
|
105
|
+
</div>
|
106
|
+
</doc:source>
|
107
|
+
<doc:scenario>
|
108
|
+
it('should sanitize the html snippet by default', function() {
|
109
|
+
expect(using('#bind-html-with-sanitize').element('div').html()).
|
110
|
+
toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
|
111
|
+
});
|
112
|
+
|
113
|
+
it('should inline raw snippet if bound to a trusted value', function() {
|
114
|
+
expect(using('#bind-html-with-trust').element("div").html()).
|
115
|
+
toBe("<p style=\"color:blue\">an html\n" +
|
116
|
+
"<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
|
117
|
+
"snippet</p>");
|
118
|
+
});
|
119
|
+
|
120
|
+
it('should escape snippet without any filter', function() {
|
121
|
+
expect(using('#bind-default').element('div').html()).
|
122
|
+
toBe("<p style=\"color:blue\">an html\n" +
|
123
|
+
"<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
|
124
|
+
"snippet</p>");
|
125
|
+
});
|
126
|
+
|
127
|
+
it('should update', function() {
|
128
|
+
input('snippet').enter('new <b onclick="alert(1)">text</b>');
|
129
|
+
expect(using('#bind-html-with-sanitize').element('div').html()).toBe('new <b>text</b>');
|
130
|
+
expect(using('#bind-html-with-trust').element('div').html()).toBe(
|
131
|
+
'new <b onclick="alert(1)">text</b>');
|
132
|
+
expect(using('#bind-default').element('div').html()).toBe(
|
133
|
+
"new <b onclick=\"alert(1)\">text</b>");
|
134
|
+
});
|
135
|
+
</doc:scenario>
|
115
136
|
</doc:example>
|
116
137
|
*/
|
117
|
-
|
138
|
+
function $SanitizeProvider() {
|
139
|
+
this.$get = ['$$sanitizeUri', function($$sanitizeUri) {
|
140
|
+
return function(html) {
|
141
|
+
var buf = [];
|
142
|
+
htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) {
|
143
|
+
return !/^unsafe/.test($$sanitizeUri(uri, isImage));
|
144
|
+
}));
|
145
|
+
return buf.join('');
|
146
|
+
};
|
147
|
+
}];
|
148
|
+
}
|
149
|
+
|
150
|
+
function sanitizeText(chars) {
|
118
151
|
var buf = [];
|
119
|
-
|
120
|
-
|
121
|
-
|
152
|
+
var writer = htmlSanitizeWriter(buf, angular.noop);
|
153
|
+
writer.chars(chars);
|
154
|
+
return buf.join('');
|
155
|
+
}
|
122
156
|
|
123
157
|
|
124
158
|
// Regular Expressions for parsing tags and attributes
|
125
|
-
var START_TAG_REGEXP =
|
159
|
+
var START_TAG_REGEXP =
|
160
|
+
/^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/,
|
126
161
|
END_TAG_REGEXP = /^<\s*\/\s*([\w:-]+)[^>]*>/,
|
127
162
|
ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,
|
128
163
|
BEGIN_TAG_REGEXP = /^</,
|
129
164
|
BEGING_END_TAGE_REGEXP = /^<\s*\//,
|
130
165
|
COMMENT_REGEXP = /<!--(.*?)-->/g,
|
166
|
+
DOCTYPE_REGEXP = /<!DOCTYPE([^>]*?)>/i,
|
131
167
|
CDATA_REGEXP = /<!\[CDATA\[(.*?)]]>/g,
|
132
|
-
|
133
|
-
NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g;
|
168
|
+
// Match everything outside of normal chars and " (quote character)
|
169
|
+
NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g;
|
134
170
|
|
135
171
|
|
136
172
|
// Good source of info about elements and attributes
|
@@ -145,23 +181,29 @@ var voidElements = makeMap("area,br,col,hr,img,wbr");
|
|
145
181
|
// http://dev.w3.org/html5/spec/Overview.html#optional-tags
|
146
182
|
var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),
|
147
183
|
optionalEndTagInlineElements = makeMap("rp,rt"),
|
148
|
-
optionalEndTagElements = angular.extend({},
|
184
|
+
optionalEndTagElements = angular.extend({},
|
185
|
+
optionalEndTagInlineElements,
|
186
|
+
optionalEndTagBlockElements);
|
149
187
|
|
150
188
|
// 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"));
|
189
|
+
var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("address,article," +
|
190
|
+
"aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5," +
|
191
|
+
"h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul"));
|
154
192
|
|
155
193
|
// 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"));
|
194
|
+
var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b," +
|
195
|
+
"bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," +
|
196
|
+
"samp,small,span,strike,strong,sub,sup,time,tt,u,var"));
|
159
197
|
|
160
198
|
|
161
199
|
// Special Elements (can contain anything)
|
162
200
|
var specialElements = makeMap("script,style");
|
163
201
|
|
164
|
-
var validElements = angular.extend({},
|
202
|
+
var validElements = angular.extend({},
|
203
|
+
voidElements,
|
204
|
+
blockElements,
|
205
|
+
inlineElements,
|
206
|
+
optionalEndTagElements);
|
165
207
|
|
166
208
|
//Attributes that have href and hence need to be sanitized
|
167
209
|
var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap");
|
@@ -203,14 +245,22 @@ function htmlParser( html, handler ) {
|
|
203
245
|
|
204
246
|
// Comment
|
205
247
|
if ( html.indexOf("<!--") === 0 ) {
|
206
|
-
|
248
|
+
// comments containing -- are not allowed unless they terminate the comment
|
249
|
+
index = html.indexOf("--", 4);
|
207
250
|
|
208
|
-
if ( index >= 0 ) {
|
251
|
+
if ( index >= 0 && html.lastIndexOf("-->", index) === index) {
|
209
252
|
if (handler.comment) handler.comment( html.substring( 4, index ) );
|
210
253
|
html = html.substring( index + 3 );
|
211
254
|
chars = false;
|
212
255
|
}
|
256
|
+
// DOCTYPE
|
257
|
+
} else if ( DOCTYPE_REGEXP.test(html) ) {
|
258
|
+
match = html.match( DOCTYPE_REGEXP );
|
213
259
|
|
260
|
+
if ( match ) {
|
261
|
+
html = html.replace( match[0] , '');
|
262
|
+
chars = false;
|
263
|
+
}
|
214
264
|
// end tag
|
215
265
|
} else if ( BEGING_END_TAGE_REGEXP.test(html) ) {
|
216
266
|
match = html.match( END_TAG_REGEXP );
|
@@ -242,21 +292,21 @@ function htmlParser( html, handler ) {
|
|
242
292
|
}
|
243
293
|
|
244
294
|
} else {
|
245
|
-
html = html.replace(new RegExp("(.*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'),
|
246
|
-
|
247
|
-
replace(COMMENT_REGEXP, "$1").
|
248
|
-
replace(CDATA_REGEXP, "$1");
|
295
|
+
html = html.replace(new RegExp("(.*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'),
|
296
|
+
function(all, text){
|
297
|
+
text = text.replace(COMMENT_REGEXP, "$1").replace(CDATA_REGEXP, "$1");
|
249
298
|
|
250
|
-
|
299
|
+
if (handler.chars) handler.chars( decodeEntities(text) );
|
251
300
|
|
252
|
-
|
301
|
+
return "";
|
253
302
|
});
|
254
303
|
|
255
304
|
parseEndTag( "", stack.last() );
|
256
305
|
}
|
257
306
|
|
258
307
|
if ( html == last ) {
|
259
|
-
throw "
|
308
|
+
throw $sanitizeMinErr('badparse', "The sanitizer was unable to parse the following block " +
|
309
|
+
"of html: {0}", html);
|
260
310
|
}
|
261
311
|
last = html;
|
262
312
|
}
|
@@ -283,13 +333,14 @@ function htmlParser( html, handler ) {
|
|
283
333
|
|
284
334
|
var attrs = {};
|
285
335
|
|
286
|
-
rest.replace(ATTR_REGEXP,
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
336
|
+
rest.replace(ATTR_REGEXP,
|
337
|
+
function(match, name, doubleQuotedValue, singleQuotedValue, unquotedValue) {
|
338
|
+
var value = doubleQuotedValue
|
339
|
+
|| singleQuotedValue
|
340
|
+
|| unquotedValue
|
341
|
+
|| '';
|
291
342
|
|
292
|
-
|
343
|
+
attrs[name] = decodeEntities(value);
|
293
344
|
});
|
294
345
|
if (handler.start) handler.start( tagName, attrs, unary );
|
295
346
|
}
|
@@ -314,15 +365,32 @@ function htmlParser( html, handler ) {
|
|
314
365
|
}
|
315
366
|
}
|
316
367
|
|
368
|
+
var hiddenPre=document.createElement("pre");
|
369
|
+
var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/;
|
317
370
|
/**
|
318
371
|
* decodes all entities into regular string
|
319
372
|
* @param value
|
320
373
|
* @returns {string} A string with decoded entities.
|
321
374
|
*/
|
322
|
-
var hiddenPre=document.createElement("pre");
|
323
375
|
function decodeEntities(value) {
|
324
|
-
|
325
|
-
|
376
|
+
if (!value) { return ''; }
|
377
|
+
|
378
|
+
// Note: IE8 does not preserve spaces at the start/end of innerHTML
|
379
|
+
// so we must capture them and reattach them afterward
|
380
|
+
var parts = spaceRe.exec(value);
|
381
|
+
var spaceBefore = parts[1];
|
382
|
+
var spaceAfter = parts[3];
|
383
|
+
var content = parts[2];
|
384
|
+
if (content) {
|
385
|
+
hiddenPre.innerHTML=content.replace(/</g,"<");
|
386
|
+
// innerText depends on styling as it doesn't display hidden elements.
|
387
|
+
// Therefore, it's better to use textContent not to cause unnecessary
|
388
|
+
// reflows. However, IE<9 don't support textContent so the innerText
|
389
|
+
// fallback is necessary.
|
390
|
+
content = 'textContent' in hiddenPre ?
|
391
|
+
hiddenPre.textContent : hiddenPre.innerText;
|
392
|
+
}
|
393
|
+
return spaceBefore + content + spaceAfter;
|
326
394
|
}
|
327
395
|
|
328
396
|
/**
|
@@ -352,7 +420,7 @@ function encodeEntities(value) {
|
|
352
420
|
* comment: function(text) {}
|
353
421
|
* }
|
354
422
|
*/
|
355
|
-
function htmlSanitizeWriter(buf){
|
423
|
+
function htmlSanitizeWriter(buf, uriValidator){
|
356
424
|
var ignore = false;
|
357
425
|
var out = angular.bind(buf, buf.push);
|
358
426
|
return {
|
@@ -361,12 +429,14 @@ function htmlSanitizeWriter(buf){
|
|
361
429
|
if (!ignore && specialElements[tag]) {
|
362
430
|
ignore = tag;
|
363
431
|
}
|
364
|
-
if (!ignore && validElements[tag]
|
432
|
+
if (!ignore && validElements[tag] === true) {
|
365
433
|
out('<');
|
366
434
|
out(tag);
|
367
435
|
angular.forEach(attrs, function(value, key){
|
368
436
|
var lkey=angular.lowercase(key);
|
369
|
-
|
437
|
+
var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background');
|
438
|
+
if (validAttrs[lkey] === true &&
|
439
|
+
(uriAttrs[lkey] !== true || uriValidator(value, isImage))) {
|
370
440
|
out(' ');
|
371
441
|
out(key);
|
372
442
|
out('="');
|
@@ -379,7 +449,7 @@ function htmlSanitizeWriter(buf){
|
|
379
449
|
},
|
380
450
|
end: function(tag){
|
381
451
|
tag = angular.lowercase(tag);
|
382
|
-
if (!ignore && validElements[tag]
|
452
|
+
if (!ignore && validElements[tag] === true) {
|
383
453
|
out('</');
|
384
454
|
out(tag);
|
385
455
|
out('>');
|
@@ -398,30 +468,9 @@ function htmlSanitizeWriter(buf){
|
|
398
468
|
|
399
469
|
|
400
470
|
// define ngSanitize module and register $sanitize service
|
401
|
-
angular.module('ngSanitize', []).
|
471
|
+
angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
402
472
|
|
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
|
-
}]);
|
473
|
+
/* global sanitizeText: false */
|
425
474
|
|
426
475
|
/**
|
427
476
|
* @ngdoc filter
|
@@ -429,8 +478,10 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
|
|
429
478
|
* @function
|
430
479
|
*
|
431
480
|
* @description
|
432
|
-
*
|
433
|
-
*
|
481
|
+
* Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and
|
482
|
+
* plain email address links.
|
483
|
+
*
|
484
|
+
* Requires the {@link ngSanitize `ngSanitize`} module to be installed.
|
434
485
|
*
|
435
486
|
* @param {string} text Input text.
|
436
487
|
* @param {string} target Window (_blank|_self|_parent|_top) or named frame to open links in.
|
@@ -519,8 +570,9 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
|
|
519
570
|
</doc:scenario>
|
520
571
|
</doc:example>
|
521
572
|
*/
|
522
|
-
angular.module('ngSanitize').filter('linky', function() {
|
523
|
-
var LINKY_URL_REGEXP =
|
573
|
+
angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
|
574
|
+
var LINKY_URL_REGEXP =
|
575
|
+
/((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>]/,
|
524
576
|
MAILTO_REGEXP = /^mailto:/;
|
525
577
|
|
526
578
|
return function(text, target) {
|
@@ -528,31 +580,43 @@ angular.module('ngSanitize').filter('linky', function() {
|
|
528
580
|
var match;
|
529
581
|
var raw = text;
|
530
582
|
var html = [];
|
531
|
-
// TODO(vojta): use $sanitize instead
|
532
|
-
var writer = htmlSanitizeWriter(html);
|
533
583
|
var url;
|
534
584
|
var i;
|
535
|
-
var properties = {};
|
536
|
-
if (angular.isDefined(target)) {
|
537
|
-
properties.target = target;
|
538
|
-
}
|
539
585
|
while ((match = raw.match(LINKY_URL_REGEXP))) {
|
540
586
|
// We can not end in these as they are sometimes found at the end of the sentence
|
541
587
|
url = match[0];
|
542
588
|
// if we did not match ftp/http/mailto then assume mailto
|
543
589
|
if (match[2] == match[3]) url = 'mailto:' + url;
|
544
590
|
i = match.index;
|
545
|
-
|
546
|
-
|
547
|
-
writer.start('a', properties);
|
548
|
-
writer.chars(match[0].replace(MAILTO_REGEXP, ''));
|
549
|
-
writer.end('a');
|
591
|
+
addText(raw.substr(0, i));
|
592
|
+
addLink(url, match[0].replace(MAILTO_REGEXP, ''));
|
550
593
|
raw = raw.substring(i + match[0].length);
|
551
594
|
}
|
552
|
-
|
553
|
-
return html.join('');
|
595
|
+
addText(raw);
|
596
|
+
return $sanitize(html.join(''));
|
597
|
+
|
598
|
+
function addText(text) {
|
599
|
+
if (!text) {
|
600
|
+
return;
|
601
|
+
}
|
602
|
+
html.push(sanitizeText(text));
|
603
|
+
}
|
604
|
+
|
605
|
+
function addLink(url, text) {
|
606
|
+
html.push('<a ');
|
607
|
+
if (angular.isDefined(target)) {
|
608
|
+
html.push('target="');
|
609
|
+
html.push(target);
|
610
|
+
html.push('" ');
|
611
|
+
}
|
612
|
+
html.push('href="');
|
613
|
+
html.push(url);
|
614
|
+
html.push('">');
|
615
|
+
addText(text);
|
616
|
+
html.push('</a>');
|
617
|
+
}
|
554
618
|
};
|
555
|
-
});
|
619
|
+
}]);
|
556
620
|
|
557
621
|
|
558
622
|
})(window, window.angular);
|