Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

add 1.1.5 triangle-squarification

  • Loading branch information...
commit ff0f20d43238c64ebceed7291b6174db4372b120 1 parent 8e438ea
@IgorMinar IgorMinar authored
Showing with 77,829 additions and 0 deletions.
  1. BIN  1.1.5/angular-1.1.5.zip
  2. +185 −0 1.1.5/angular-cookies.js
  3. +7 −0 1.1.5/angular-cookies.min.js
  4. +304 −0 1.1.5/angular-loader.js
  5. +7 −0 1.1.5/angular-loader.min.js
  6. +460 −0 1.1.5/angular-mobile.js
  7. +11 −0 1.1.5/angular-mobile.min.js
  8. +1,886 −0 1.1.5/angular-mocks.js
  9. +537 −0 1.1.5/angular-resource.js
  10. +11 −0 1.1.5/angular-resource.min.js
  11. +558 −0 1.1.5/angular-sanitize.js
  12. +13 −0 1.1.5/angular-sanitize.min.js
  13. +28,463 −0 1.1.5/angular-scenario.js
  14. +16,876 −0 1.1.5/angular.js
  15. +178 −0 1.1.5/angular.min.js
  16. +19 −0 1.1.5/docs/.htaccess
  17. +298 −0 1.1.5/docs/appcache-offline.manifest
  18. +20 −0 1.1.5/docs/appcache.manifest
  19. +1,838 −0 1.1.5/docs/components/angular-bootstrap-prettify.js
  20. +41 −0 1.1.5/docs/components/angular-bootstrap-prettify.min.js
  21. +221 −0 1.1.5/docs/components/angular-bootstrap.js
  22. +11 −0 1.1.5/docs/components/angular-bootstrap.min.js
  23. +81 −0 1.1.5/docs/css/animations.css
  24. +689 −0 1.1.5/docs/css/bootstrap.min.css
  25. +150 −0 1.1.5/docs/css/doc_widgets.css
  26. +310 −0 1.1.5/docs/css/docs.css
  27. +540 −0 1.1.5/docs/css/font-awesome.css
  28. +224 −0 1.1.5/docs/docs-keywords.js
  29. +44 −0 1.1.5/docs/docs-scenario.html
  30. +4,850 −0 1.1.5/docs/docs-scenario.js
  31. BIN  1.1.5/docs/favicon.ico
  32. BIN  1.1.5/docs/font/FontAwesome.otf
  33. BIN  1.1.5/docs/font/fontawesome-webfont.eot
  34. +284 −0 1.1.5/docs/font/fontawesome-webfont.svg
  35. BIN  1.1.5/docs/font/fontawesome-webfont.svgz
  36. BIN  1.1.5/docs/font/fontawesome-webfont.ttf
  37. BIN  1.1.5/docs/font/fontawesome-webfont.woff
  38. BIN  1.1.5/docs/img/AngularJS-small.png
  39. BIN  1.1.5/docs/img/One_Way_Data_Binding.png
  40. BIN  1.1.5/docs/img/Two_Way_Data_Binding.png
  41. BIN  1.1.5/docs/img/angular_parts.png
  42. BIN  1.1.5/docs/img/bullet.png
  43. BIN  1.1.5/docs/img/form_data_flow.png
  44. BIN  1.1.5/docs/img/glyphicons-halflings-white.png
  45. BIN  1.1.5/docs/img/glyphicons-halflings.png
  46. BIN  1.1.5/docs/img/guide/about_model_final.png
  47. BIN  1.1.5/docs/img/guide/about_view_final.png
  48. BIN  1.1.5/docs/img/guide/concepts-controller.png
  49. BIN  1.1.5/docs/img/guide/concepts-directive.png
  50. BIN  1.1.5/docs/img/guide/concepts-model.png
  51. BIN  1.1.5/docs/img/guide/concepts-module-injector.png
  52. BIN  1.1.5/docs/img/guide/concepts-runtime.png
  53. BIN  1.1.5/docs/img/guide/concepts-scope.png
  54. BIN  1.1.5/docs/img/guide/concepts-startup.png
  55. BIN  1.1.5/docs/img/guide/concepts-view.png
  56. BIN  1.1.5/docs/img/guide/di_sequence_final.png
  57. BIN  1.1.5/docs/img/guide/dom_scope_final.png
  58. BIN  1.1.5/docs/img/guide/hashbang_vs_regular_url.jpg
  59. BIN  1.1.5/docs/img/guide/scenario_runner.png
  60. BIN  1.1.5/docs/img/guide/simple_scope_final.png
  61. BIN  1.1.5/docs/img/helloworld.png
  62. BIN  1.1.5/docs/img/helloworld_2way.png
  63. BIN  1.1.5/docs/img/tutorial/catalog_screen.png
  64. BIN  1.1.5/docs/img/tutorial/tutorial_00.png
  65. BIN  1.1.5/docs/img/tutorial/tutorial_00_final.png
  66. BIN  1.1.5/docs/img/tutorial/tutorial_02.png
  67. BIN  1.1.5/docs/img/tutorial/tutorial_03.png
  68. BIN  1.1.5/docs/img/tutorial/tutorial_04.png
  69. BIN  1.1.5/docs/img/tutorial/tutorial_07_final.png
  70. BIN  1.1.5/docs/img/tutorial/tutorial_08-09_final.png
  71. BIN  1.1.5/docs/img/tutorial/tutorial_10-11_final.png
  72. BIN  1.1.5/docs/img/tutorial/xhr_service_final.png
  73. +353 −0 1.1.5/docs/index-debug.html
  74. +353 −0 1.1.5/docs/index-jq-debug.html
  75. +353 −0 1.1.5/docs/index-jq-nocache.html
  76. +353 −0 1.1.5/docs/index-jq.html
  77. +353 −0 1.1.5/docs/index-nocache.html
  78. +353 −0 1.1.5/docs/index.html
  79. +688 −0 1.1.5/docs/js/docs.js
  80. +9,440 −0 1.1.5/docs/js/jquery.js
  81. +2 −0  1.1.5/docs/js/jquery.min.js
  82. +1,560 −0 1.1.5/docs/js/lunr.js
  83. +4 −0 1.1.5/docs/offline.html
  84. +138 −0 1.1.5/docs/partials/api/AUTO.$injector.html
  85. +85 −0 1.1.5/docs/partials/api/AUTO.$provide.html
  86. +4 −0 1.1.5/docs/partials/api/AUTO.html
  87. +72 −0 1.1.5/docs/partials/api/angular.IModule.html
  88. +12 −0 1.1.5/docs/partials/api/angular.bind.html
  89. +12 −0 1.1.5/docs/partials/api/angular.bootstrap.html
  90. +22 −0 1.1.5/docs/partials/api/angular.copy.html
  91. +73 −0 1.1.5/docs/partials/api/angular.element.html
  92. +24 −0 1.1.5/docs/partials/api/angular.equals.html
  93. +11 −0 1.1.5/docs/partials/api/angular.extend.html
  94. +24 −0 1.1.5/docs/partials/api/angular.forEach.html
  95. +10 −0 1.1.5/docs/partials/api/angular.fromJson.html
  96. +17 −0 1.1.5/docs/partials/api/angular.identity.html
  97. +25 −0 1.1.5/docs/partials/api/angular.injector.html
  98. +10 −0 1.1.5/docs/partials/api/angular.isArray.html
  99. +10 −0 1.1.5/docs/partials/api/angular.isDate.html
  100. +10 −0 1.1.5/docs/partials/api/angular.isDefined.html
  101. +10 −0 1.1.5/docs/partials/api/angular.isElement.html
  102. +10 −0 1.1.5/docs/partials/api/angular.isFunction.html
  103. +10 −0 1.1.5/docs/partials/api/angular.isNumber.html
  104. +11 −0 1.1.5/docs/partials/api/angular.isObject.html
  105. +10 −0 1.1.5/docs/partials/api/angular.isString.html
  106. +10 −0 1.1.5/docs/partials/api/angular.isUndefined.html
  107. +10 −0 1.1.5/docs/partials/api/angular.lowercase.html
  108. +35 −0 1.1.5/docs/partials/api/angular.mock.TzDate.html
  109. +25 −0 1.1.5/docs/partials/api/angular.mock.createMockWindow.html
  110. +16 −0 1.1.5/docs/partials/api/angular.mock.dump.html
  111. +5 −0 1.1.5/docs/partials/api/angular.mock.html
  112. +53 −0 1.1.5/docs/partials/api/angular.mock.inject.html
  113. +17 −0 1.1.5/docs/partials/api/angular.mock.module.html
  114. +43 −0 1.1.5/docs/partials/api/angular.module.html
  115. +12 −0 1.1.5/docs/partials/api/angular.noConflict.html
  116. +17 −0 1.1.5/docs/partials/api/angular.noop.html
  117. +10 −0 1.1.5/docs/partials/api/angular.toJson.html
  118. +10 −0 1.1.5/docs/partials/api/angular.uppercase.html
  119. +19 −0 1.1.5/docs/partials/api/angular.version.html
  120. +6 −0 1.1.5/docs/partials/api/index.html
  121. +23 −0 1.1.5/docs/partials/api/ng.$anchorScroll.html
  122. +13 −0 1.1.5/docs/partials/api/ng.$animation.html
  123. +23 −0 1.1.5/docs/partials/api/ng.$animationProvider.html
  124. +36 −0 1.1.5/docs/partials/api/ng.$animator.html
  125. +23 −0 1.1.5/docs/partials/api/ng.$cacheFactory.html
  126. +27 −0 1.1.5/docs/partials/api/ng.$compile.directive.Attributes.html
  127. +128 −0 1.1.5/docs/partials/api/ng.$compile.html
  128. +27 −0 1.1.5/docs/partials/api/ng.$compileProvider.html
  129. +25 −0 1.1.5/docs/partials/api/ng.$controller.html
  130. +18 −0 1.1.5/docs/partials/api/ng.$controllerProvider.html
  131. +12 −0 1.1.5/docs/partials/api/ng.$document.html
  132. +20 −0 1.1.5/docs/partials/api/ng.$exceptionHandler.html
  133. +15 −0 1.1.5/docs/partials/api/ng.$filter.html
  134. +53 −0 1.1.5/docs/partials/api/ng.$filterProvider.html
  135. +489 −0 1.1.5/docs/partials/api/ng.$http.html
  136. +21 −0 1.1.5/docs/partials/api/ng.$httpBackend.html
  137. +47 −0 1.1.5/docs/partials/api/ng.$interpolate.html
  138. +16 −0 1.1.5/docs/partials/api/ng.$interpolateProvider.html
  139. +12 −0 1.1.5/docs/partials/api/ng.$locale.html
  140. +93 −0 1.1.5/docs/partials/api/ng.$location.html
  141. +16 −0 1.1.5/docs/partials/api/ng.$locationProvider.html
  142. +60 −0 1.1.5/docs/partials/api/ng.$log.html
  143. +13 −0 1.1.5/docs/partials/api/ng.$logProvider.html
  144. +38 −0 1.1.5/docs/partials/api/ng.$parse.html
  145. +206 −0 1.1.5/docs/partials/api/ng.$q.html
  146. +8 −0 1.1.5/docs/partials/api/ng.$rootElement.html
  147. +374 −0 1.1.5/docs/partials/api/ng.$rootScope.Scope.html
  148. +9 −0 1.1.5/docs/partials/api/ng.$rootScope.html
  149. +16 −0 1.1.5/docs/partials/api/ng.$rootScopeProvider.html
  150. +203 −0 1.1.5/docs/partials/api/ng.$route.html
  151. +27 −0 1.1.5/docs/partials/api/ng.$routeParams.html
  152. +94 −0 1.1.5/docs/partials/api/ng.$routeProvider.html
  153. +9 −0 1.1.5/docs/partials/api/ng.$templateCache.html
  154. +34 −0 1.1.5/docs/partials/api/ng.$timeout.html
  155. +47 −0 1.1.5/docs/partials/api/ng.$window.html
  156. +16 −0 1.1.5/docs/partials/api/ng.directive:a.html
  157. +48 −0 1.1.5/docs/partials/api/ng.directive:form.FormController.html
  158. +108 −0 1.1.5/docs/partials/api/ng.directive:form.html
  159. +57 −0 1.1.5/docs/partials/api/ng.directive:input.checkbox.html
  160. +76 −0 1.1.5/docs/partials/api/ng.directive:input.email.html
  161. +108 −0 1.1.5/docs/partials/api/ng.directive:input.html
  162. +81 −0 1.1.5/docs/partials/api/ng.directive:input.number.html
  163. +51 −0 1.1.5/docs/partials/api/ng.directive:input.radio.html
  164. +87 −0 1.1.5/docs/partials/api/ng.directive:input.text.html
  165. +78 −0 1.1.5/docs/partials/api/ng.directive:input.url.html
  166. +197 −0 1.1.5/docs/partials/api/ng.directive:ngAnimate.html
  167. +36 −0 1.1.5/docs/partials/api/ng.directive:ngApp.html
  168. +62 −0 1.1.5/docs/partials/api/ng.directive:ngBind.html
  169. +20 −0 1.1.5/docs/partials/api/ng.directive:ngBindHtmlUnsafe.html
  170. +63 −0 1.1.5/docs/partials/api/ng.directive:ngBindTemplate.html
  171. +60 −0 1.1.5/docs/partials/api/ng.directive:ngChange.html
  172. +37 −0 1.1.5/docs/partials/api/ng.directive:ngChecked.html
  173. +64 −0 1.1.5/docs/partials/api/ng.directive:ngClass.html
  174. +60 −0 1.1.5/docs/partials/api/ng.directive:ngClassEven.html
  175. +60 −0 1.1.5/docs/partials/api/ng.directive:ngClassOdd.html
  176. +41 −0 1.1.5/docs/partials/api/ng.directive:ngClick.html
  177. +65 −0 1.1.5/docs/partials/api/ng.directive:ngCloak.html
  178. +194 −0 1.1.5/docs/partials/api/ng.directive:ngController.html
  179. +41 −0 1.1.5/docs/partials/api/ng.directive:ngCsp.html
  180. +18 −0 1.1.5/docs/partials/api/ng.directive:ngDblclick.html
