angularjs-on-rails 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/app/assets/javascripts/angular-animate.js +77 -21
- data/app/assets/javascripts/angular-cookies.js +17 -15
- data/app/assets/javascripts/angular-loader.js +2 -2
- data/app/assets/javascripts/angular-mocks.js +11 -3
- data/app/assets/javascripts/angular-resource.js +12 -12
- data/app/assets/javascripts/angular-route.js +2 -4
- data/app/assets/javascripts/angular-sanitize.js +40 -30
- data/app/assets/javascripts/angular-scenario.js +909 -744
- data/app/assets/javascripts/angular-touch.js +1 -1
- data/app/assets/javascripts/angular.js +908 -743
- data/lib/angularjs-on-rails/version.rb +1 -1
- data/lib/generators/angular/install/templates/index.html +0 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3cb4699d08b726e41a28f3719681f041dc10c230
|
4
|
+
data.tar.gz: b901dda615033812c74498b9a6642cf81e1c38cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e79bb84bc0f3a9f3914b0b069d67e5427df4c04529927393c7d9324ef214c03d763ede1074d36aeaa941007901d7ad66e57da77cb54815d52f20ffa646ffed8
|
7
|
+
data.tar.gz: a436a7f3ff30dfc33592491d1822a1722569799eefc412ed79575f2275a2c73e8aa57d1250a6a03a9dd6ea1e86bac1f2ed162930bf7b74cd0539664e55b8d204
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
## AngularJS on Rails [![Gem Version](https://badge.fury.io/rb/angularjs-on-rails.svg)](http://badge.fury.io/rb/angularjs-on-rails)
|
2
2
|
|
3
|
-
wraps the [AngularJS 1.2.
|
3
|
+
wraps the [AngularJS 1.2.21](http://angularjs.org) library for use in [Rails 3.x](http://rubyonrails.org/) and above. This project is an application skeleton for a typical AngularJS web app. You can use it to quickly bootstrap your angular webapp projects.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.2.
|
2
|
+
* @license AngularJS v1.2.21
|
3
3
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -52,9 +52,9 @@
|
|
52
52
|
* }
|
53
53
|
*
|
54
54
|
* .slide.ng-enter { } /* starting animations for enter */
|
55
|
-
* .slide.ng-enter-active { } /* terminal animations for enter */
|
55
|
+
* .slide.ng-enter.ng-enter-active { } /* terminal animations for enter */
|
56
56
|
* .slide.ng-leave { } /* starting animations for leave */
|
57
|
-
* .slide.ng-leave-active { } /* terminal animations for leave */
|
57
|
+
* .slide.ng-leave.ng-leave-active { } /* terminal animations for leave */
|
58
58
|
* </style>
|
59
59
|
*
|
60
60
|
* <!--
|
@@ -64,8 +64,22 @@
|
|
64
64
|
* <ANY class="slide" ng-include="..."></ANY>
|
65
65
|
* ```
|
66
66
|
*
|
67
|
-
* Keep in mind that if an animation is running, any child elements cannot be animated
|
68
|
-
* animation has completed.
|
67
|
+
* Keep in mind that, by default, if an animation is running, any child elements cannot be animated
|
68
|
+
* until the parent element's animation has completed. This blocking feature can be overridden by
|
69
|
+
* placing the `ng-animate-children` attribute on a parent container tag.
|
70
|
+
*
|
71
|
+
* ```html
|
72
|
+
* <div class="slide-animation" ng-if="on" ng-animate-children>
|
73
|
+
* <div class="fade-animation" ng-if="on">
|
74
|
+
* <div class="explode-animation" ng-if="on">
|
75
|
+
* ...
|
76
|
+
* </div>
|
77
|
+
* </div>
|
78
|
+
* </div>
|
79
|
+
* ```
|
80
|
+
*
|
81
|
+
* When the `on` expression value changes and an animation is triggered then each of the elements within
|
82
|
+
* will all animate without the block being applied to child elements.
|
69
83
|
*
|
70
84
|
* <h2>CSS-defined Animations</h2>
|
71
85
|
* The animate service will automatically apply two CSS classes to the animated element and these two CSS classes
|
@@ -255,6 +269,19 @@ angular.module('ngAnimate', ['ng'])
|
|
255
269
|
* Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application.
|
256
270
|
*
|
257
271
|
*/
|
272
|
+
.directive('ngAnimateChildren', function() {
|
273
|
+
var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren';
|
274
|
+
return function(scope, element, attrs) {
|
275
|
+
var val = attrs.ngAnimateChildren;
|
276
|
+
if(angular.isString(val) && val.length === 0) { //empty attribute
|
277
|
+
element.data(NG_ANIMATE_CHILDREN, true);
|
278
|
+
} else {
|
279
|
+
scope.$watch(val, function(value) {
|
280
|
+
element.data(NG_ANIMATE_CHILDREN, !!value);
|
281
|
+
});
|
282
|
+
}
|
283
|
+
};
|
284
|
+
})
|
258
285
|
|
259
286
|
//this private service is only used within CSS-enabled animations
|
260
287
|
//IE8 + IE9 do not support rAF natively, but that is fine since they
|
@@ -283,6 +310,7 @@ angular.module('ngAnimate', ['ng'])
|
|
283
310
|
|
284
311
|
var ELEMENT_NODE = 1;
|
285
312
|
var NG_ANIMATE_STATE = '$$ngAnimateState';
|
313
|
+
var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren';
|
286
314
|
var NG_ANIMATE_CLASS_NAME = 'ng-animate';
|
287
315
|
var rootAnimateState = {running: true};
|
288
316
|
|
@@ -332,6 +360,12 @@ angular.module('ngAnimate', ['ng'])
|
|
332
360
|
return classNameFilter.test(className);
|
333
361
|
};
|
334
362
|
|
363
|
+
function blockElementAnimations(element) {
|
364
|
+
var data = element.data(NG_ANIMATE_STATE) || {};
|
365
|
+
data.running = true;
|
366
|
+
element.data(NG_ANIMATE_STATE, data);
|
367
|
+
}
|
368
|
+
|
335
369
|
function lookup(name) {
|
336
370
|
if (name) {
|
337
371
|
var matches = [],
|
@@ -558,7 +592,7 @@ angular.module('ngAnimate', ['ng'])
|
|
558
592
|
parentElement = prepareElement(parentElement);
|
559
593
|
afterElement = prepareElement(afterElement);
|
560
594
|
|
561
|
-
|
595
|
+
blockElementAnimations(element);
|
562
596
|
$delegate.enter(element, parentElement, afterElement);
|
563
597
|
$rootScope.$$postDigest(function() {
|
564
598
|
element = stripCommentsFromElement(element);
|
@@ -596,7 +630,7 @@ angular.module('ngAnimate', ['ng'])
|
|
596
630
|
leave : function(element, doneCallback) {
|
597
631
|
element = angular.element(element);
|
598
632
|
cancelChildAnimations(element);
|
599
|
-
|
633
|
+
blockElementAnimations(element);
|
600
634
|
$rootScope.$$postDigest(function() {
|
601
635
|
performAnimation('leave', 'ng-leave', stripCommentsFromElement(element), null, null, function() {
|
602
636
|
$delegate.leave(element);
|
@@ -640,7 +674,7 @@ angular.module('ngAnimate', ['ng'])
|
|
640
674
|
afterElement = prepareElement(afterElement);
|
641
675
|
|
642
676
|
cancelChildAnimations(element);
|
643
|
-
|
677
|
+
blockElementAnimations(element);
|
644
678
|
$delegate.move(element, parentElement, afterElement);
|
645
679
|
$rootScope.$$postDigest(function() {
|
646
680
|
element = stripCommentsFromElement(element);
|
@@ -814,9 +848,12 @@ angular.module('ngAnimate', ['ng'])
|
|
814
848
|
|
815
849
|
//only allow animations if the currently running animation is not structural
|
816
850
|
//or if there is no animation running at all
|
817
|
-
var skipAnimations
|
818
|
-
|
819
|
-
|
851
|
+
var skipAnimations;
|
852
|
+
if (runner.isClassBased) {
|
853
|
+
skipAnimations = ngAnimateState.running ||
|
854
|
+
ngAnimateState.disabled ||
|
855
|
+
(lastAnimation && !lastAnimation.isClassBased);
|
856
|
+
}
|
820
857
|
|
821
858
|
//skip the animation if animations are disabled, a parent is already being animated,
|
822
859
|
//the element is not currently attached to the document body or then completely close
|
@@ -1033,30 +1070,49 @@ angular.module('ngAnimate', ['ng'])
|
|
1033
1070
|
}
|
1034
1071
|
|
1035
1072
|
function animationsDisabled(element, parentElement) {
|
1036
|
-
if (rootAnimateState.disabled)
|
1073
|
+
if (rootAnimateState.disabled) {
|
1074
|
+
return true;
|
1075
|
+
}
|
1037
1076
|
|
1038
|
-
if(isMatchingElement(element, $rootElement)) {
|
1039
|
-
return rootAnimateState.
|
1077
|
+
if (isMatchingElement(element, $rootElement)) {
|
1078
|
+
return rootAnimateState.running;
|
1040
1079
|
}
|
1041
1080
|
|
1081
|
+
var allowChildAnimations, parentRunningAnimation, hasParent;
|
1042
1082
|
do {
|
1043
1083
|
//the element did not reach the root element which means that it
|
1044
1084
|
//is not apart of the DOM. Therefore there is no reason to do
|
1045
1085
|
//any animations on it
|
1046
|
-
if(parentElement.length === 0) break;
|
1086
|
+
if (parentElement.length === 0) break;
|
1047
1087
|
|
1048
1088
|
var isRoot = isMatchingElement(parentElement, $rootElement);
|
1049
|
-
var state = isRoot ? rootAnimateState : parentElement.data(NG_ANIMATE_STATE);
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1089
|
+
var state = isRoot ? rootAnimateState : (parentElement.data(NG_ANIMATE_STATE) || {});
|
1090
|
+
if (state.disabled) {
|
1091
|
+
return true;
|
1092
|
+
}
|
1093
|
+
|
1094
|
+
//no matter what, for an animation to work it must reach the root element
|
1095
|
+
//this implies that the element is attached to the DOM when the animation is run
|
1096
|
+
if (isRoot) {
|
1097
|
+
hasParent = true;
|
1053
1098
|
}
|
1054
1099
|
|
1055
|
-
|
1100
|
+
//once a flag is found that is strictly false then everything before
|
1101
|
+
//it will be discarded and all child animations will be restricted
|
1102
|
+
if (allowChildAnimations !== false) {
|
1103
|
+
var animateChildrenFlag = parentElement.data(NG_ANIMATE_CHILDREN);
|
1104
|
+
if(angular.isDefined(animateChildrenFlag)) {
|
1105
|
+
allowChildAnimations = animateChildrenFlag;
|
1106
|
+
}
|
1107
|
+
}
|
1108
|
+
|
1109
|
+
parentRunningAnimation = parentRunningAnimation ||
|
1110
|
+
state.running ||
|
1111
|
+
(state.last && !state.last.isClassBased);
|
1056
1112
|
}
|
1057
1113
|
while(parentElement = parentElement.parent());
|
1058
1114
|
|
1059
|
-
return
|
1115
|
+
return !hasParent || (!allowChildAnimations && parentRunningAnimation);
|
1060
1116
|
}
|
1061
1117
|
}]);
|
1062
1118
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.2.
|
2
|
+
* @license AngularJS v1.2.21
|
3
3
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -39,12 +39,13 @@ angular.module('ngCookies', ['ng']).
|
|
39
39
|
* @example
|
40
40
|
*
|
41
41
|
* ```js
|
42
|
-
*
|
43
|
-
*
|
44
|
-
*
|
45
|
-
*
|
46
|
-
*
|
47
|
-
*
|
42
|
+
* angular.module('cookiesExample', ['ngCookies'])
|
43
|
+
* .controller('ExampleController', ['$cookies', function($cookies) {
|
44
|
+
* // Retrieving a cookie
|
45
|
+
* var favoriteCookie = $cookies.myFavorite;
|
46
|
+
* // Setting a cookie
|
47
|
+
* $cookies.myFavorite = 'oatmeal';
|
48
|
+
* }]);
|
48
49
|
* ```
|
49
50
|
*/
|
50
51
|
factory('$cookies', ['$rootScope', '$browser', function ($rootScope, $browser) {
|
@@ -142,14 +143,15 @@ angular.module('ngCookies', ['ng']).
|
|
142
143
|
* @example
|
143
144
|
*
|
144
145
|
* ```js
|
145
|
-
*
|
146
|
-
*
|
147
|
-
*
|
148
|
-
*
|
149
|
-
*
|
150
|
-
*
|
151
|
-
*
|
152
|
-
*
|
146
|
+
* angular.module('cookieStoreExample', ['ngCookies'])
|
147
|
+
* .controller('ExampleController', ['$cookieStore', function($cookieStore) {
|
148
|
+
* // Put cookie
|
149
|
+
* $cookieStore.put('myFavorite','oatmeal');
|
150
|
+
* // Get cookie
|
151
|
+
* var favoriteCookie = $cookieStore.get('myFavorite');
|
152
|
+
* // Removing a cookie
|
153
|
+
* $cookieStore.remove('myFavorite');
|
154
|
+
* }]);
|
153
155
|
* ```
|
154
156
|
*/
|
155
157
|
factory('$cookieStore', ['$cookies', function($cookies) {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.2.
|
2
|
+
* @license AngularJS v1.2.21
|
3
3
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -69,7 +69,7 @@ function minErr(module) {
|
|
69
69
|
return match;
|
70
70
|
});
|
71
71
|
|
72
|
-
message = message + '\nhttp://errors.angularjs.org/1.2.
|
72
|
+
message = message + '\nhttp://errors.angularjs.org/1.2.21/' +
|
73
73
|
(module ? module + '/' : '') + code;
|
74
74
|
for (i = 2; i < arguments.length; i++) {
|
75
75
|
message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.2.
|
2
|
+
* @license AngularJS v1.2.21
|
3
3
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -462,7 +462,7 @@ angular.mock.$IntervalProvider = function() {
|
|
462
462
|
iteration = 0,
|
463
463
|
skipApply = (angular.isDefined(invokeApply) && !invokeApply);
|
464
464
|
|
465
|
-
count = (angular.isDefined(count)) ? count : 0
|
465
|
+
count = (angular.isDefined(count)) ? count : 0;
|
466
466
|
promise.then(null, null, fn);
|
467
467
|
|
468
468
|
promise.$$intervalId = nextRepeatId;
|
@@ -1722,11 +1722,12 @@ angular.mock.$RootElementProvider = function() {
|
|
1722
1722
|
/**
|
1723
1723
|
* @ngdoc module
|
1724
1724
|
* @name ngMock
|
1725
|
+
* @packageName angular-mocks
|
1725
1726
|
* @description
|
1726
1727
|
*
|
1727
1728
|
* # ngMock
|
1728
1729
|
*
|
1729
|
-
* The `ngMock` module
|
1730
|
+
* The `ngMock` module provides support to inject and mock Angular services into unit tests.
|
1730
1731
|
* In addition, ngMock also extends various core ng services such that they can be
|
1731
1732
|
* inspected and controlled in a synchronous manner within test code.
|
1732
1733
|
*
|
@@ -1751,6 +1752,7 @@ angular.module('ngMock', ['ng']).provider({
|
|
1751
1752
|
* @ngdoc module
|
1752
1753
|
* @name ngMockE2E
|
1753
1754
|
* @module ngMockE2E
|
1755
|
+
* @packageName angular-mocks
|
1754
1756
|
* @description
|
1755
1757
|
*
|
1756
1758
|
* The `ngMockE2E` is an angular module which contains mocks suitable for end-to-end testing.
|
@@ -1965,6 +1967,12 @@ if(window.jasmine || window.mocha) {
|
|
1965
1967
|
(window.afterEach || window.teardown)(function() {
|
1966
1968
|
var injector = currentSpec.$injector;
|
1967
1969
|
|
1970
|
+
angular.forEach(currentSpec.$modules, function(module) {
|
1971
|
+
if (module && module.$$hashKey) {
|
1972
|
+
module.$$hashKey = undefined;
|
1973
|
+
}
|
1974
|
+
});
|
1975
|
+
|
1968
1976
|
currentSpec.$injector = null;
|
1969
1977
|
currentSpec.$modules = null;
|
1970
1978
|
currentSpec = null;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.2.
|
2
|
+
* @license AngularJS v1.2.21
|
3
3
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -114,8 +114,8 @@ function shallowClearAndCopy(src, dst) {
|
|
114
114
|
*
|
115
115
|
* - **`action`** – {string} – The name of action. This name becomes the name of the method on
|
116
116
|
* your resource object.
|
117
|
-
* - **`method`** – {string} – HTTP
|
118
|
-
* `DELETE`,
|
117
|
+
* - **`method`** – {string} – Case insensitive HTTP method (e.g. `GET`, `POST`, `PUT`,
|
118
|
+
* `DELETE`, `JSONP`, etc).
|
119
119
|
* - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of
|
120
120
|
* the parameter value is a function, it will be executed every time when a param value needs to
|
121
121
|
* be obtained for a request (unless the param was overridden).
|
@@ -295,20 +295,20 @@ function shallowClearAndCopy(src, dst) {
|
|
295
295
|
* # Creating a custom 'PUT' request
|
296
296
|
* In this example we create a custom method on our resource to make a PUT request
|
297
297
|
* ```js
|
298
|
-
*
|
298
|
+
* var app = angular.module('app', ['ngResource', 'ngRoute']);
|
299
299
|
*
|
300
|
-
*
|
301
|
-
*
|
302
|
-
*
|
300
|
+
* // Some APIs expect a PUT request in the format URL/object/ID
|
301
|
+
* // Here we are creating an 'update' method
|
302
|
+
* app.factory('Notes', ['$resource', function($resource) {
|
303
303
|
* return $resource('/notes/:id', null,
|
304
304
|
* {
|
305
305
|
* 'update': { method:'PUT' }
|
306
306
|
* });
|
307
|
-
*
|
307
|
+
* }]);
|
308
308
|
*
|
309
|
-
*
|
310
|
-
*
|
311
|
-
*
|
309
|
+
* // In our controller we get the ID from the URL using ngRoute and $routeParams
|
310
|
+
* // We pass in $routeParams and our Notes factory along with $scope
|
311
|
+
* app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
|
312
312
|
function($scope, $routeParams, Notes) {
|
313
313
|
* // First get a note object from the factory
|
314
314
|
* var note = Notes.get({ id:$routeParams.id });
|
@@ -318,7 +318,7 @@ function shallowClearAndCopy(src, dst) {
|
|
318
318
|
* Notes.update({ id:$id }, note);
|
319
319
|
*
|
320
320
|
* // This will PUT /notes/ID with the note object in the request payload
|
321
|
-
*
|
321
|
+
* }]);
|
322
322
|
* ```
|
323
323
|
*/
|
324
324
|
angular.module('ngResource', ['ng']).
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.2.
|
2
|
+
* @license AngularJS v1.2.21
|
3
3
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -473,9 +473,7 @@ function $RouteProvider(){
|
|
473
473
|
for (var i = 1, len = m.length; i < len; ++i) {
|
474
474
|
var key = keys[i - 1];
|
475
475
|
|
476
|
-
var val =
|
477
|
-
? decodeURIComponent(m[i])
|
478
|
-
: m[i];
|
476
|
+
var val = m[i];
|
479
477
|
|
480
478
|
if (key && val) {
|
481
479
|
params[key.name] = val;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.2.
|
2
|
+
* @license AngularJS v1.2.21
|
3
3
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -57,20 +57,21 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize');
|
|
57
57
|
* @returns {string} Sanitized html.
|
58
58
|
*
|
59
59
|
* @example
|
60
|
-
<example module="
|
60
|
+
<example module="sanitizeExample" deps="angular-sanitize.js">
|
61
61
|
<file name="index.html">
|
62
62
|
<script>
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
63
|
+
angular.module('sanitizeExample', ['ngSanitize'])
|
64
|
+
.controller('ExampleController', ['$scope', '$sce', function($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
|
+
}]);
|
72
73
|
</script>
|
73
|
-
<div ng-controller="
|
74
|
+
<div ng-controller="ExampleController">
|
74
75
|
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
|
75
76
|
<table>
|
76
77
|
<tr>
|
@@ -158,11 +159,11 @@ function sanitizeText(chars) {
|
|
158
159
|
|
159
160
|
// Regular Expressions for parsing tags and attributes
|
160
161
|
var START_TAG_REGEXP =
|
161
|
-
|
162
|
-
END_TAG_REGEXP =
|
162
|
+
/^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/,
|
163
|
+
END_TAG_REGEXP = /^<\/\s*([\w:-]+)[^>]*>/,
|
163
164
|
ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,
|
164
165
|
BEGIN_TAG_REGEXP = /^</,
|
165
|
-
BEGING_END_TAGE_REGEXP =
|
166
|
+
BEGING_END_TAGE_REGEXP = /^<\//,
|
166
167
|
COMMENT_REGEXP = /<!--(.*?)-->/g,
|
167
168
|
DOCTYPE_REGEXP = /<!DOCTYPE([^>]*?)>/i,
|
168
169
|
CDATA_REGEXP = /<!\[CDATA\[(.*?)]]>/g,
|
@@ -236,10 +237,11 @@ function makeMap(str) {
|
|
236
237
|
* @param {object} handler
|
237
238
|
*/
|
238
239
|
function htmlParser( html, handler ) {
|
239
|
-
var index, chars, match, stack = [], last = html;
|
240
|
+
var index, chars, match, stack = [], last = html, text;
|
240
241
|
stack.last = function() { return stack[ stack.length - 1 ]; };
|
241
242
|
|
242
243
|
while ( html ) {
|
244
|
+
text = '';
|
243
245
|
chars = true;
|
244
246
|
|
245
247
|
// Make sure we're not in a script or style element
|
@@ -278,16 +280,23 @@ function htmlParser( html, handler ) {
|
|
278
280
|
match = html.match( START_TAG_REGEXP );
|
279
281
|
|
280
282
|
if ( match ) {
|
281
|
-
|
282
|
-
match[
|
283
|
+
// We only have a valid start-tag if there is a '>'.
|
284
|
+
if ( match[4] ) {
|
285
|
+
html = html.substring( match[0].length );
|
286
|
+
match[0].replace( START_TAG_REGEXP, parseStartTag );
|
287
|
+
}
|
283
288
|
chars = false;
|
289
|
+
} else {
|
290
|
+
// no ending tag found --- this piece should be encoded as an entity.
|
291
|
+
text += '<';
|
292
|
+
html = html.substring(1);
|
284
293
|
}
|
285
294
|
}
|
286
295
|
|
287
296
|
if ( chars ) {
|
288
297
|
index = html.indexOf("<");
|
289
298
|
|
290
|
-
|
299
|
+
text += index < 0 ? html : html.substring( 0, index );
|
291
300
|
html = index < 0 ? "" : html.substring( index );
|
292
301
|
|
293
302
|
if (handler.chars) handler.chars( decodeEntities(text) );
|
@@ -498,20 +507,21 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
|
498
507
|
<span ng-bind-html="linky_expression | linky"></span>
|
499
508
|
*
|
500
509
|
* @example
|
501
|
-
<example module="
|
510
|
+
<example module="linkyExample" deps="angular-sanitize.js">
|
502
511
|
<file name="index.html">
|
503
512
|
<script>
|
504
|
-
|
505
|
-
$scope
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
+
angular.module('linkyExample', ['ngSanitize'])
|
514
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
515
|
+
$scope.snippet =
|
516
|
+
'Pretty text with some links:\n'+
|
517
|
+
'http://angularjs.org/,\n'+
|
518
|
+
'mailto:us@somewhere.org,\n'+
|
519
|
+
'another@somewhere.org,\n'+
|
520
|
+
'and one more: ftp://127.0.0.1/.';
|
521
|
+
$scope.snippetWithTarget = 'http://angularjs.org/';
|
522
|
+
}]);
|
513
523
|
</script>
|
514
|
-
<div ng-controller="
|
524
|
+
<div ng-controller="ExampleController">
|
515
525
|
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
|
516
526
|
<table>
|
517
527
|
<tr>
|