angularjs-rails 1.3.15 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/lib/angularjs-rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/angular-animate.js +3443 -1872
  4. data/vendor/assets/javascripts/angular-aria.js +89 -75
  5. data/vendor/assets/javascripts/angular-cookies.js +255 -141
  6. data/vendor/assets/javascripts/angular-loader.js +41 -17
  7. data/vendor/assets/javascripts/angular-message-format.js +980 -0
  8. data/vendor/assets/javascripts/angular-messages.js +430 -153
  9. data/vendor/assets/javascripts/angular-mocks.js +76 -92
  10. data/vendor/assets/javascripts/angular-resource.js +6 -6
  11. data/vendor/assets/javascripts/angular-route.js +8 -6
  12. data/vendor/assets/javascripts/angular-sanitize.js +32 -28
  13. data/vendor/assets/javascripts/angular-scenario.js +4315 -2452
  14. data/vendor/assets/javascripts/angular-touch.js +26 -21
  15. data/vendor/assets/javascripts/angular.js +4314 -2490
  16. data/vendor/assets/javascripts/unstable/angular2.js +24024 -0
  17. metadata +4 -14
  18. data/vendor/assets/javascripts/unstable/angular-animate.js +0 -2137
  19. data/vendor/assets/javascripts/unstable/angular-aria.js +0 -364
  20. data/vendor/assets/javascripts/unstable/angular-cookies.js +0 -206
  21. data/vendor/assets/javascripts/unstable/angular-loader.js +0 -405
  22. data/vendor/assets/javascripts/unstable/angular-messages.js +0 -401
  23. data/vendor/assets/javascripts/unstable/angular-mocks.js +0 -2468
  24. data/vendor/assets/javascripts/unstable/angular-resource.js +0 -668
  25. data/vendor/assets/javascripts/unstable/angular-route.js +0 -989
  26. data/vendor/assets/javascripts/unstable/angular-sanitize.js +0 -679
  27. data/vendor/assets/javascripts/unstable/angular-scenario.js +0 -37678
  28. data/vendor/assets/javascripts/unstable/angular-touch.js +0 -622
  29. data/vendor/assets/javascripts/unstable/angular.js +0 -26309