Sorry, we could not display the entire diff because too many files (596) changed.
View
BIN  1.1.5/angular-1.1.5.zip
Binary file not shown
View
185 1.1.5/angular-cookies.js
@@ -0,0 +1,185 @@
+/**
+ * @license AngularJS v1.1.5
+ * (c) 2010-2012 Google, Inc. http://angularjs.org
+ * License: MIT
+ */
+(function(window, angular, undefined) {
+'use strict';
+
+/**
+ * @ngdoc overview
+ * @name ngCookies
+ */
+
+
+angular.module('ngCookies', ['ng']).
+ /**
+ * @ngdoc object
+ * @name ngCookies.$cookies
+ * @requires $browser
+ *
+ * @description
+ * Provides read/write access to browser's cookies.
+ *
+ * Only a simple Object is exposed and by adding or removing properties to/from
+ * this object, new cookies are created/deleted at the end of current $eval.
+ *
+ * @example
+ <doc:example>
+ <doc:source>
+ <script>
+ function ExampleController($cookies) {
+ // Retrieving a cookie
+ var favoriteCookie = $cookies.myFavorite;
+ // Setting a cookie
+ $cookies.myFavorite = 'oatmeal';
+ }
+ </script>
+ </doc:source>
+ </doc:example>
+ */
+ factory('$cookies', ['$rootScope', '$browser', function ($rootScope, $browser) {
+ var cookies = {},
+ lastCookies = {},
+ lastBrowserCookies,
+ runEval = false,
+ copy = angular.copy,
+ isUndefined = angular.isUndefined;
+
+ //creates a poller fn that copies all cookies from the $browser to service & inits the service
+ $browser.addPollFn(function() {
+ var currentCookies = $browser.cookies();
+ if (lastBrowserCookies != currentCookies) { //relies on browser.cookies() impl
+ lastBrowserCookies = currentCookies;
+ copy(currentCookies, lastCookies);
+ copy(currentCookies, cookies);
+ if (runEval) $rootScope.$apply();
+ }
+ })();
+
+ runEval = true;
+
+ //at the end of each eval, push cookies
+ //TODO: this should happen before the "delayed" watches fire, because if some cookies are not
+ // strings or browser refuses to store some cookies, we update the model in the push fn.
+ $rootScope.$watch(push);
+
+ return cookies;
+
+
+ /**
+ * Pushes all the cookies from the service to the browser and verifies if all cookies were stored.
+ */
+ function push() {
+ var name,
+ value,
+ browserCookies,
+ updated;
+
+ //delete any cookies deleted in $cookies
+ for (name in lastCookies) {
+ if (isUndefined(cookies[name])) {
+ $browser.cookies(name, undefined);
+ }
+ }
+
+ //update all cookies updated in $cookies
+ for(name in cookies) {
+ value = cookies[name];
+ if (!angular.isString(value)) {
+ if (angular.isDefined(lastCookies[name])) {
+ cookies[name] = lastCookies[name];
+ } else {
+ delete cookies[name];
+ }
+ } else if (value !== lastCookies[name]) {
+ $browser.cookies(name, value);
+ updated = true;
+ }
+ }
+
+ //verify what was actually stored
+ if (updated){
+ updated = false;
+ browserCookies = $browser.cookies();
+
+ for (name in cookies) {
+ if (cookies[name] !== browserCookies[name]) {
+ //delete or reset all cookies that the browser dropped from $cookies
+ if (isUndefined(browserCookies[name])) {
+ delete cookies[name];
+ } else {
+ cookies[name] = browserCookies[name];
+ }
+ updated = true;
+ }
+ }
+ }
+ }
+ }]).
+
+
+ /**
+ * @ngdoc object
+ * @name ngCookies.$cookieStore
+ * @requires $cookies
+ *
+ * @description
+ * Provides a key-value (string-object) storage, that is backed by session cookies.
+ * Objects put or retrieved from this storage are automatically serialized or
+ * deserialized by angular's toJson/fromJson.
+ * @example
+ */
+ factory('$cookieStore', ['$cookies', function($cookies) {
+
+ return {
+ /**
+ * @ngdoc method
+ * @name ngCookies.$cookieStore#get
+ * @methodOf ngCookies.$cookieStore
+ *
+ * @description
+ * Returns the value of given cookie key
+ *
+ * @param {string} key Id to use for lookup.
+ * @returns {Object} Deserialized cookie value.
+ */
+ get: function(key) {
+ var value = $cookies[key];
+ return value ? angular.fromJson(value) : value;
+ },
+
+ /**
+ * @ngdoc method
+ * @name ngCookies.$cookieStore#put
+ * @methodOf ngCookies.$cookieStore
+ *
+ * @description
+ * Sets a value for given cookie key
+ *
+ * @param {string} key Id for the `value`.
+ * @param {Object} value Value to be stored.
+ */
+ put: function(key, value) {
+ $cookies[key] = angular.toJson(value);
+ },
+
+ /**
+ * @ngdoc method
+ * @name ngCookies.$cookieStore#remove
+ * @methodOf ngCookies.$cookieStore
+ *
+ * @description
+ * Remove given cookie
+ *
+ * @param {string} key Id of the key-value pair to delete.
+ */
+ remove: function(key) {
+ delete $cookies[key];
+ }
+ };
+
+ }]);
+
+
+})(window, window.angular);
View
7 1.1.5/angular-cookies.min.js
@@ -0,0 +1,7 @@
+/*
+ AngularJS v1.1.5
+ (c) 2010-2012 Google, Inc. http://angularjs.org
+ License: MIT
+*/
+(function(m,f,l){'use strict';f.module("ngCookies",["ng"]).factory("$cookies",["$rootScope","$browser",function(d,b){var c={},g={},h,i=!1,j=f.copy,k=f.isUndefined;b.addPollFn(function(){var a=b.cookies();h!=a&&(h=a,j(a,g),j(a,c),i&&d.$apply())})();i=!0;d.$watch(function(){var a,e,d;for(a in g)k(c[a])&&b.cookies(a,l);for(a in c)e=c[a],f.isString(e)?e!==g[a]&&(b.cookies(a,e),d=!0):f.isDefined(g[a])?c[a]=g[a]:delete c[a];if(d)for(a in e=b.cookies(),c)c[a]!==e[a]&&(k(e[a])?delete c[a]:c[a]=e[a])});return c}]).factory("$cookieStore",
+["$cookies",function(d){return{get:function(b){return(b=d[b])?f.fromJson(b):b},put:function(b,c){d[b]=f.toJson(c)},remove:function(b){delete d[b]}}}])})(window,window.angular);
View
304 1.1.5/angular-loader.js
@@ -0,0 +1,304 @@
+/**
+ * @license AngularJS v1.1.5
+ * (c) 2010-2012 Google, Inc. http://angularjs.org
+ * License: MIT
+ */
+
+(
+
+/**
+ * @ngdoc interface
+ * @name angular.Module
+ * @description
+ *
+ * Interface for configuring angular {@link angular.module modules}.
+ */
+
+function setupModuleLoader(window) {
+
+ function ensure(obj, name, factory) {
+ return obj[name] || (obj[name] = factory());
+ }
+
+ return ensure(ensure(window, 'angular', Object), 'module', function() {
+ /** @type {Object.<string, angular.Module>} */
+ var modules = {};
+
+ /**
+ * @ngdoc function
+ * @name angular.module
+ * @description
+ *
+ * The `angular.module` is a global place for creating and registering Angular modules. All
+ * modules (angular core or 3rd party) that should be available to an application must be
+ * registered using this mechanism.
+ *
+ *
+ * # Module
+ *
+ * A module is a collocation of services, directives, filters, and configuration information. Module
+ * is used to configure the {@link AUTO.$injector $injector}.
+ *
+ * <pre>
+ * // Create a new module
+ * var myModule = angular.module('myModule', []);
+ *
+ * // register a new service
+ * myModule.value('appName', 'MyCoolApp');
+ *
+ * // configure existing services inside initialization blocks.
+ * myModule.config(function($locationProvider) {
+'use strict';
+ * // Configure existing providers
+ * $locationProvider.hashPrefix('!');
+ * });
+ * </pre>
+ *
+ * Then you can create an injector and load your modules like this:
+ *
+ * <pre>
+ * var injector = angular.injector(['ng', 'MyModule'])
+ * </pre>
+ *
+ * However it's more likely that you'll just use
+ * {@link ng.directive:ngApp ngApp} or
+ * {@link angular.bootstrap} to simplify this process for you.
+ *
+ * @param {!string} name The name of the module to create or retrieve.
+ * @param {Array.<string>=} requires If specified then new module is being created. If unspecified then the
+ * the module is being retrieved for further configuration.
+ * @param {Function} configFn Optional configuration function for the module. Same as
+ * {@link angular.Module#config Module#config()}.
+ * @returns {module} new module with the {@link angular.Module} api.
+ */
+ return function module(name, requires, configFn) {
+ if (requires && modules.hasOwnProperty(name)) {
+ modules[name] = null;
+ }
+ return ensure(modules, name, function() {
+ if (!requires) {
+ throw Error('No module: ' + name);
+ }
+
+ /** @type {!Array.<Array.<*>>} */
+ var invokeQueue = [];
+
+ /** @type {!Array.<Function>} */
+ var runBlocks = [];
+
+ var config = invokeLater('$injector', 'invoke');
+
+ /** @type {angular.Module} */
+ var moduleInstance = {
+ // Private state
+ _invokeQueue: invokeQueue,
+ _runBlocks: runBlocks,
+
+ /**
+ * @ngdoc property
+ * @name angular.Module#requires
+ * @propertyOf angular.Module
+ * @returns {Array.<string>} List of module names which must be loaded before this module.
+ * @description
+ * Holds the list of modules which the injector will load before the current module is loaded.
+ */
+ requires: requires,
+
+ /**
+ * @ngdoc property
+ * @name angular.Module#name
+ * @propertyOf angular.Module
+ * @returns {string} Name of the module.
+ * @description
+ */
+ name: name,
+
+
+ /**
+ * @ngdoc method
+ * @name angular.Module#provider
+ * @methodOf angular.Module
+ * @param {string} name service name
+ * @param {Function} providerType Construction function for creating new instance of the service.
+ * @description
+ * See {@link AUTO.$provide#provider $provide.provider()}.
+ */
+ provider: invokeLater('$provide', 'provider'),
+
+ /**
+ * @ngdoc method
+ * @name angular.Module#factory
+ * @methodOf angular.Module
+ * @param {string} name service name
+ * @param {Function} providerFunction Function for creating new instance of the service.
+ * @description
+ * See {@link AUTO.$provide#factory $provide.factory()}.
+ */
+ factory: invokeLater('$provide', 'factory'),
+
+ /**
+ * @ngdoc method
+ * @name angular.Module#service
+ * @methodOf angular.Module
+ * @param {string} name service name
+ * @param {Function} constructor A constructor function that will be instantiated.
+ * @description
+ * See {@link AUTO.$provide#service $provide.service()}.
+ */
+ service: invokeLater('$provide', 'service'),
+
+ /**
+ * @ngdoc method
+ * @name angular.Module#value
+ * @methodOf angular.Module
+ * @param {string} name service name
+ * @param {*} object Service instance object.
+ * @description
+ * See {@link AUTO.$provide#value $provide.value()}.
+ */
+ value: invokeLater('$provide', 'value'),
+
+ /**
+ * @ngdoc method
+ * @name angular.Module#constant
+ * @methodOf angular.Module
+ * @param {string} name constant name
+ * @param {*} object Constant value.
+ * @description
+ * Because the constant are fixed, they get applied before other provide methods.
+ * See {@link AUTO.$provide#constant $provide.constant()}.
+ */
+ constant: invokeLater('$provide', 'constant', 'unshift'),
+
+ /**
+ * @ngdoc method
+ * @name angular.Module#animation
+ * @methodOf angular.Module
+ * @param {string} name animation name
+ * @param {Function} animationFactory Factory function for creating new instance of an animation.
+ * @description
+ *
+ * Defines an animation hook that can be later used with {@link ng.directive:ngAnimate ngAnimate}
+ * alongside {@link ng.directive:ngAnimate#Description common ng directives} as well as custom directives.
+ * <pre>
+ * module.animation('animation-name', function($inject1, $inject2) {
+ * return {
+ * //this gets called in preparation to setup an animation
+ * setup : function(element) { ... },
+ *
+ * //this gets called once the animation is run
+ * start : function(element, done, memo) { ... }
+ * }
+ * })
+ * </pre>
+ *
+ * See {@link ng.$animationProvider#register $animationProvider.register()} and
+ * {@link ng.directive:ngAnimate ngAnimate} for more information.
+ */
+ animation: invokeLater('$animationProvider', 'register'),
+
+ /**
+ * @ngdoc method
+ * @name angular.Module#filter
+ * @methodOf angular.Module
+ * @param {string} name Filter name.
+ * @param {Function} filterFactory Factory function for creating new instance of filter.
+ * @description
+ * See {@link ng.$filterProvider#register $filterProvider.register()}.
+ */
+ filter: invokeLater('$filterProvider', 'register'),
+
+ /**
+ * @ngdoc method
+ * @name angular.Module#controller
+ * @methodOf angular.Module
+ * @param {string} name Controller name.
+ * @param {Function} constructor Controller constructor function.
+ * @description
+ * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
+ */
+ controller: invokeLater('$controllerProvider', 'register'),
+
+ /**
+ * @ngdoc method
+ * @name angular.Module#directive
+ * @methodOf angular.Module
+ * @param {string} name directive name
+ * @param {Function} directiveFactory Factory function for creating new instance of
+ * directives.
+ * @description
+ * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
+ */
+ directive: invokeLater('$compileProvider', 'directive'),
+
+ /**
+ * @ngdoc method
+ * @name angular.Module#config
+ * @methodOf angular.Module
+ * @param {Function} configFn Execute this function on module load. Useful for service
+ * configuration.
+ * @description
+ * Use this method to register work which needs to be performed on module loading.
+ */
+ config: config,
+
+ /**
+ * @ngdoc method
+ * @name angular.Module#run
+ * @methodOf angular.Module
+ * @param {Function} initializationFn Execute this function after injector creation.
+ * Useful for application initialization.
+ * @description
+ * Use this method to register work which should be performed when the injector is done
+ * loading all modules.
+ */
+ run: function(block) {
+ runBlocks.push(block);
+ return this;
+ }
+ };
+
+ if (configFn) {
+ config(configFn);
+ }
+
+ return moduleInstance;
+
+ /**
+ * @param {string} provider
+ * @param {string} method
+ * @param {String=} insertMethod
+ * @returns {angular.Module}
+ */
+ function invokeLater(provider, method, insertMethod) {
+ return function() {
+ invokeQueue[insertMethod || 'push']([provider, method, arguments]);
+ return moduleInstance;
+ }
+ }
+ });
+ };
+ });
+
+}
+
+)(window);
+
+/**
+ * Closure compiler type information
+ *
+ * @typedef { {
+ * requires: !Array.<string>,
+ * invokeQueue: !Array.<Array.<*>>,
+ *
+ * service: function(string, Function):angular.Module,
+ * factory: function(string, Function):angular.Module,
+ * value: function(string, *):angular.Module,
+ *
+ * filter: function(string, Function):angular.Module,
+ *
+ * init: function(Function):angular.Module
+ * } }
+ */
+angular.Module;
+
View
7 1.1.5/angular-loader.min.js
@@ -0,0 +1,7 @@
+/*
+ AngularJS v1.1.5
+ (c) 2010-2012 Google, Inc. http://angularjs.org
+ License: MIT
+*/
+(function(i){'use strict';function d(c,b,e){return c[b]||(c[b]=e())}return d(d(i,"angular",Object),"module",function(){var c={};return function(b,e,f){e&&c.hasOwnProperty(b)&&(c[b]=null);return d(c,b,function(){function a(a,b,d){return function(){c[d||"push"]([a,b,arguments]);return g}}if(!e)throw Error("No module: "+b);var c=[],d=[],h=a("$injector","invoke"),g={_invokeQueue:c,_runBlocks:d,requires:e,name:b,provider:a("$provide","provider"),factory:a("$provide","factory"),service:a("$provide","service"),
+value:a("$provide","value"),constant:a("$provide","constant","unshift"),animation:a("$animationProvider","register"),filter:a("$filterProvider","register"),controller:a("$controllerProvider","register"),directive:a("$compileProvider","directive"),config:h,run:function(a){d.push(a);return this}};f&&h(f);return g})}})})(window);
View
460 1.1.5/angular-mobile.js
@@ -0,0 +1,460 @@
+/**
+ * @license AngularJS v1.1.5
+ * (c) 2010-2012 Google, Inc. http://angularjs.org
+ * License: MIT
+ */
+(function(window, angular, undefined) {
+'use strict';
+
+/**
+ * @ngdoc overview
+ * @name ngMobile
+ * @description
+ * Touch events and other mobile helpers.
+ * Based on jQuery Mobile touch event handling (jquerymobile.com)
+ */
+
+// define ngMobile module
+var ngMobile = angular.module('ngMobile', []);
+
+/**
+ * @ngdoc directive
+ * @name ngMobile.directive:ngClick
+ *
+ * @description
+ * A more powerful replacement for the default ngClick designed to be used on touchscreen
+ * devices. Most mobile browsers wait about 300ms after a tap-and-release before sending
+ * the click event. This version handles them immediately, and then prevents the
+ * following click event from propagating.
+ *
+ * This directive can fall back to using an ordinary click event, and so works on desktop
+ * browsers as well as mobile.
+ *
+ * This directive also sets the CSS class `ng-click-active` while the element is being held
+ * down (by a mouse click or touch) so you can restyle the depressed element if you wish.
+ *
+ * @element ANY
+ * @param {expression} ngClick {@link guide/expression Expression} to evaluate
+ * upon tap. (Event object is available as `$event`)
+ *
+ * @example
+ <doc:example>
+ <doc:source>
+ <button ng-click="count = count + 1" ng-init="count=0">
+ Increment
+ </button>
+ count: {{ count }}
+ </doc:source>
+ </doc:example>
+ */
+
+ngMobile.config(['$provide', function($provide) {
+ $provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
+ // drop the default ngClick directive
+ $delegate.shift();
+ return $delegate;
+ }]);
+}]);
+
+ngMobile.directive('ngClick', ['$parse', '$timeout', '$rootElement',
+ function($parse, $timeout, $rootElement) {
+ var TAP_DURATION = 750; // Shorter than 750ms is a tap, longer is a taphold or drag.
+ var MOVE_TOLERANCE = 12; // 12px seems to work in most mobile browsers.
+ var PREVENT_DURATION = 2500; // 2.5 seconds maximum from preventGhostClick call to click
+ var CLICKBUSTER_THRESHOLD = 25; // 25 pixels in any dimension is the limit for busting clicks.
+
+ var ACTIVE_CLASS_NAME = 'ng-click-active';
+ var lastPreventedTime;
+ var touchCoordinates;
+
+
+ // TAP EVENTS AND GHOST CLICKS
+ //
+ // Why tap events?
+ // Mobile browsers detect a tap, then wait a moment (usually ~300ms) to see if you're
+ // double-tapping, and then fire a click event.
+ //
+ // This delay sucks and makes mobile apps feel unresponsive.
+ // So we detect touchstart, touchmove, touchcancel and touchend ourselves and determine when
+ // the user has tapped on something.
+ //
+ // What happens when the browser then generates a click event?
+ // The browser, of course, also detects the tap and fires a click after a delay. This results in
+ // tapping/clicking twice. So we do "clickbusting" to prevent it.
+ //
+ // How does it work?
+ // We attach global touchstart and click handlers, that run during the capture (early) phase.
+ // So the sequence for a tap is:
+ // - global touchstart: Sets an "allowable region" at the point touched.
+ // - element's touchstart: Starts a touch
+ // (- touchmove or touchcancel ends the touch, no click follows)
+ // - element's touchend: Determines if the tap is valid (didn't move too far away, didn't hold
+ // too long) and fires the user's tap handler. The touchend also calls preventGhostClick().
+ // - preventGhostClick() removes the allowable region the global touchstart created.
+ // - The browser generates a click event.
+ // - The global click handler catches the click, and checks whether it was in an allowable region.
+ // - If preventGhostClick was called, the region will have been removed, the click is busted.
+ // - If the region is still there, the click proceeds normally. Therefore clicks on links and
+ // other elements without ngTap on them work normally.
+ //
+ // This is an ugly, terrible hack!
+ // Yeah, tell me about it. The alternatives are using the slow click events, or making our users
+ // deal with the ghost clicks, so I consider this the least of evils. Fortunately Angular
+ // encapsulates this ugly logic away from the user.
+ //
+ // Why not just put click handlers on the element?
+ // We do that too, just to be sure. The problem is that the tap event might have caused the DOM
+ // to change, so that the click fires in the same position but something else is there now. So
+ // the handlers are global and care only about coordinates and not elements.
+
+ // Checks if the coordinates are close enough to be within the region.
+ function hit(x1, y1, x2, y2) {
+ return Math.abs(x1 - x2) < CLICKBUSTER_THRESHOLD && Math.abs(y1 - y2) < CLICKBUSTER_THRESHOLD;
+ }
+
+ // Checks a list of allowable regions against a click location.
+ // Returns true if the click should be allowed.
+ // Splices out the allowable region from the list after it has been used.
+ function checkAllowableRegions(touchCoordinates, x, y) {
+ for (var i = 0; i < touchCoordinates.length; i += 2) {
+ if (hit(touchCoordinates[i], touchCoordinates[i+1], x, y)) {
+ touchCoordinates.splice(i, i + 2);
+ return true; // allowable region
+ }
+ }
+ return false; // No allowable region; bust it.
+ }
+
+ // Global click handler that prevents the click if it's in a bustable zone and preventGhostClick
+ // was called recently.
+ function onClick(event) {
+ if (Date.now() - lastPreventedTime > PREVENT_DURATION) {
+ return; // Too old.
+ }
+
+ var touches = event.touches && event.touches.length ? event.touches : [event];
+ var x = touches[0].clientX;
+ var y = touches[0].clientY;
+ // Work around desktop Webkit quirk where clicking a label will fire two clicks (on the label
+ // and on the input element). Depending on the exact browser, this second click we don't want
+ // to bust has either (0,0) or negative coordinates.
+ if (x < 1 && y < 1) {
+ return; // offscreen
+ }
+
+ // Look for an allowable region containing this click.
+ // If we find one, that means it was created by touchstart and not removed by
+ // preventGhostClick, so we don't bust it.
+ if (checkAllowableRegions(touchCoordinates, x, y)) {
+ return;
+ }
+
+ // If we didn't find an allowable region, bust the click.
+ event.stopPropagation();
+ event.preventDefault();
+ }
+
+
+ // Global touchstart handler that creates an allowable region for a click event.
+ // This allowable region can be removed by preventGhostClick if we want to bust it.
+ function onTouchStart(event) {
+ var touches = event.touches && event.touches.length ? event.touches : [event];
+ var x = touches[0].clientX;
+ var y = touches[0].clientY;
+ touchCoordinates.push(x, y);
+
+ $timeout(function() {
+ // Remove the allowable region.
+ for (var i = 0; i < touchCoordinates.length; i += 2) {
+ if (touchCoordinates[i] == x && touchCoordinates[i+1] == y) {
+ touchCoordinates.splice(i, i + 2);
+ return;
+ }
+ }
+ }, PREVENT_DURATION, false);
+ }
+
+ // On the first call, attaches some event handlers. Then whenever it gets called, it creates a
+ // zone around the touchstart where clicks will get busted.
+ function preventGhostClick(x, y) {
+ if (!touchCoordinates) {
+ $rootElement[0].addEventListener('click', onClick, true);
+ $rootElement[0].addEventListener('touchstart', onTouchStart, true);
+ touchCoordinates = [];
+ }
+
+ lastPreventedTime = Date.now();
+
+ checkAllowableRegions(touchCoordinates, x, y);
+ }
+
+ // Actual linking function.
+ return function(scope, element, attr) {
+ var clickHandler = $parse(attr.ngClick),
+ tapping = false,
+ tapElement, // Used to blur the element after a tap.
+ startTime, // Used to check if the tap was held too long.
+ touchStartX,
+ touchStartY;
+
+ function resetState() {
+ tapping = false;
+ element.removeClass(ACTIVE_CLASS_NAME);
+ }
+
+ element.bind('touchstart', function(event) {
+ tapping = true;
+ tapElement = event.target ? event.target : event.srcElement; // IE uses srcElement.
+ // Hack for Safari, which can target text nodes instead of containers.
+ if(tapElement.nodeType == 3) {
+ tapElement = tapElement.parentNode;
+ }
+
+ element.addClass(ACTIVE_CLASS_NAME);
+
+ startTime = Date.now();
+
+ var touches = event.touches && event.touches.length ? event.touches : [event];
+ var e = touches[0].originalEvent || touches[0];
+ touchStartX = e.clientX;
+ touchStartY = e.clientY;
+ });
+
+ element.bind('touchmove', function(event) {
+ resetState();
+ });
+
+ element.bind('touchcancel', function(event) {
+ resetState();
+ });
+
+ element.bind('touchend', function(event) {
+ var diff = Date.now() - startTime;
+
+ var touches = (event.changedTouches && event.changedTouches.length) ? event.changedTouches :
+ ((event.touches && event.touches.length) ? event.touches : [event]);
+ var e = touches[0].originalEvent || touches[0];
+ var x = e.clientX;
+ var y = e.clientY;
+ var dist = Math.sqrt( Math.pow(x - touchStartX, 2) + Math.pow(y - touchStartY, 2) );
+
+ if (tapping && diff < TAP_DURATION && dist < MOVE_TOLERANCE) {
+ // Call preventGhostClick so the clickbuster will catch the corresponding click.
+ preventGhostClick(x, y);
+
+ // Blur the focused element (the button, probably) before firing the callback.
+ // This doesn't work perfectly on Android Chrome, but seems to work elsewhere.
+ // I couldn't get anything to work reliably on Android Chrome.
+ if (tapElement) {
+ tapElement.blur();
+ }
+
+ scope.$apply(function() {
+ // TODO(braden): This is sending the touchend, not a tap or click. Is that kosher?
+ clickHandler(scope, {$event: event});
+ });
+ }
+
+ resetState();
+ });
+
+ // Hack for iOS Safari's benefit. It goes searching for onclick handlers and is liable to click
+ // something else nearby.
+ element.onclick = function(event) { };
+
+ // Fallback click handler.
+ // Busted clicks don't get this far, and adding this handler allows ng-tap to be used on
+ // desktop as well, to allow more portable sites.
+ element.bind('click', function(event) {
+ scope.$apply(function() {
+ clickHandler(scope, {$event: event});
+ });
+ });
+
+ element.bind('mousedown', function(event) {
+ element.addClass(ACTIVE_CLASS_NAME);
+ });
+
+ element.bind('mousemove mouseup', function(event) {
+ element.removeClass(ACTIVE_CLASS_NAME);
+ });
+
+ };
+}]);
+
+/**
+ * @ngdoc directive
+ * @name ngMobile.directive:ngSwipeLeft
+ *
+ * @description
+ * Specify custom behavior when an element is swiped to the left on a touchscreen device.
+ * A leftward swipe is a quick, right-to-left slide of the finger.
+ * Though ngSwipeLeft is designed for touch-based devices, it will work with a mouse click and drag too.
+ *
+ * @element ANY
+ * @param {expression} ngSwipeLeft {@link guide/expression Expression} to evaluate
+ * upon left swipe. (Event object is available as `$event`)
+ *
+ * @example
+ <doc:example>
+ <doc:source>
+ <div ng-show="!showActions" ng-swipe-left="showActions = true">
+ Some list content, like an email in the inbox
+ </div>
+ <div ng-show="showActions" ng-swipe-right="showActions = false">
+ <button ng-click="reply()">Reply</button>
+ <button ng-click="delete()">Delete</button>
+ </div>
+ </doc:source>
+ </doc:example>
+ */
+
+/**
+ * @ngdoc directive
+ * @name ngMobile.directive:ngSwipeRight
+ *
+ * @description
+ * Specify custom behavior when an element is swiped to the right on a touchscreen device.
+ * A rightward swipe is a quick, left-to-right slide of the finger.
+ * Though ngSwipeRight is designed for touch-based devices, it will work with a mouse click and drag too.
+ *
+ * @element ANY
+ * @param {expression} ngSwipeRight {@link guide/expression Expression} to evaluate
+ * upon right swipe. (Event object is available as `$event`)
+ *
+ * @example
+ <doc:example>
+ <doc:source>
+ <div ng-show="!showActions" ng-swipe-left="showActions = true">
+ Some list content, like an email in the inbox
+ </div>
+ <div ng-show="showActions" ng-swipe-right="showActions = false">
+ <button ng-click="reply()">Reply</button>
+ <button ng-click="delete()">Delete</button>
+ </div>
+ </doc:source>
+ </doc:example>
+ */
+
+function makeSwipeDirective(directiveName, direction) {
+ ngMobile.directive(directiveName, ['$parse', function($parse) {
+ // The maximum vertical delta for a swipe should be less than 75px.
+ var MAX_VERTICAL_DISTANCE = 75;
+ // Vertical distance should not be more than a fraction of the horizontal distance.
+ var MAX_VERTICAL_RATIO = 0.3;
+ // At least a 30px lateral motion is necessary for a swipe.
+ var MIN_HORIZONTAL_DISTANCE = 30;
+ // The total distance in any direction before we make the call on swipe vs. scroll.
+ var MOVE_BUFFER_RADIUS = 10;
+
+ function getCoordinates(event) {
+ var touches = event.touches && event.touches.length ? event.touches : [event];
+ var e = (event.changedTouches && event.changedTouches[0]) ||
+ (event.originalEvent && event.originalEvent.changedTouches &&
+ event.originalEvent.changedTouches[0]) ||
+ touches[0].originalEvent || touches[0];
+
+ return {
+ x: e.clientX,
+ y: e.clientY
+ };
+ }
+
+ return function(scope, element, attr) {
+ var swipeHandler = $parse(attr[directiveName]);
+ var startCoords, valid;
+ var totalX, totalY;
+ var lastX, lastY;
+
+ function validSwipe(event) {
+ // Check that it's within the coordinates.
+ // Absolute vertical distance must be within tolerances.
+ // Horizontal distance, we take the current X - the starting X.
+ // This is negative for leftward swipes and positive for rightward swipes.
+ // After multiplying by the direction (-1 for left, +1 for right), legal swipes
+ // (ie. same direction as the directive wants) will have a positive delta and
+ // illegal ones a negative delta.
+ // Therefore this delta must be positive, and larger than the minimum.
+ if (!startCoords) return false;
+ var coords = getCoordinates(event);
+ var deltaY = Math.abs(coords.y - startCoords.y);
+ var deltaX = (coords.x - startCoords.x) * direction;
+ return valid && // Short circuit for already-invalidated swipes.
+ deltaY < MAX_VERTICAL_DISTANCE &&
+ deltaX > 0 &&
+ deltaX > MIN_HORIZONTAL_DISTANCE &&
+ deltaY / deltaX < MAX_VERTICAL_RATIO;
+ }
+
+ element.bind('touchstart mousedown', function(event) {
+ startCoords = getCoordinates(event);
+ valid = true;
+ totalX = 0;
+ totalY = 0;
+ lastX = startCoords.x;
+ lastY = startCoords.y;
+ });
+
+ element.bind('touchcancel', function(event) {
+ valid = false;
+ });
+
+ element.bind('touchmove mousemove', function(event) {
+ if (!valid) return;
+
+ // Android will send a touchcancel if it thinks we're starting to scroll.
+ // So when the total distance (+ or - or both) exceeds 10px in either direction,
+ // we either:
+ // - On totalX > totalY, we send preventDefault() and treat this as a swipe.
+ // - On totalY > totalX, we let the browser handle it as a scroll.
+
+ // Invalidate a touch while it's in progress if it strays too far away vertically.
+ // We don't want a scroll down and back up while drifting sideways to be a swipe just
+ // because you happened to end up vertically close in the end.
+ if (!startCoords) return;
+ var coords = getCoordinates(event);
+
+ if (Math.abs(coords.y - startCoords.y) > MAX_VERTICAL_DISTANCE) {
+ valid = false;
+ return;
+ }
+
+ totalX += Math.abs(coords.x - lastX);
+ totalY += Math.abs(coords.y - lastY);
+
+ lastX = coords.x;
+ lastY = coords.y;
+
+ if (totalX < MOVE_BUFFER_RADIUS && totalY < MOVE_BUFFER_RADIUS) {
+ return;
+ }
+
+ // One of totalX or totalY has exceeded the buffer, so decide on swipe vs. scroll.
+ if (totalY > totalX) {
+ valid = false;
+ return;
+ } else {
+ event.preventDefault();
+ }
+ });
+
+ element.bind('touchend mouseup', function(event) {
+ if (validSwipe(event)) {
+ // Prevent this swipe from bubbling up to any other elements with ngSwipes.
+ event.stopPropagation();
+ scope.$apply(function() {
+ swipeHandler(scope, {$event:event});
+ });
+ }
+ });
+ };
+ }]);
+}
+
+// Left is negative X-coordinate, right is positive.
+makeSwipeDirective('ngSwipeLeft', -1);
+makeSwipeDirective('ngSwipeRight', 1);
+
+
+
+})(window, window.angular);
View
11 1.1.5/angular-mobile.min.js
@@ -0,0 +1,11 @@
+/*
+ AngularJS v1.1.5
+ (c) 2010-2012 Google, Inc. http://angularjs.org
+ License: MIT
+*/
+(function(u,s){'use strict';function k(i,t){j.directive(i,["$parse",function(l){function g(b){var h=b.touches&&b.touches.length?b.touches:[b],b=b.changedTouches&&b.changedTouches[0]||b.originalEvent&&b.originalEvent.changedTouches&&b.originalEvent.changedTouches[0]||h[0].originalEvent||h[0];return{x:b.clientX,y:b.clientY}}var m=75,j=0.3,p=30;return function(b,h,n){function o(e){if(!a)return!1;var b=g(e),e=Math.abs(b.y-a.y),b=(b.x-a.x)*t;return c&&e<m&&b>0&&b>p&&e/b<j}var d=l(n[i]),a,c,f,e,q,r;h.bind("touchstart mousedown",
+function(b){a=g(b);c=!0;e=f=0;q=a.x;r=a.y});h.bind("touchcancel",function(){c=!1});h.bind("touchmove mousemove",function(b){if(c&&a){var d=g(b);Math.abs(d.y-a.y)>m?c=!1:(f+=Math.abs(d.x-q),e+=Math.abs(d.y-r),q=d.x,r=d.y,f<10&&e<10||(e>f?c=!1:b.preventDefault()))}});h.bind("touchend mouseup",function(a){o(a)&&(a.stopPropagation(),b.$apply(function(){d(b,{$event:a})}))})}}])}var j=s.module("ngMobile",[]);j.config(["$provide",function(i){i.decorator("ngClickDirective",["$delegate",function(i){i.shift();
+return i}])}]);j.directive("ngClick",["$parse","$timeout","$rootElement",function(i,j,l){function g(a,c,b){for(var e=0;e<a.length;e+=2)if(Math.abs(a[e]-c)<h&&Math.abs(a[e+1]-b)<h)return a.splice(e,e+2),!0;return!1}function m(a){if(!(Date.now()-o>b)){var c=a.touches&&a.touches.length?a.touches:[a],f=c[0].clientX,c=c[0].clientY;!(f<1&&c<1)&&!g(d,f,c)&&(a.stopPropagation(),a.preventDefault())}}function k(a){var a=a.touches&&a.touches.length?a.touches:[a],c=a[0].clientX,f=a[0].clientY;d.push(c,f);j(function(){for(var a=
+0;a<d.length;a+=2)if(d[a]==c&&d[a+1]==f){d.splice(a,a+2);break}},b,!1)}function p(a,b){d||(l[0].addEventListener("click",m,!0),l[0].addEventListener("touchstart",k,!0),d=[]);o=Date.now();g(d,a,b)}var b=2500,h=25,n="ng-click-active",o,d;return function(a,b,d){function e(){j=!1;b.removeClass(n)}var h=i(d.ngClick),j=!1,g,k,l,m;b.bind("touchstart",function(a){j=!0;g=a.target?a.target:a.srcElement;if(g.nodeType==3)g=g.parentNode;b.addClass(n);k=Date.now();a=a.touches&&a.touches.length?a.touches:[a];a=
+a[0].originalEvent||a[0];l=a.clientX;m=a.clientY});b.bind("touchmove",function(){e()});b.bind("touchcancel",function(){e()});b.bind("touchend",function(b){var d=Date.now()-k,c=b.changedTouches&&b.changedTouches.length?b.changedTouches:b.touches&&b.touches.length?b.touches:[b],f=c[0].originalEvent||c[0],c=f.clientX,f=f.clientY,i=Math.sqrt(Math.pow(c-l,2)+Math.pow(f-m,2));j&&d<750&&i<12&&(p(c,f),g&&g.blur(),a.$apply(function(){h(a,{$event:b})}));e()});b.onclick=function(){};b.bind("click",function(b){a.$apply(function(){h(a,
+{$event:b})})});b.bind("mousedown",function(){b.addClass(n)});b.bind("mousemove mouseup",function(){b.removeClass(n)})}}]);k("ngSwipeLeft",-1);k("ngSwipeRight",1)})(window,window.angular);
View
1,886 1.1.5/angular-mocks.js
@@ -0,0 +1,1886 @@
+/**
+ * @license AngularJS v1.1.5
+ * (c) 2010-2012 Google, Inc. http://angularjs.org
+ * License: MIT
+ *
+ * TODO(vojta): wrap whole file into closure during build
+ */
+
+/**
+ * @ngdoc overview
+ * @name angular.mock
+ * @description
+ *
+ * Namespace from 'angular-mocks.js' which contains testing related code.
+ */
+angular.mock = {};
+
+/**
+ * ! This is a private undocumented service !
+ *
+ * @name ngMock.$browser
+ *
+ * @description
+ * This service is a mock implementation of {@link ng.$browser}. It provides fake
+ * implementation for commonly used browser apis that are hard to test, e.g. setTimeout, xhr,
+ * cookies, etc...
+ *
+ * The api of this service is the same as that of the real {@link ng.$browser $browser}, except
+ * that there are several helper methods available which can be used in tests.
+ */
+angular.mock.$BrowserProvider = function() {
+ this.$get = function(){
+ return new angular.mock.$Browser();
+ };
+};
+
+angular.mock.$Browser = function() {
+ var self = this;
+
+ this.isMock = true;
+ self.$$url = "http://server/";
+ self.$$lastUrl = self.$$url; // used by url polling fn
+ self.pollFns = [];
+
+ // TODO(vojta): remove this temporary api
+ self.$$completeOutstandingRequest = angular.noop;
+ self.$$incOutstandingRequestCount = angular.noop;
+
+
+ // register url polling fn
+
+ self.onUrlChange = function(listener) {
+ self.pollFns.push(
+ function() {
+ if (self.$$lastUrl != self.$$url) {
+ self.$$lastUrl = self.$$url;
+ listener(self.$$url);
+ }
+ }
+ );
+
+ return listener;
+ };
+
+ self.cookieHash = {};
+ self.lastCookieHash = {};
+ self.deferredFns = [];
+ self.deferredNextId = 0;
+
+ self.defer = function(fn, delay) {
+ delay = delay || 0;
+ self.deferredFns.push({time:(self.defer.now + delay), fn:fn, id: self.deferredNextId});
+ self.deferredFns.sort(function(a,b){ return a.time - b.time;});
+ return self.deferredNextId++;
+ };
+
+
+ self.defer.now = 0;
+
+
+ self.defer.cancel = function(deferId) {
+ var fnIndex;
+
+ angular.forEach(self.deferredFns, function(fn, index) {
+ if (fn.id === deferId) fnIndex = index;
+ });
+
+ if (fnIndex !== undefined) {
+ self.deferredFns.splice(fnIndex, 1);
+ return true;
+ }
+
+ return false;
+ };
+
+
+ /**
+ * @name ngMock.$browser#defer.flush
+ * @methodOf ngMock.$browser
+ *
+ * @description
+ * Flushes all pending requests and executes the defer callbacks.
+ *
+ * @param {number=} number of milliseconds to flush. See {@link #defer.now}
+ */
+ self.defer.flush = function(delay) {
+ if (angular.isDefined(delay)) {
+ self.defer.now += delay;
+ } else {
+ if (self.deferredFns.length) {
+ self.defer.now = self.deferredFns[self.deferredFns.length-1].time;
+ } else {
+ throw Error('No deferred tasks to be flushed');
+ }
+ }
+
+ while (self.deferredFns.length && self.deferredFns[0].time <= self.defer.now) {
+ self.deferredFns.shift().fn();
+ }
+ };
+ /**
+ * @name ngMock.$browser#defer.now
+ * @propertyOf ngMock.$browser
+ *
+ * @description
+ * Current milliseconds mock time.
+ */
+
+ self.$$baseHref = '';
+ self.baseHref = function() {
+ return this.$$baseHref;
+ };
+};
+angular.mock.$Browser.prototype = {
+
+/**
+ * @name ngMock.$browser#poll
+ * @methodOf ngMock.$browser
+ *
+ * @description
+ * run all fns in pollFns
+ */
+ poll: function poll() {
+ angular.forEach(this.pollFns, function(pollFn){
+ pollFn();
+ });
+ },
+
+ addPollFn: function(pollFn) {
+ this.pollFns.push(pollFn);
+ return pollFn;
+ },
+
+ url: function(url, replace) {
+ if (url) {
+ this.$$url = url;
+ return this;
+ }
+
+ return this.$$url;
+ },
+
+ cookies: function(name, value) {
+ if (name) {
+ if (value == undefined) {
+ delete this.cookieHash[name];
+ } else {
+ if (angular.isString(value) && //strings only
+ value.length <= 4096) { //strict cookie storage limits
+ this.cookieHash[name] = value;
+ }
+ }
+ } else {
+ if (!angular.equals(this.cookieHash, this.lastCookieHash)) {
+ this.lastCookieHash = angular.copy(this.cookieHash);
+ this.cookieHash = angular.copy(this.cookieHash);
+ }
+ return this.cookieHash;
+ }
+ },
+
+ notifyWhenNoOutstandingRequests: function(fn) {
+ fn();
+ }
+};
+
+
+/**
+ * @ngdoc object
+ * @name ngMock.$exceptionHandlerProvider
+ *
+ * @description
+ * Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors passed
+ * into the `$exceptionHandler`.
+ */
+
+/**
+ * @ngdoc object
+ * @name ngMock.$exceptionHandler
+ *
+ * @description
+ * Mock implementation of {@link ng.$exceptionHandler} that rethrows or logs errors passed
+ * into it. See {@link ngMock.$exceptionHandlerProvider $exceptionHandlerProvider} for configuration
+ * information.
+ *
+ *
+ * <pre>
+ * describe('$exceptionHandlerProvider', function() {
+ *
+ * it('should capture log messages and exceptions', function() {
+ *
+ * module(function($exceptionHandlerProvider) {
+ * $exceptionHandlerProvider.mode('log');
+ * });
+ *
+ * inject(function($log, $exceptionHandler, $timeout) {
+ * $timeout(function() { $log.log(1); });
+ * $timeout(function() { $log.log(2); throw 'banana peel'; });
+ * $timeout(function() { $log.log(3); });
+ * expect($exceptionHandler.errors).toEqual([]);
+ * expect($log.assertEmpty());
+ * $timeout.flush();
+ * expect($exceptionHandler.errors).toEqual(['banana peel']);
+ * expect($log.log.logs).toEqual([[1], [2], [3]]);
+ * });
+ * });
+ * });
+ * </pre>
+ */
+
+angular.mock.$ExceptionHandlerProvider = function() {
+ var handler;
+
+ /**
+ * @ngdoc method
+ * @name ngMock.$exceptionHandlerProvider#mode
+ * @methodOf ngMock.$exceptionHandlerProvider
+ *
+ * @description
+ * Sets the logging mode.
+ *
+ * @param {string} mode Mode of operation, defaults to `rethrow`.
+ *
+ * - `rethrow`: If any errors are passed into the handler in tests, it typically
+ * means that there is a bug in the application or test, so this mock will
+ * make these tests fail.
+ * - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log` mode stores an
+ * array of errors in `$exceptionHandler.errors`, to allow later assertion of them.
+ * See {@link ngMock.$log#assertEmpty assertEmpty()} and
+ * {@link ngMock.$log#reset reset()}
+ */
+ this.mode = function(mode) {
+ switch(mode) {
+ case 'rethrow':
+ handler = function(e) {
+ throw e;
+ };
+ break;
+ case 'log':
+ var errors = [];
+
+ handler = function(e) {
+ if (arguments.length == 1) {
+ errors.push(e);
+ } else {
+ errors.push([].slice.call(arguments, 0));
+ }
+ };
+
+ handler.errors = errors;
+ break;
+ default:
+ throw Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!");
+ }
+ };
+
+ this.$get = function() {
+ return handler;
+ };
+
+ this.mode('rethrow');
+};
+
+
+/**
+ * @ngdoc service
+ * @name ngMock.$log
+ *
+ * @description
+ * Mock implementation of {@link ng.$log} that gathers all logged messages in arrays
+ * (one array per logging level). These arrays are exposed as `logs` property of each of the
+ * level-specific log function, e.g. for level `error` the array is exposed as `$log.error.logs`.
+ *
+ */
+angular.mock.$LogProvider = function() {
+
+ function concat(array1, array2, index) {
+ return array1.concat(Array.prototype.slice.call(array2, index));
+ }
+
+
+ this.$get = function () {
+ var $log = {
+ log: function() { $log.log.logs.push(concat([], arguments, 0)); },
+ warn: function() { $log.warn.logs.push(concat([], arguments, 0)); },
+ info: function() { $log.info.logs.push(concat([], arguments, 0)); },
+ error: function() { $log.error.logs.push(concat([], arguments, 0)); }
+ };
+
+ /**
+ * @ngdoc method
+ * @name ngMock.$log#reset
+ * @methodOf ngMock.$log
+ *
+ * @description
+ * Reset all of the logging arrays to empty.
+ */
+ $log.reset = function () {
+ /**
+ * @ngdoc property
+ * @name ngMock.$log#log.logs
+ * @propertyOf ngMock.$log
+ *
+ * @description
+ * Array of messages logged using {@link ngMock.$log#log}.
+ *
+ * @example
+ * <pre>
+ * $log.log('Some Log');
+ * var first = $log.log.logs.unshift();
+ * </pre>
+ */
+ $log.log.logs = [];
+ /**
+ * @ngdoc property
+ * @name ngMock.$log#warn.logs
+ * @propertyOf ngMock.$log
+ *
+ * @description
+ * Array of messages logged using {@link ngMock.$log#warn}.
+ *
+ * @example
+ * <pre>
+ * $log.warn('Some Warning');
+ * var first = $log.warn.logs.unshift();
+ * </pre>
+ */
+ $log.warn.logs = [];
+ /**
+ * @ngdoc property
+ * @name ngMock.$log#info.logs
+ * @propertyOf ngMock.$log
+ *
+ * @description
+ * Array of messages logged using {@link ngMock.$log#info}.
+ *
+ * @example
+ * <pre>
+ * $log.info('Some Info');
+ * var first = $log.info.logs.unshift();
+ * </pre>
+ */
+ $log.info.logs = [];
+ /**
+ * @ngdoc property
+ * @name ngMock.$log#error.logs
+ * @propertyOf ngMock.$log
+ *
+ * @description
+ * Array of messages logged using {@link ngMock.$log#error}.
+ *
+ * @example
+ * <pre>
+ * $log.log('Some Error');
+ * var first = $log.error.logs.unshift();
+ * </pre>
+ */
+ $log.error.logs = [];
+ };
+
+ /**
+ * @ngdoc method
+ * @name ngMock.$log#assertEmpty
+ * @methodOf ngMock.$log
+ *
+ * @description
+ * Assert that the all of the logging methods have no logged messages. If messages present, an exception is thrown.
+ */
+ $log.assertEmpty = function() {
+ var errors = [];
+ angular.forEach(['error', 'warn', 'info', 'log'], function(logLevel) {
+ angular.forEach($log[logLevel].logs, function(log) {
+ angular.forEach(log, function (logItem) {
+ errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' + (logItem.stack || ''));
+ });
+ });
+ });
+ if (errors.length) {
+ errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or an expected " +
+ "log message was not checked and removed:");
+ errors.push('');
+ throw new Error(errors.join('\n---------\n'));
+ }
+ };
+
+ $log.reset();
+ return $log;
+ };
+};
+
+
+(function() {
+ var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
+
+ function jsonStringToDate(string){
+ var match;
+ if (match = string.match(R_ISO8061_STR)) {
+ var date = new Date(0),
+ tzHour = 0,
+ tzMin = 0;
+ if (match[9]) {
+ tzHour = int(match[9] + match[10]);
+ tzMin = int(match[9] + match[11]);
+ }
+ date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
+ date.setUTCHours(int(match[4]||0) - tzHour, int(match[5]||0) - tzMin, int(match[6]||0), int(match[7]||0));
+ return date;
+ }
+ return string;
+ }
+
+ function int(str) {
+ return parseInt(str, 10);
+ }
+
+ function padNumber(num, digits, trim) {
+ var neg = '';
+ if (num < 0) {
+ neg = '-';
+ num = -num;
+ }
+ num = '' + num;
+ while(num.length < digits) num = '0' + num;
+ if (trim)
+ num = num.substr(num.length - digits);
+ return neg + num;
+ }
+
+
+ /**
+ * @ngdoc object
+ * @name angular.mock.TzDate
+ * @description
+ *
+ * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`.
+ *
+ * Mock of the Date type which has its timezone specified via constructor arg.
+ *
+ * The main purpose is to create Date-like instances with timezone fixed to the specified timezone
+ * offset, so that we can test code that depends on local timezone settings without dependency on
+ * the time zone settings of the machine where the code is running.
+ *
+ * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored)
+ * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC*
+ *
+ * @example
+ * !!!! WARNING !!!!!
+ * This is not a complete Date object so only methods that were implemented can be called safely.
+ * To make matters worse, TzDate instances inherit stuff from Date via a prototype.
+ *
+ * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is
+ * incomplete we might be missing some non-standard methods. This can result in errors like:
+ * "Date.prototype.foo called on incompatible Object".
+ *
+ * <pre>
+ * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z');
+ * newYearInBratislava.getTimezoneOffset() => -60;
+ * newYearInBratislava.getFullYear() => 2010;
+ * newYearInBratislava.getMonth() => 0;
+ * newYearInBratislava.getDate() => 1;
+ * newYearInBratislava.getHours() => 0;
+ * newYearInBratislava.getMinutes() => 0;
+ * newYearInBratislava.getSeconds() => 0;
+ * </pre>
+ *
+ */
+ angular.mock.TzDate = function (offset, timestamp) {
+ var self = new Date(0);
+ if (angular.isString(timestamp)) {
+ var tsStr = timestamp;
+
+ self.origDate = jsonStringToDate(timestamp);
+
+ timestamp = self.origDate.getTime();
+ if (isNaN(timestamp))
+ throw {
+ name: "Illegal Argument",
+ message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
+ };
+ } else {
+ self.origDate = new Date(timestamp);
+ }
+
+ var localOffset = new Date(timestamp).getTimezoneOffset();
+ self.offsetDiff = localOffset*60*1000 - offset*1000*60*60;
+ self.date = new Date(timestamp + self.offsetDiff);
+
+ self.getTime = function() {
+ return self.date.getTime() - self.offsetDiff;
+ };
+
+ self.toLocaleDateString = function() {
+ return self.date.toLocaleDateString();
+ };
+
+ self.getFullYear = function() {
+ return self.date.getFullYear();
+ };
+
+ self.getMonth = function() {
+ return self.date.getMonth();
+ };
+
+ self.getDate = function() {
+ return self.date.getDate();
+ };
+
+ self.getHours = function() {
+ return self.date.getHours();
+ };
+
+ self.getMinutes = function() {
+ return self.date.getMinutes();
+ };
+
+ self.getSeconds = function() {
+ return self.date.getSeconds();
+ };
+
+ self.getMilliseconds = function() {
+ return self.date.getMilliseconds();
+ };
+
+ self.getTimezoneOffset = function() {
+ return offset * 60;
+ };
+
+ self.getUTCFullYear = function() {
+ return self.origDate.getUTCFullYear();
+ };
+
+ self.getUTCMonth = function() {
+ return self.origDate.getUTCMonth();
+ };
+
+ self.getUTCDate = function() {
+ return self.origDate.getUTCDate();
+ };
+
+ self.getUTCHours = function() {
+ return self.origDate.getUTCHours();
+ };
+
+ self.getUTCMinutes = function() {
+ return self.origDate.getUTCMinutes();
+ };
+
+ self.getUTCSeconds = function() {
+ return self.origDate.getUTCSeconds();
+ };
+
+ self.getUTCMilliseconds = function() {
+ return self.origDate.getUTCMilliseconds();
+ };
+
+ self.getDay = function() {
+ return self.date.getDay();
+ };
+
+ // provide this method only on browsers that already have it
+ if (self.toISOString) {
+ self.toISOString = function() {
+ return padNumber(self.origDate.getUTCFullYear(), 4) + '-' +
+ padNumber(self.origDate.getUTCMonth() + 1, 2) + '-' +
+ padNumber(self.origDate.getUTCDate(), 2) + 'T' +
+ padNumber(self.origDate.getUTCHours(), 2) + ':' +
+ padNumber(self.origDate.getUTCMinutes(), 2) + ':' +
+ padNumber(self.origDate.getUTCSeconds(), 2) + '.' +
+ padNumber(self.origDate.getUTCMilliseconds(), 3) + 'Z'
+ }
+ }
+
+ //hide all methods not implemented in this mock that the Date prototype exposes
+ var unimplementedMethods = ['getUTCDay',
+ 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds',
+ 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear',
+ 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds',
+ 'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString',
+ 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf'];
+
+ angular.forEach(unimplementedMethods, function(methodName) {
+ self[methodName] = function() {
+ throw Error("Method '" + methodName + "' is not implemented in the TzDate mock");
+ };
+ });
+
+ return self;
+ };
+
+ //make "tzDateInstance instanceof Date" return true
+ angular.mock.TzDate.prototype = Date.prototype;
+})();
+
+/**
+ * @ngdoc function
+ * @name angular.mock.createMockWindow
+ * @description
+ *
+ * This function creates a mock window object useful for controlling access ot setTimeout, but mocking out
+ * sufficient window's properties to allow Angular to execute.
+ *
+ * @example
+ *
+ * <pre>
+ beforeEach(module(function($provide) {
+ $provide.value('$window', window = angular.mock.createMockWindow());
+ }));
+
+ it('should do something', inject(function($window) {
+ var val = null;
+ $window.setTimeout(function() { val = 123; }, 10);
+ expect(val).toEqual(null);
+ window.setTimeout.expect(10).process();
+ expect(val).toEqual(123);
+ });
+ * </pre>
+ *
+ */
+angular.mock.createMockWindow = function() {
+ var mockWindow = {};
+ var setTimeoutQueue = [];
+
+ mockWindow.document = window.document;
+ mockWindow.getComputedStyle = angular.bind(window, window.getComputedStyle);
+ mockWindow.scrollTo = angular.bind(window, window.scrollTo);
+ mockWindow.navigator = window.navigator;
+ mockWindow.setTimeout = function(fn, delay) {
+ setTimeoutQueue.push({fn: fn, delay: delay});
+ };
+ mockWindow.setTimeout.queue = setTimeoutQueue;
+ mockWindow.setTimeout.expect = function(delay) {
+ if (setTimeoutQueue.length > 0) {
+ return {
+ process: function() {
+ var tick = setTimeoutQueue.shift();
+ expect(tick.delay).toEqual(delay);
+ tick.fn();
+ }
+ };
+ } else {
+ expect('SetTimoutQueue empty. Expecting delay of ').toEqual(delay);
+ }
+ };
+
+ return mockWindow;
+};
+
+/**
+ * @ngdoc function
+ * @name angular.mock.dump
+ * @description
+ *
+ * *NOTE*: this is not an injectable instance, just a globally available function.
+ *
+ * Method for serializing common angular objects (scope, elements, etc..) into strings, useful for debugging.
+ *
+ * This method is also available on window, where it can be used to display objects on debug console.
+ *
+ * @param {*} object - any object to turn into string.
+ * @return {string} a serialized string of the argument
+ */
+angular.mock.dump = function(object) {
+ return serialize(object);
+
+ function serialize(object) {
+ var out;
+
+ if (angular.isElement(object)) {
+ object = angular.element(object);
+ out = angular.element('<div></div>');
+ angular.forEach(object, function(element) {
+ out.append(angular.element(element).clone());
+ });
+ out = out.html();
+ } else if (angular.isArray(object)) {
+ out = [];
+ angular.forEach(object, function(o) {
+ out.push(serialize(o));
+ });
+ out = '[ ' + out.join(', ') + ' ]';
+ } else if (angular.isObject(object)) {
+ if (angular.isFunction(object.$eval) && angular.isFunction(object.$apply)) {
+ out = serializeScope(object);
+ } else if (object instanceof Error) {
+ out = object.stack || ('' + object.name + ': ' + object.message);
+ } else {
+ out = angular.toJson(object, true);
+ }
+ } else {
+ out = String(object);
+ }
+
+ return out;
+ }
+
+ function serializeScope(scope, offset) {
+ offset = offset || ' ';
+ var log = [offset + 'Scope(' + scope.$id + '): {'];
+ for ( var key in scope ) {
+ if (scope.hasOwnProperty(key) && !key.match(/^(\$|this)/)) {
+ log.push(' ' + key + ': ' + angular.toJson(scope[key]));
+ }
+ }
+ var child = scope.$$childHead;
+ while(child) {
+ log.push(serializeScope(child, offset + ' '));
+ child = child.$$nextSibling;
+ }
+ log.push('}');
+ return log.join('\n' + offset);
+ }
+};
+
+/**
+ * @ngdoc object
+ * @name ngMock.$httpBackend
+ * @description
+ * Fake HTTP backend implementation suitable for unit testing applications that use the
+ * {@link ng.$http $http service}.
+ *
+ * *Note*: For fake HTTP backend implementation suitable for end-to-end testing or backend-less
+ * development please see {@link ngMockE2E.$httpBackend e2e $httpBackend mock}.
+ *
+ * During unit testing, we want our unit tests to run quickly and have no external dependencies so
+ * we don’t want to send {@link https://developer.mozilla.org/en/xmlhttprequest XHR} or
+ * {@link http://en.wikipedia.org/wiki/JSONP JSONP} requests to a real server. All we really need is
+ * to verify whether a certain request has been sent or not, or alternatively just let the
+ * application make requests, respond with pre-trained responses and assert that the end result is
+ * what we expect it to be.
+ *
+ * This mock implementation can be used to respond with static or dynamic responses via the
+ * `expect` and `when` apis and their shortcuts (`expectGET`, `whenPOST`, etc).
+ *
+ * When an Angular application needs some data from a server, it calls the $http service, which
+ * sends the request to a real server using $httpBackend service. With dependency injection, it is
+ * easy to inject $httpBackend mock (which has the same API as $httpBackend) and use it to verify
+ * the requests and respond with some testing data without sending a request to real server.
+ *
+ * There are two ways to specify what test data should be returned as http responses by the mock
+ * backend when the code under test makes http requests:
+ *
+ * - `$httpBackend.expect` - specifies a request expectation
+ * - `$httpBackend.when` - specifies a backend definition
+ *
+ *
+ * # Request Expectations vs Backend Definitions
+ *
+ * Request expectations provide a way to make assertions about requests made by the application and
+ * to define responses for those requests. The test will fail if the expected requests are not made
+ * or they are made in the wrong order.
+ *
+ * Backend definitions allow you to define a fake backend for your application which doesn't assert
+ * if a particular request was made or not, it just returns a trained response if a request is made.
+ * The test will pass whether or not the request gets made during testing.
+ *
+ *
+ * <table class="table">
+ * <tr><th width="220px"></th><th>Request expectations</th><th>Backend definitions</th></tr>
+ * <tr>
+ * <th>Syntax</th>
+ * <td>.expect(...).respond(...)</td>
+ * <td>.when(...).respond(...)</td>
+ * </tr>
+ * <tr>
+ * <th>Typical usage</th>
+ * <td>strict unit tests</td>
+ * <td>loose (black-box) unit testing</td>
+ * </tr>
+ * <tr>
+ * <th>Fulfills multiple requests</th>
+ * <td>NO</td>
+ * <td>YES</td>
+ * </tr>
+ * <tr>
+ * <th>Order of requests matters</th>
+ * <td>YES</td>
+ * <td>NO</td>
+ * </tr>
+ * <tr>
+ * <th>Request required</th>
+ * <td>YES</td>
+ * <td>NO</td>
+ * </tr>
+ * <tr>
+ * <th>Response required</th>
+ * <td>optional (see below)</td>
+ * <td>YES</td>
+ * </tr>
+ * </table>
+ *
+ * In cases where both backend definitions and request expectations are specified during unit
+ * testing, the request expectations are evaluated first.
+ *
+ * If a request expectation has no response specified, the algorithm will search your backend
+ * definitions for an appropriate response.
+ *
+ * If a request didn't match any expectation or if the expectation doesn't have the response
+ * defined, the backend definitions are evaluated in sequential order to see if any of them match
+ * the request. The response from the first matched definition is returned.
+ *
+ *
+ * # Flushing HTTP requests
+ *
+ * The $httpBackend used in production, always responds to requests with responses asynchronously.
+ * If we preserved this behavior in unit testing, we'd have to create async unit tests, which are
+ * hard to write, follow and maintain. At the same time the testing mock, can't respond
+ * synchronously because that would change the execution of the code under test. For this reason the
+ * mock $httpBackend has a `flush()` method, which allows the test to explicitly flush pending
+ * requests and thus preserving the async api of the backend, while allowing the test to execute
+ * synchronously.
+ *
+ *
+ * # Unit testing with mock $httpBackend
+ *
+ * <pre>
+ // controller
+ function MyController($scope, $http) {
+ $http.get('/auth.py').success(function(data) {
+ $scope.user = data;
+ });
+
+ this.saveMessage = function(message) {
+ $scope.status = 'Saving...';
+ $http.post('/add-msg.py', message).success(function(response) {
+ $scope.status = '';
+ }).error(function() {
+ $scope.status = 'ERROR!';
+ });
+ };
+ }
+
+ // testing controller
+ var $httpBackend;
+
+ beforeEach(inject(function($injector) {
+ $httpBackend = $injector.get('$httpBackend');
+
+ // backend definition common for all tests
+ $httpBackend.when('GET', '/auth.py').respond({userId: 'userX'}, {'A-Token': 'xxx'});
+ }));
+
+
+ afterEach(function() {
+ $httpBackend.verifyNoOutstandingExpectation();
+ $httpBackend.verifyNoOutstandingRequest();
+ });
+
+
+ it('should fetch authentication token', function() {
+ $httpBackend.expectGET('/auth.py');
+ var controller = scope.$new(MyController);
+ $httpBackend.flush();
+ });
+
+
+ it('should send msg to server', function() {
+ // now you don’t care about the authentication, but
+ // the controller will still send the request and
+ // $httpBackend will respond without you having to
+ // specify the expectation and response for this request
+ $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, '');
+
+ var controller = scope.$new(MyController);
+ $httpBackend.flush();
+ controller.saveMessage('message content');
+ expect(controller.status).toBe('Saving...');
+ $httpBackend.flush();
+ expect(controller.status).toBe('');
+ });
+
+
+ it('should send auth header', function() {
+ $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
+ // check if the header was send, if it wasn't the expectation won't
+ // match the request and the test will fail
+ return headers['Authorization'] == 'xxx';
+ }).respond(201, '');
+
+ var controller = scope.$new(MyController);
+ controller.saveMessage('whatever');
+ $httpBackend.flush();
+ });
+ </pre>
+ */
+angular.mock.$HttpBackendProvider = function() {
+ this.$get = ['$rootScope', createHttpBackendMock];
+};
+
+/**
+ * General factory function for $httpBackend mock.
+ * Returns instance for unit testing (when no arguments specified):
+ * - passing through is disabled
+ * - auto flushing is disabled
+ *
+ * Returns instance for e2e testing (when `$delegate` and `$browser` specified):
+ * - passing through (delegating request to real backend) is enabled
+ * - auto flushing is enabled
+ *
+ * @param {Object=} $delegate Real $httpBackend instance (allow passing through if specified)
+ * @param {Object=} $browser Auto-flushing enabled if specified
+ * @return {Object} Instance of $httpBackend mock
+ */
+function createHttpBackendMock($rootScope, $delegate, $browser) {
+ var definitions = [],
+ expectations = [],
+ responses = [],
+ responsesPush = angular.bind(responses, responses.push);
+
+ function createResponse(status, data, headers) {
+ if (angular.isFunction(status)) return status;
+
+ return function() {
+ return angular.isNumber(status)
+ ? [status, data, headers]
+ : [200, status, data];
+ };
+ }
+
+ // TODO(vojta): change params to: method, url, data, headers, callback
+ function $httpBackend(method, url, data, callback, headers, timeout) {
+ var xhr = new MockXhr(),
+ expectation = expectations[0],
+ wasExpected = false;
+
+ function prettyPrint(data) {
+ return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp)
+ ? data
+ : angular.toJson(data);
+ }
+
+ function wrapResponse(wrapped) {
+ if (!$browser && timeout && timeout.then) timeout.then(handleTimeout);
+
+ return handleResponse;
+
+ function handleResponse() {
+ var response = wrapped.response(method, url, data, headers);
+ xhr.$$respHeaders = response[2];
+ callback(response[0], response[1], xhr.getAllResponseHeaders());
+ }
+
+ function handleTimeout() {
+ for (var i = 0, ii = responses.length; i < ii; i++) {
+ if (responses[i] === handleResponse) {
+ responses.splice(i, 1);
+ callback(-1, undefined, '');
+ break;
+ }
+ }
+ }
+ }
+
+ if (expectation && expectation.match(method, url)) {
+ if (!expectation.matchData(data))
+ throw Error('Expected ' + expectation + ' with different data\n' +
+ 'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data);
+
+ if (!expectation.matchHeaders(headers))
+ throw Error('Expected ' + expectation + ' with different headers\n' +
+ 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
+ prettyPrint(headers));
+
+ expectations.shift();
+
+ if (expectation.response) {
+ responses.push(wrapResponse(expectation));
+ return;
+ }
+ wasExpected = true;
+ }
+
+ var i = -1, definition;
+ while ((definition = definitions[++i])) {
+ if (definition.match(method, url, data, headers || {})) {
+ if (definition.response) {
+ // if $browser specified, we do auto flush all requests
+ ($browser ? $browser.defer : responsesPush)(wrapResponse(definition));
+ } else if (definition.passThrough) {
+ $delegate(method, url, data, callback, headers, timeout);
+ } else throw Error('No response defined !');
+ return;
+ }
+ }
+ throw wasExpected ?
+ Error('No response defined !') :
+ Error('Unexpected request: ' + method + ' ' + url + '\n' +
+ (expectation ? 'Expected ' + expectation : 'No more request expected'));
+ }
+
+ /**
+ * @ngdoc method
+ * @name ngMock.$httpBackend#when
+ * @methodOf ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition.
+ *
+ * @param {string} method HTTP method.
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
+ * object and returns true if the headers match the current definition.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ *
+ * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
+ * – The respond method takes a set of static data to be returned or a function that can return
+ * an array containing response status (number), response data (string) and response headers
+ * (Object).
+ */
+ $httpBackend.when = function(method, url, data, headers) {
+ var definition = new MockHttpExpectation(method, url, data, headers),
+ chain = {
+ respond: function(status, data, headers) {
+ definition.response = createResponse(status, data, headers);
+ }
+ };
+
+ if ($browser) {
+ chain.passThrough = function() {
+ definition.passThrough = true;
+ };
+ }
+
+ definitions.push(definition);
+ return chain;
+ };
+
+ /**
+ * @ngdoc method
+ * @name ngMock.$httpBackend#whenGET
+ * @methodOf ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition for GET requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name ngMock.$httpBackend#whenHEAD
+ * @methodOf ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition for HEAD requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name ngMock.$httpBackend#whenDELETE
+ * @methodOf ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition for DELETE requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name ngMock.$httpBackend#whenPOST
+ * @methodOf ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition for POST requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name ngMock.$httpBackend#whenPUT
+ * @methodOf ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition for PUT requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name ngMock.$httpBackend#whenJSONP
+ * @methodOf ngMock.$httpBackend
+ * @description
+ * Creates a new backend definition for JSONP requests. For more info see `when()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ */
+ createShortMethods('when');
+
+
+ /**
+ * @ngdoc method
+ * @name ngMock.$httpBackend#expect
+ * @methodOf ngMock.$httpBackend
+ * @description
+ * Creates a new request expectation.
+ *
+ * @param {string} method HTTP method.
+ * @param {string|RegExp} url HTTP url.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
+ * object and returns true if the headers match the current expectation.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled.
+ *
+ * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
+ * – The respond method takes a set of static data to be returned or a function that can return
+ * an array containing response status (number), response data (string) and response headers
+ * (Object).
+ */
+ $httpBackend.expect = function(method, url, data, headers) {
+ var expectation = new MockHttpExpectation(method, url, data, headers);
+ expectations.push(expectation);
+ return {
+ respond: function(status, data, headers) {
+ expectation.response = createResponse(status, data, headers);
+ }
+ };
+ };
+
+
+ /**
+ * @ngdoc method
+ * @name ngMock.$httpBackend#expectGET
+ * @methodOf ngMock.$httpBackend
+ * @description
+ * Creates a new request expectation for GET requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp} url HTTP url.
+ * @param {Object=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled. See #expect for more info.
+ */
+
+ /**
+ * @ngdoc method