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.
@@ -1,15 +1,26 @@
1
1
  /**
2
- * @license AngularJS v1.1.4
3
- * (c) 2010-2012 Google, Inc. http://angularjs.org
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
- 'use strict';
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
- <doc:source>
50
- <script>
51
- function Ctrl($scope) {
52
- $scope.snippet =
53
- '<p style="color:blue">an html\n' +
54
- '<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' +
55
- 'snippet</p>';
56
- }
57
- </script>
58
- <div ng-controller="Ctrl">
59
- Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
60
- <table>
61
- <tr>
62
- <td>Filter</td>
63
- <td>Source</td>
64
- <td>Rendered</td>
65
- </tr>
66
- <tr id="html-filter">
67
- <td>html filter</td>
68
- <td>
69
- <pre>&lt;div ng-bind-html="snippet"&gt;<br/>&lt;/div&gt;</pre>
70
- </td>
71
- <td>
72
- <div ng-bind-html="snippet"></div>
73
- </td>
74
- </tr>
75
- <tr id="escaped-html">
76
- <td>no filter</td>
77
- <td><pre>&lt;div ng-bind="snippet"&gt;<br/>&lt;/div&gt;</pre></td>
78
- <td><div ng-bind="snippet"></div></td>
79
- </tr>
80
- <tr id="html-unsafe-filter">
81
- <td>unsafe html filter</td>
82
- <td><pre>&lt;div ng-bind-html-unsafe="snippet"&gt;<br/>&lt;/div&gt;</pre></td>
83
- <td><div ng-bind-html-unsafe="snippet"></div></td>
84
- </tr>
85
- </table>
86
- </div>
87
- </doc:source>
88
- <doc:scenario>
89
- it('should sanitize the html snippet ', function() {
90
- expect(using('#html-filter').element('div').html()).
91
- toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
92
- });
93
-
94
- it('should escape snippet without any filter', function() {
95
- expect(using('#escaped-html').element('div').html()).
96
- toBe("&lt;p style=\"color:blue\"&gt;an html\n" +
97
- "&lt;em onmouseover=\"this.textContent='PWN3D!'\"&gt;click here&lt;/em&gt;\n" +
98
- "snippet&lt;/p&gt;");
99
- });
100
-
101
- it('should inline raw snippet if filtered as unsafe', function() {
102
- expect(using('#html-unsafe-filter').element("div").html()).
103
- toBe("<p style=\"color:blue\">an html\n" +
104
- "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
105
- "snippet</p>");
106
- });
107
-
108
- it('should update', function() {
109
- input('snippet').enter('new <b>text</b>');
110
- expect(using('#html-filter').binding('snippet')).toBe('new <b>text</b>');
111
- expect(using('#escaped-html').element('div').html()).toBe("new &lt;b&gt;text&lt;/b&gt;");
112
- expect(using('#html-unsafe-filter').binding("snippet")).toBe('new <b>text</b>');
113
- });
114
- </doc:scenario>
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>&lt;div ng-bind-html="snippet"&gt;<br/>&lt;/div&gt;</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>&lt;div ng-bind-html="deliberatelyTrustDangerousSnippet()"&gt;
94
+ &lt;/div&gt;</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>&lt;div ng-bind="snippet"&gt;<br/>&lt;/div&gt;</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("&lt;p style=\"color:blue\"&gt;an html\n" +
123
+ "&lt;em onmouseover=\"this.textContent='PWN3D!'\"&gt;click here&lt;/em&gt;\n" +
124
+ "snippet&lt;/p&gt;");
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 &lt;b onclick=\"alert(1)\"&gt;text&lt;/b&gt;");
134
+ });
135
+ </doc:scenario>
115
136
  </doc:example>
116
137
  */
117
- var $sanitize = function(html) {
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
- htmlParser(html, htmlSanitizeWriter(buf));
120
- return buf.join('');
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 = /^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/,
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
- URI_REGEXP = /^((ftp|https?):\/\/|mailto:|tel:|#)/,
133
- NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; // Match everything outside of normal chars and " (quote character)
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({}, optionalEndTagInlineElements, optionalEndTagBlockElements);
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,aside," +
152
- "blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6," +
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,bdi,bdo," +
157
- "big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small," +
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({}, voidElements, blockElements, inlineElements, optionalEndTagElements);
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
- index = html.indexOf("-->");
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'), function(all, text){
246
- text = text.
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
- if (handler.chars) handler.chars( decodeEntities(text) );
299
+ if (handler.chars) handler.chars( decodeEntities(text) );
251
300
 
252
- return "";
301
+ return "";
253
302
  });
254
303
 
255
304
  parseEndTag( "", stack.last() );
256
305
  }
257
306
 
258
307
  if ( html == last ) {
259
- throw "Parse Error: " + html;
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, function(match, name, doubleQuotedValue, singleQoutedValue, unqoutedValue) {
287
- var value = doubleQuotedValue
288
- || singleQoutedValue
289
- || unqoutedValue
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
- attrs[name] = decodeEntities(value);
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
- hiddenPre.innerHTML=value.replace(/</g,"&lt;");
325
- return hiddenPre.innerText || hiddenPre.textContent || '';
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,"&lt;");
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] == true) {
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
- if (validAttrs[lkey]==true && (uriAttrs[lkey]!==true || value.match(URI_REGEXP))) {
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] == true) {
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', []).value('$sanitize', $sanitize);
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
- * Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and
433
- * plain email address links.
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 = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}\<\>]/,
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
- writer.chars(raw.substr(0, i));
546
- properties.href = url;
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
- writer.chars(raw);
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);