@@ -1,679 +0,0 @@
1
- /**
2
- * @license AngularJS v1.3.15
3
- * (c) 2010-2014 Google, Inc. http://angularjs.org
4
- * License: MIT
5
- */
6
- (function(window, angular, undefined) {'use strict';
7
-
8
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
9
- * Any commits to this file should be reviewed with security in mind. *
10
- * Changes to this file can potentially create security vulnerabilities. *
11
- * An approval from 2 Core members with history of modifying *
12
- * this file is required. *
13
- * *
14
- * Does the change somehow allow for arbitrary javascript to be executed? *
15
- * Or allows for someone to change the prototype of built-in objects? *
16
- * Or gives undesired access to variables likes document or window? *
17
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
18
-
19
- var $sanitizeMinErr = angular.$$minErr('$sanitize');
20
-
21
- /**
22
- * @ngdoc module
23
- * @name ngSanitize
24
- * @description
25
- *
26
- * # ngSanitize
27
- *
28
- * The `ngSanitize` module provides functionality to sanitize HTML.
29
- *
30
- *
31
- * <div doc-module-components="ngSanitize"></div>
32
- *
33
- * See {@link ngSanitize.$sanitize `$sanitize`} for usage.
34
- */
35
-
36
- /*
37
- * HTML Parser By Misko Hevery (misko@hevery.com)
38
- * based on: HTML Parser By John Resig (ejohn.org)
39
- * Original code by Erik Arvidsson, Mozilla Public License
40
- * http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
41
- *
42
- * // Use like so:
43
- * htmlParser(htmlString, {
44
- * start: function(tag, attrs, unary) {},
45
- * end: function(tag) {},
46
- * chars: function(text) {},
47
- * comment: function(text) {}
48
- * });
49
- *
50
- */
51
-
52
-
53
- /**
54
- * @ngdoc service
55
- * @name $sanitize
56
- * @kind function
57
- *
58
- * @description
59
- * The input is sanitized by parsing the HTML into tokens. All safe tokens (from a whitelist) are
60
- * then serialized back to properly escaped html string. This means that no unsafe input can make
61
- * it into the returned string, however, since our parser is more strict than a typical browser
62
- * parser, it's possible that some obscure input, which would be recognized as valid HTML by a
63
- * browser, won't make it through the sanitizer. The input may also contain SVG markup.
64
- * The whitelist is configured using the functions `aHrefSanitizationWhitelist` and
65
- * `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider `$compileProvider`}.
66
- *
67
- * @param {string} html HTML input.
68
- * @returns {string} Sanitized HTML.
69
- *
70
- * @example
71
- <example module="sanitizeExample" deps="angular-sanitize.js">
72
- <file name="index.html">
73
- <script>
74
- angular.module('sanitizeExample', ['ngSanitize'])
75
- .controller('ExampleController', ['$scope', '$sce', function($scope, $sce) {
76
- $scope.snippet =
77
- '<p style="color:blue">an html\n' +
78
- '<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' +
79
- 'snippet</p>';
80
- $scope.deliberatelyTrustDangerousSnippet = function() {
81
- return $sce.trustAsHtml($scope.snippet);
82
- };
83
- }]);
84
- </script>
85
- <div ng-controller="ExampleController">
86
- Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
87
- <table>
88
- <tr>
89
- <td>Directive</td>
90
- <td>How</td>
91
- <td>Source</td>
92
- <td>Rendered</td>
93
- </tr>
94
- <tr id="bind-html-with-sanitize">
95
- <td>ng-bind-html</td>
96
- <td>Automatically uses $sanitize</td>
97
- <td><pre>&lt;div ng-bind-html="snippet"&gt;<br/>&lt;/div&gt;</pre></td>
98
- <td><div ng-bind-html="snippet"></div></td>
99
- </tr>
100
- <tr id="bind-html-with-trust">
101
- <td>ng-bind-html</td>
102
- <td>Bypass $sanitize by explicitly trusting the dangerous value</td>
103
- <td>
104
- <pre>&lt;div ng-bind-html="deliberatelyTrustDangerousSnippet()"&gt;
105
- &lt;/div&gt;</pre>
106
- </td>
107
- <td><div ng-bind-html="deliberatelyTrustDangerousSnippet()"></div></td>
108
- </tr>
109
- <tr id="bind-default">
110
- <td>ng-bind</td>
111
- <td>Automatically escapes</td>
112
- <td><pre>&lt;div ng-bind="snippet"&gt;<br/>&lt;/div&gt;</pre></td>
113
- <td><div ng-bind="snippet"></div></td>
114
- </tr>
115
- </table>
116
- </div>
117
- </file>
118
- <file name="protractor.js" type="protractor">
119
- it('should sanitize the html snippet by default', function() {
120
- expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
121
- toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
122
- });
123
-
124
- it('should inline raw snippet if bound to a trusted value', function() {
125
- expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).
126
- toBe("<p style=\"color:blue\">an html\n" +
127
- "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
128
- "snippet</p>");
129
- });
130
-
131
- it('should escape snippet without any filter', function() {
132
- expect(element(by.css('#bind-default div')).getInnerHtml()).
133
- toBe("&lt;p style=\"color:blue\"&gt;an html\n" +
134
- "&lt;em onmouseover=\"this.textContent='PWN3D!'\"&gt;click here&lt;/em&gt;\n" +
135
- "snippet&lt;/p&gt;");
136
- });
137
-
138
- it('should update', function() {
139
- element(by.model('snippet')).clear();
140
- element(by.model('snippet')).sendKeys('new <b onclick="alert(1)">text</b>');
141
- expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
142
- toBe('new <b>text</b>');
143
- expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).toBe(
144
- 'new <b onclick="alert(1)">text</b>');
145
- expect(element(by.css('#bind-default div')).getInnerHtml()).toBe(
146
- "new &lt;b onclick=\"alert(1)\"&gt;text&lt;/b&gt;");
147
- });
148
- </file>
149
- </example>
150
- */
151
- function $SanitizeProvider() {
152
- this.$get = ['$$sanitizeUri', function($$sanitizeUri) {
153
- return function(html) {
154
- var buf = [];
155
- htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) {
156
- return !/^unsafe/.test($$sanitizeUri(uri, isImage));
157
- }));
158
- return buf.join('');
159
- };
160
- }];
161
- }
162
-
163
- function sanitizeText(chars) {
164
- var buf = [];
165
- var writer = htmlSanitizeWriter(buf, angular.noop);
166
- writer.chars(chars);
167
- return buf.join('');
168
- }
169
-
170
-
171
- // Regular Expressions for parsing tags and attributes
172
- var START_TAG_REGEXP =
173
- /^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/,
174
- END_TAG_REGEXP = /^<\/\s*([\w:-]+)[^>]*>/,
175
- ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,
176
- BEGIN_TAG_REGEXP = /^</,
177
- BEGING_END_TAGE_REGEXP = /^<\//,
178
- COMMENT_REGEXP = /<!--(.*?)-->/g,
179
- DOCTYPE_REGEXP = /<!DOCTYPE([^>]*?)>/i,
180
- CDATA_REGEXP = /<!\[CDATA\[(.*?)]]>/g,
181
- SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
182
- // Match everything outside of normal chars and " (quote character)
183
- NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g;
184
-
185
-
186
- // Good source of info about elements and attributes
187
- // http://dev.w3.org/html5/spec/Overview.html#semantics
188
- // http://simon.html5.org/html-elements
189
-
190
- // Safe Void Elements - HTML5
191
- // http://dev.w3.org/html5/spec/Overview.html#void-elements
192
- var voidElements = makeMap("area,br,col,hr,img,wbr");
193
-
194
- // Elements that you can, intentionally, leave open (and which close themselves)
195
- // http://dev.w3.org/html5/spec/Overview.html#optional-tags
196
- var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),
197
- optionalEndTagInlineElements = makeMap("rp,rt"),
198
- optionalEndTagElements = angular.extend({},
199
- optionalEndTagInlineElements,
200
- optionalEndTagBlockElements);
201
-
202
- // Safe Block Elements - HTML5
203
- var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("address,article," +
204
- "aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5," +
205
- "h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul"));
206
-
207
- // Inline Elements - HTML5
208
- var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b," +
209
- "bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," +
210
- "samp,small,span,strike,strong,sub,sup,time,tt,u,var"));
211
-
212
- // SVG Elements
213
- // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements
214
- var svgElements = makeMap("animate,animateColor,animateMotion,animateTransform,circle,defs," +
215
- "desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,hkern,image,linearGradient," +
216
- "line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,radialGradient,rect,set," +
217
- "stop,svg,switch,text,title,tspan,use");
218
-
219
- // Special Elements (can contain anything)
220
- var specialElements = makeMap("script,style");
221
-
222
- var validElements = angular.extend({},
223
- voidElements,
224
- blockElements,
225
- inlineElements,
226
- optionalEndTagElements,
227
- svgElements);
228
-
229
- //Attributes that have href and hence need to be sanitized
230
- var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap,xlink:href");
231
-
232
- var htmlAttrs = makeMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' +
233
- 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,' +
234
- 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,' +
235
- 'scope,scrolling,shape,size,span,start,summary,target,title,type,' +
236
- 'valign,value,vspace,width');
237
-
238
- // SVG attributes (without "id" and "name" attributes)
239
- // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes
240
- var svgAttrs = makeMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' +
241
- 'attributeName,attributeType,baseProfile,bbox,begin,by,calcMode,cap-height,class,color,' +
242
- 'color-rendering,content,cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,' +
243
- 'font-size,font-stretch,font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,' +
244
- 'gradientUnits,hanging,height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,' +
245
- 'keySplines,keyTimes,lang,marker-end,marker-mid,marker-start,markerHeight,markerUnits,' +
246
- 'markerWidth,mathematical,max,min,offset,opacity,orient,origin,overline-position,' +
247
- 'overline-thickness,panose-1,path,pathLength,points,preserveAspectRatio,r,refX,refY,' +
248
- 'repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,' +
249
- 'stemv,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,stroke,' +
250
- 'stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,' +
251
- 'stroke-opacity,stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,' +
252
- 'underline-position,underline-thickness,unicode,unicode-range,units-per-em,values,version,' +
253
- 'viewBox,visibility,width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,' +
254
- 'xlink:show,xlink:title,xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,' +
255
- 'zoomAndPan');
256
-
257
- var validAttrs = angular.extend({},
258
- uriAttrs,
259
- svgAttrs,
260
- htmlAttrs);
261
-
262
- function makeMap(str) {
263
- var obj = {}, items = str.split(','), i;
264
- for (i = 0; i < items.length; i++) obj[items[i]] = true;
265
- return obj;
266
- }
267
-
268
-
269
- /**
270
- * @example
271
- * htmlParser(htmlString, {
272
- * start: function(tag, attrs, unary) {},
273
- * end: function(tag) {},
274
- * chars: function(text) {},
275
- * comment: function(text) {}
276
- * });
277
- *
278
- * @param {string} html string
279
- * @param {object} handler
280
- */
281
- function htmlParser(html, handler) {
282
- if (typeof html !== 'string') {
283
- if (html === null || typeof html === 'undefined') {
284
- html = '';
285
- } else {
286
- html = '' + html;
287
- }
288
- }
289
- var index, chars, match, stack = [], last = html, text;
290
- stack.last = function() { return stack[stack.length - 1]; };
291
-
292
- while (html) {
293
- text = '';
294
- chars = true;
295
-
296
- // Make sure we're not in a script or style element
297
- if (!stack.last() || !specialElements[stack.last()]) {
298
-
299
- // Comment
300
- if (html.indexOf("<!--") === 0) {
301
- // comments containing -- are not allowed unless they terminate the comment
302
- index = html.indexOf("--", 4);
303
-
304
- if (index >= 0 && html.lastIndexOf("-->", index) === index) {
305
- if (handler.comment) handler.comment(html.substring(4, index));
306
- html = html.substring(index + 3);
307
- chars = false;
308
- }
309
- // DOCTYPE
310
- } else if (DOCTYPE_REGEXP.test(html)) {
311
- match = html.match(DOCTYPE_REGEXP);
312
-
313
- if (match) {
314
- html = html.replace(match[0], '');
315
- chars = false;
316
- }
317
- // end tag
318
- } else if (BEGING_END_TAGE_REGEXP.test(html)) {
319
- match = html.match(END_TAG_REGEXP);
320
-
321
- if (match) {
322
- html = html.substring(match[0].length);
323
- match[0].replace(END_TAG_REGEXP, parseEndTag);
324
- chars = false;
325
- }
326
-
327
- // start tag
328
- } else if (BEGIN_TAG_REGEXP.test(html)) {
329
- match = html.match(START_TAG_REGEXP);
330
-
331
- if (match) {
332
- // We only have a valid start-tag if there is a '>'.
333
- if (match[4]) {
334
- html = html.substring(match[0].length);
335
- match[0].replace(START_TAG_REGEXP, parseStartTag);
336
- }
337
- chars = false;
338
- } else {
339
- // no ending tag found --- this piece should be encoded as an entity.
340
- text += '<';
341
- html = html.substring(1);
342
- }
343
- }
344
-
345
- if (chars) {
346
- index = html.indexOf("<");
347
-
348
- text += index < 0 ? html : html.substring(0, index);
349
- html = index < 0 ? "" : html.substring(index);
350
-
351
- if (handler.chars) handler.chars(decodeEntities(text));
352
- }
353
-
354
- } else {
355
- // IE versions 9 and 10 do not understand the regex '[^]', so using a workaround with [\W\w].
356
- html = html.replace(new RegExp("([\\W\\w]*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'),
357
- function(all, text) {
358
- text = text.replace(COMMENT_REGEXP, "$1").replace(CDATA_REGEXP, "$1");
359
-
360
- if (handler.chars) handler.chars(decodeEntities(text));
361
-
362
- return "";
363
- });
364
-
365
- parseEndTag("", stack.last());
366
- }
367
-
368
- if (html == last) {
369
- throw $sanitizeMinErr('badparse', "The sanitizer was unable to parse the following block " +
370
- "of html: {0}", html);
371
- }
372
- last = html;
373
- }
374
-
375
- // Clean up any remaining tags
376
- parseEndTag();
377
-
378
- function parseStartTag(tag, tagName, rest, unary) {
379
- tagName = angular.lowercase(tagName);
380
- if (blockElements[tagName]) {
381
- while (stack.last() && inlineElements[stack.last()]) {
382
- parseEndTag("", stack.last());
383
- }
384
- }
385
-
386
- if (optionalEndTagElements[tagName] && stack.last() == tagName) {
387
- parseEndTag("", tagName);
388
- }
389
-
390
- unary = voidElements[tagName] || !!unary;
391
-
392
- if (!unary)
393
- stack.push(tagName);
394
-
395
- var attrs = {};
396
-
397
- rest.replace(ATTR_REGEXP,
398
- function(match, name, doubleQuotedValue, singleQuotedValue, unquotedValue) {
399
- var value = doubleQuotedValue
400
- || singleQuotedValue
401
- || unquotedValue
402
- || '';
403
-
404
- attrs[name] = decodeEntities(value);
405
- });
406
- if (handler.start) handler.start(tagName, attrs, unary);
407
- }
408
-
409
- function parseEndTag(tag, tagName) {
410
- var pos = 0, i;
411
- tagName = angular.lowercase(tagName);
412
- if (tagName)
413
- // Find the closest opened tag of the same type
414
- for (pos = stack.length - 1; pos >= 0; pos--)
415
- if (stack[pos] == tagName)
416
- break;
417
-
418
- if (pos >= 0) {
419
- // Close all the open elements, up the stack
420
- for (i = stack.length - 1; i >= pos; i--)
421
- if (handler.end) handler.end(stack[i]);
422
-
423
- // Remove the open elements from the stack
424
- stack.length = pos;
425
- }
426
- }
427
- }
428
-
429
- var hiddenPre=document.createElement("pre");
430
- /**
431
- * decodes all entities into regular string
432
- * @param value
433
- * @returns {string} A string with decoded entities.
434
- */
435
- function decodeEntities(value) {
436
- if (!value) { return ''; }
437
-
438
- hiddenPre.innerHTML = value.replace(/</g,"&lt;");
439
- // innerText depends on styling as it doesn't display hidden elements.
440
- // Therefore, it's better to use textContent not to cause unnecessary reflows.
441
- return hiddenPre.textContent;
442
- }
443
-
444
- /**
445
- * Escapes all potentially dangerous characters, so that the
446
- * resulting string can be safely inserted into attribute or
447
- * element text.
448
- * @param value
449
- * @returns {string} escaped text
450
- */
451
- function encodeEntities(value) {
452
- return value.
453
- replace(/&/g, '&amp;').
454
- replace(SURROGATE_PAIR_REGEXP, function(value) {
455
- var hi = value.charCodeAt(0);
456
- var low = value.charCodeAt(1);
457
- return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';';
458
- }).
459
- replace(NON_ALPHANUMERIC_REGEXP, function(value) {
460
- return '&#' + value.charCodeAt(0) + ';';
461
- }).
462
- replace(/</g, '&lt;').
463
- replace(/>/g, '&gt;');
464
- }
465
-
466
- /**
467
- * create an HTML/XML writer which writes to buffer
468
- * @param {Array} buf use buf.jain('') to get out sanitized html string
469
- * @returns {object} in the form of {
470
- * start: function(tag, attrs, unary) {},
471
- * end: function(tag) {},
472
- * chars: function(text) {},
473
- * comment: function(text) {}
474
- * }
475
- */
476
- function htmlSanitizeWriter(buf, uriValidator) {
477
- var ignore = false;
478
- var out = angular.bind(buf, buf.push);
479
- return {
480
- start: function(tag, attrs, unary) {
481
- tag = angular.lowercase(tag);
482
- if (!ignore && specialElements[tag]) {
483
- ignore = tag;
484
- }
485
- if (!ignore && validElements[tag] === true) {
486
- out('<');
487
- out(tag);
488
- angular.forEach(attrs, function(value, key) {
489
- var lkey=angular.lowercase(key);
490
- var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background');
491
- if (validAttrs[lkey] === true &&
492
- (uriAttrs[lkey] !== true || uriValidator(value, isImage))) {
493
- out(' ');
494
- out(key);
495
- out('="');
496
- out(encodeEntities(value));
497
- out('"');
498
- }
499
- });
500
- out(unary ? '/>' : '>');
501
- }
502
- },
503
- end: function(tag) {
504
- tag = angular.lowercase(tag);
505
- if (!ignore && validElements[tag] === true) {
506
- out('</');
507
- out(tag);
508
- out('>');
509
- }
510
- if (tag == ignore) {
511
- ignore = false;
512
- }
513
- },
514
- chars: function(chars) {
515
- if (!ignore) {
516
- out(encodeEntities(chars));
517
- }
518
- }
519
- };
520
- }
521
-
522
-
523
- // define ngSanitize module and register $sanitize service
524
- angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
525
-
526
- /* global sanitizeText: false */
527
-
528
- /**
529
- * @ngdoc filter
530
- * @name linky
531
- * @kind function
532
- *
533
- * @description
534
- * Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and
535
- * plain email address links.
536
- *
537
- * Requires the {@link ngSanitize `ngSanitize`} module to be installed.
538
- *
539
- * @param {string} text Input text.
540
- * @param {string} target Window (_blank|_self|_parent|_top) or named frame to open links in.
541
- * @returns {string} Html-linkified text.
542
- *
543
- * @usage
544
- <span ng-bind-html="linky_expression | linky"></span>
545
- *
546
- * @example
547
- <example module="linkyExample" deps="angular-sanitize.js">
548
- <file name="index.html">
549
- <script>
550
- angular.module('linkyExample', ['ngSanitize'])
551
- .controller('ExampleController', ['$scope', function($scope) {
552
- $scope.snippet =
553
- 'Pretty text with some links:\n'+
554
- 'http://angularjs.org/,\n'+
555
- 'mailto:us@somewhere.org,\n'+
556
- 'another@somewhere.org,\n'+
557
- 'and one more: ftp://127.0.0.1/.';
558
- $scope.snippetWithTarget = 'http://angularjs.org/';
559
- }]);
560
- </script>
561
- <div ng-controller="ExampleController">
562
- Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
563
- <table>
564
- <tr>
565
- <td>Filter</td>
566
- <td>Source</td>
567
- <td>Rendered</td>
568
- </tr>
569
- <tr id="linky-filter">
570
- <td>linky filter</td>
571
- <td>
572
- <pre>&lt;div ng-bind-html="snippet | linky"&gt;<br>&lt;/div&gt;</pre>
573
- </td>
574
- <td>
575
- <div ng-bind-html="snippet | linky"></div>
576
- </td>
577
- </tr>
578
- <tr id="linky-target">
579
- <td>linky target</td>
580
- <td>
581
- <pre>&lt;div ng-bind-html="snippetWithTarget | linky:'_blank'"&gt;<br>&lt;/div&gt;</pre>
582
- </td>
583
- <td>
584
- <div ng-bind-html="snippetWithTarget | linky:'_blank'"></div>
585
- </td>
586
- </tr>
587
- <tr id="escaped-html">
588
- <td>no filter</td>
589
- <td><pre>&lt;div ng-bind="snippet"&gt;<br>&lt;/div&gt;</pre></td>
590
- <td><div ng-bind="snippet"></div></td>
591
- </tr>
592
- </table>
593
- </file>
594
- <file name="protractor.js" type="protractor">
595
- it('should linkify the snippet with urls', function() {
596
- expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
597
- toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' +
598
- 'another@somewhere.org, and one more: ftp://127.0.0.1/.');
599
- expect(element.all(by.css('#linky-filter a')).count()).toEqual(4);
600
- });
601
-
602
- it('should not linkify snippet without the linky filter', function() {
603
- expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()).
604
- toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' +
605
- 'another@somewhere.org, and one more: ftp://127.0.0.1/.');
606
- expect(element.all(by.css('#escaped-html a')).count()).toEqual(0);
607
- });
608
-
609
- it('should update', function() {
610
- element(by.model('snippet')).clear();
611
- element(by.model('snippet')).sendKeys('new http://link.');
612
- expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
613
- toBe('new http://link.');
614
- expect(element.all(by.css('#linky-filter a')).count()).toEqual(1);
615
- expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText())
616
- .toBe('new http://link.');
617
- });
618
-
619
- it('should work with the target property', function() {
620
- expect(element(by.id('linky-target')).
621
- element(by.binding("snippetWithTarget | linky:'_blank'")).getText()).
622
- toBe('http://angularjs.org/');
623
- expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank');
624
- });
625
- </file>
626
- </example>
627
- */
628
- angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
629
- var LINKY_URL_REGEXP =
630
- /((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"”’]/,
631
- MAILTO_REGEXP = /^mailto:/;
632
-
633
- return function(text, target) {
634
- if (!text) return text;
635
- var match;
636
- var raw = text;
637
- var html = [];
638
- var url;
639
- var i;
640
- while ((match = raw.match(LINKY_URL_REGEXP))) {
641
- // We can not end in these as they are sometimes found at the end of the sentence
642
- url = match[0];
643
- // if we did not match ftp/http/www/mailto then assume mailto
644
- if (!match[2] && !match[4]) {
645
- url = (match[3] ? 'http://' : 'mailto:') + url;
646
- }
647
- i = match.index;
648
- addText(raw.substr(0, i));
649
- addLink(url, match[0].replace(MAILTO_REGEXP, ''));
650
- raw = raw.substring(i + match[0].length);
651
- }
652
- addText(raw);
653
- return $sanitize(html.join(''));
654
-
655
- function addText(text) {
656
- if (!text) {
657
- return;
658
- }
659
- html.push(sanitizeText(text));
660
- }
661
-
662
- function addLink(url, text) {
663
- html.push('<a ');
664
- if (angular.isDefined(target)) {
665
- html.push('target="',
666
- target,
667
- '" ');
668
- }
669
- html.push('href="',
670
- url.replace(/"/g, '&quot;'),
671
- '">');
672
- addText(text);
673
- html.push('</a>');
674
- }
675
- };
676
- }]);
677
-
678
-
679
- })(window, window.angular);