/** * @license AngularJS v1.8.2 * (c) 2010-2020 Google LLC. http://angularjs.org * License: MIT */ (function(window, angular) {'use strict'; /* global shallowCopy: true */ /** * Creates a shallow copy of an object, an array or a primitive. * * Assumes that there are no proto properties for objects. */ function shallowCopy(src, dst) { if (isArray(src)) { dst = dst || []; for (var i = 0, ii = src.length; i < ii; i++) { dst[i] = src[i]; } } else if (isObject(src)) { dst = dst || {}; for (var key in src) { if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) { dst[key] = src[key]; } } } return dst || src; } /* global routeToRegExp: true */ /** * @param {string} path - The path to parse. (It is assumed to have query and hash stripped off.) * @param {Object} opts - Options. * @return {Object} - An object containing an array of path parameter names (`keys`) and a regular * expression (`regexp`) that can be used to identify a matching URL and extract the path * parameter values. * * @description * Parses the given path, extracting path parameter names and a regular expression to match URLs. * * Originally inspired by `pathRexp` in `visionmedia/express/lib/utils.js`. */ function routeToRegExp(path, opts) { var keys = []; var pattern = path .replace(/([().])/g, '\\$1') .replace(/(\/)?:(\w+)(\*\?|[?*])?/g, function(_, slash, key, option) { var optional = option === '?' || option === '*?'; var star = option === '*' || option === '*?'; keys.push({name: key, optional: optional}); slash = slash || ''; return ( (optional ? '(?:' + slash : slash + '(?:') + (star ? '(.+?)' : '([^/]+)') + (optional ? '?)?' : ')') ); }) .replace(/([/$*])/g, '\\$1'); if (opts.ignoreTrailingSlashes) { pattern = pattern.replace(/\/+$/, '') + '/*'; } return { keys: keys, regexp: new RegExp( '^' + pattern + '(?:[?#]|$)', opts.caseInsensitiveMatch ? 'i' : '' ) }; } /* global routeToRegExp: false */ /* global shallowCopy: false */ // `isArray` and `isObject` are necessary for `shallowCopy()` (included via `src/shallowCopy.js`). // They are initialized inside the `$RouteProvider`, to ensure `window.angular` is available. var isArray; var isObject; var isDefined; var noop; /** * @ngdoc module * @name ngRoute * @description * * The `ngRoute` module provides routing and deeplinking services and directives for AngularJS apps. * * ## Example * See {@link ngRoute.$route#examples $route} for an example of configuring and using `ngRoute`. * */ /* global -ngRouteModule */ var ngRouteModule = angular. module('ngRoute', []). info({ angularVersion: '1.8.2' }). provider('$route', $RouteProvider). // Ensure `$route` will be instantiated in time to capture the initial `$locationChangeSuccess` // event (unless explicitly disabled). This is necessary in case `ngView` is included in an // asynchronously loaded template. run(instantiateRoute); var $routeMinErr = angular.$$minErr('ngRoute'); var isEagerInstantiationEnabled; /** * @ngdoc provider * @name $routeProvider * @this * * @description * * Used for configuring routes. * * ## Example * See {@link ngRoute.$route#examples $route} for an example of configuring and using `ngRoute`. * * ## Dependencies * Requires the {@link ngRoute `ngRoute`} module to be installed. */ function $RouteProvider() { isArray = angular.isArray; isObject = angular.isObject; isDefined = angular.isDefined; noop = angular.noop; function inherit(parent, extra) { return angular.extend(Object.create(parent), extra); } var routes = {}; /** * @ngdoc method * @name $routeProvider#when * * @param {string} path Route path (matched against `$location.path`). If `$location.path` * contains redundant trailing slash or is missing one, the route will still match and the * `$location.path` will be updated to add or drop the trailing slash to exactly match the * route definition. * * * `path` can contain named groups starting with a colon: e.g. `:name`. All characters up * to the next slash are matched and stored in `$routeParams` under the given `name` * when the route matches. * * `path` can contain named groups starting with a colon and ending with a star: * e.g.`:name*`. All characters are eagerly stored in `$routeParams` under the given `name` * when the route matches. * * `path` can contain optional named groups with a question mark: e.g.`:name?`. * * For example, routes like `/color/:color/largecode/:largecode*\/edit` will match * `/color/brown/largecode/code/with/slashes/edit` and extract: * * * `color: brown` * * `largecode: code/with/slashes`. * * * @param {Object} route Mapping information to be assigned to `$route.current` on route * match. * * Object properties: * * - `controller` – `{(string|Function)=}` – Controller fn that should be associated with * newly created scope or the name of a {@link angular.Module#controller registered * controller} if passed as a string. * - `controllerAs` – `{string=}` – An identifier name for a reference to the controller. * If present, the controller will be published to scope under the `controllerAs` name. * - `template` – `{(string|Function)=}` – html template as a string or a function that * returns an html template as a string which should be used by {@link * ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives. * This property takes precedence over `templateUrl`. * * If `template` is a function, it will be called with the following parameters: * * - `{Array.}` - route parameters extracted from the current * `$location.path()` by applying the current route * * One of `template` or `templateUrl` is required. * * - `templateUrl` – `{(string|Function)=}` – path or function that returns a path to an html * template that should be used by {@link ngRoute.directive:ngView ngView}. * * If `templateUrl` is a function, it will be called with the following parameters: * * - `{Array.}` - route parameters extracted from the current * `$location.path()` by applying the current route * * One of `templateUrl` or `template` is required. * * - `resolve` - `{Object.=}` - An optional map of dependencies which should * be injected into the controller. If any of these dependencies are promises, the router * will wait for them all to be resolved or one to be rejected before the controller is * instantiated. * If all the promises are resolved successfully, the values of the resolved promises are * injected and {@link ngRoute.$route#$routeChangeSuccess $routeChangeSuccess} event is * fired. If any of the promises are rejected the * {@link ngRoute.$route#$routeChangeError $routeChangeError} event is fired. * For easier access to the resolved dependencies from the template, the `resolve` map will * be available on the scope of the route, under `$resolve` (by default) or a custom name * specified by the `resolveAs` property (see below). This can be particularly useful, when * working with {@link angular.Module#component components} as route templates.
*
* **Note:** If your scope already contains a property with this name, it will be hidden * or overwritten. Make sure, you specify an appropriate name for this property, that * does not collide with other properties on the scope. *
* The map object is: * * - `key` – `{string}`: a name of a dependency to be injected into the controller. * - `factory` - `{string|Function}`: If `string` then it is an alias for a service. * Otherwise if function, then it is {@link auto.$injector#invoke injected} * and the return value is treated as the dependency. If the result is a promise, it is * resolved before its value is injected into the controller. Be aware that * `ngRoute.$routeParams` will still refer to the previous route within these resolve * functions. Use `$route.current.params` to access the new route parameters, instead. * * - `resolveAs` - `{string=}` - The name under which the `resolve` map will be available on * the scope of the route. If omitted, defaults to `$resolve`. * * - `redirectTo` – `{(string|Function)=}` – value to update * {@link ng.$location $location} path with and trigger route redirection. * * If `redirectTo` is a function, it will be called with the following parameters: * * - `{Object.}` - route parameters extracted from the current * `$location.path()` by applying the current route templateUrl. * - `{string}` - current `$location.path()` * - `{Object}` - current `$location.search()` * * The custom `redirectTo` function is expected to return a string which will be used * to update `$location.url()`. If the function throws an error, no further processing will * take place and the {@link ngRoute.$route#$routeChangeError $routeChangeError} event will * be fired. * * Routes that specify `redirectTo` will not have their controllers, template functions * or resolves called, the `$location` will be changed to the redirect url and route * processing will stop. The exception to this is if the `redirectTo` is a function that * returns `undefined`. In this case the route transition occurs as though there was no * redirection. * * - `resolveRedirectTo` – `{Function=}` – a function that will (eventually) return the value * to update {@link ng.$location $location} URL with and trigger route redirection. In * contrast to `redirectTo`, dependencies can be injected into `resolveRedirectTo` and the * return value can be either a string or a promise that will be resolved to a string. * * Similar to `redirectTo`, if the return value is `undefined` (or a promise that gets * resolved to `undefined`), no redirection takes place and the route transition occurs as * though there was no redirection. * * If the function throws an error or the returned promise gets rejected, no further * processing will take place and the * {@link ngRoute.$route#$routeChangeError $routeChangeError} event will be fired. * * `redirectTo` takes precedence over `resolveRedirectTo`, so specifying both on the same * route definition, will cause the latter to be ignored. * * - `[reloadOnUrl=true]` - `{boolean=}` - reload route when any part of the URL changes * (including the path) even if the new URL maps to the same route. * * If the option is set to `false` and the URL in the browser changes, but the new URL maps * to the same route, then a `$routeUpdate` event is broadcasted on the root scope (without * reloading the route). * * - `[reloadOnSearch=true]` - `{boolean=}` - reload route when only `$location.search()` * or `$location.hash()` changes. * * If the option is set to `false` and the URL in the browser changes, then a `$routeUpdate` * event is broadcasted on the root scope (without reloading the route). * *
* **Note:** This option has no effect if `reloadOnUrl` is set to `false`. *
* * - `[caseInsensitiveMatch=false]` - `{boolean=}` - match routes without being case sensitive * * If the option is set to `true`, then the particular route can be matched without being * case sensitive * * @returns {Object} self * * @description * Adds a new route definition to the `$route` service. */ this.when = function(path, route) { //copy original route object to preserve params inherited from proto chain var routeCopy = shallowCopy(route); if (angular.isUndefined(routeCopy.reloadOnUrl)) { routeCopy.reloadOnUrl = true; } if (angular.isUndefined(routeCopy.reloadOnSearch)) { routeCopy.reloadOnSearch = true; } if (angular.isUndefined(routeCopy.caseInsensitiveMatch)) { routeCopy.caseInsensitiveMatch = this.caseInsensitiveMatch; } routes[path] = angular.extend( routeCopy, {originalPath: path}, path && routeToRegExp(path, routeCopy) ); // create redirection for trailing slashes if (path) { var redirectPath = (path[path.length - 1] === '/') ? path.substr(0, path.length - 1) : path + '/'; routes[redirectPath] = angular.extend( {originalPath: path, redirectTo: path}, routeToRegExp(redirectPath, routeCopy) ); } return this; }; /** * @ngdoc property * @name $routeProvider#caseInsensitiveMatch * @description * * A boolean property indicating if routes defined * using this provider should be matched using a case insensitive * algorithm. Defaults to `false`. */ this.caseInsensitiveMatch = false; /** * @ngdoc method * @name $routeProvider#otherwise * * @description * Sets route definition that will be used on route change when no other route definition * is matched. * * @param {Object|string} params Mapping information to be assigned to `$route.current`. * If called with a string, the value maps to `redirectTo`. * @returns {Object} self */ this.otherwise = function(params) { if (typeof params === 'string') { params = {redirectTo: params}; } this.when(null, params); return this; }; /** * @ngdoc method * @name $routeProvider#eagerInstantiationEnabled * @kind function * * @description * Call this method as a setter to enable/disable eager instantiation of the * {@link ngRoute.$route $route} service upon application bootstrap. You can also call it as a * getter (i.e. without any arguments) to get the current value of the * `eagerInstantiationEnabled` flag. * * Instantiating `$route` early is necessary for capturing the initial * {@link ng.$location#$locationChangeStart $locationChangeStart} event and navigating to the * appropriate route. Usually, `$route` is instantiated in time by the * {@link ngRoute.ngView ngView} directive. Yet, in cases where `ngView` is included in an * asynchronously loaded template (e.g. in another directive's template), the directive factory * might not be called soon enough for `$route` to be instantiated _before_ the initial * `$locationChangeSuccess` event is fired. Eager instantiation ensures that `$route` is always * instantiated in time, regardless of when `ngView` will be loaded. * * The default value is true. * * **Note**:
* You may want to disable the default behavior when unit-testing modules that depend on * `ngRoute`, in order to avoid an unexpected request for the default route's template. * * @param {boolean=} enabled - If provided, update the internal `eagerInstantiationEnabled` flag. * * @returns {*} The current value of the `eagerInstantiationEnabled` flag if used as a getter or * itself (for chaining) if used as a setter. */ isEagerInstantiationEnabled = true; this.eagerInstantiationEnabled = function eagerInstantiationEnabled(enabled) { if (isDefined(enabled)) { isEagerInstantiationEnabled = enabled; return this; } return isEagerInstantiationEnabled; }; this.$get = ['$rootScope', '$location', '$routeParams', '$q', '$injector', '$templateRequest', '$sce', '$browser', function($rootScope, $location, $routeParams, $q, $injector, $templateRequest, $sce, $browser) { /** * @ngdoc service * @name $route * @requires $location * @requires $routeParams * * @property {Object} current Reference to the current route definition. * The route definition contains: * * - `controller`: The controller constructor as defined in the route definition. * - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for * controller instantiation. The `locals` contain * the resolved values of the `resolve` map. Additionally the `locals` also contain: * * - `$scope` - The current route scope. * - `$template` - The current route template HTML. * * The `locals` will be assigned to the route scope's `$resolve` property. You can override * the property name, using `resolveAs` in the route definition. See * {@link ngRoute.$routeProvider $routeProvider} for more info. * * @property {Object} routes Object with all route configuration Objects as its properties. * * @description * `$route` is used for deep-linking URLs to controllers and views (HTML partials). * It watches `$location.url()` and tries to map the path to an existing route definition. * * Requires the {@link ngRoute `ngRoute`} module to be installed. * * You can define routes through {@link ngRoute.$routeProvider $routeProvider}'s API. * * The `$route` service is typically used in conjunction with the * {@link ngRoute.directive:ngView `ngView`} directive and the * {@link ngRoute.$routeParams `$routeParams`} service. * * @example * This example shows how changing the URL hash causes the `$route` to match a route against the * URL, and the `ngView` pulls in the partial. * * * *
* Choose: * Moby | * Moby: Ch1 | * Gatsby | * Gatsby: Ch4 | * Scarlet Letter
* *
* *
* *
$location.path() = {{$location.path()}}
*
$route.current.templateUrl = {{$route.current.templateUrl}}
*
$route.current.params = {{$route.current.params}}
*
$route.current.scope.name = {{$route.current.scope.name}}
*
$routeParams = {{$routeParams}}
*
*
* * * controller: {{name}}
* Book Id: {{params.bookId}}
*
* * * controller: {{name}}
* Book Id: {{params.bookId}}
* Chapter Id: {{params.chapterId}} *
* * * angular.module('ngRouteExample', ['ngRoute']) * * .controller('MainController', function($scope, $route, $routeParams, $location) { * $scope.$route = $route; * $scope.$location = $location; * $scope.$routeParams = $routeParams; * }) * * .controller('BookController', function($scope, $routeParams) { * $scope.name = 'BookController'; * $scope.params = $routeParams; * }) * * .controller('ChapterController', function($scope, $routeParams) { * $scope.name = 'ChapterController'; * $scope.params = $routeParams; * }) * * .config(function($routeProvider, $locationProvider) { * $routeProvider * .when('/Book/:bookId', { * templateUrl: 'book.html', * controller: 'BookController', * resolve: { * // I will cause a 1 second delay * delay: function($q, $timeout) { * var delay = $q.defer(); * $timeout(delay.resolve, 1000); * return delay.promise; * } * } * }) * .when('/Book/:bookId/ch/:chapterId', { * templateUrl: 'chapter.html', * controller: 'ChapterController' * }); * * // configure html5 to get links working on jsfiddle * $locationProvider.html5Mode(true); * }); * * * * * it('should load and compile correct template', function() { * element(by.linkText('Moby: Ch1')).click(); * var content = element(by.css('[ng-view]')).getText(); * expect(content).toMatch(/controller: ChapterController/); * expect(content).toMatch(/Book Id: Moby/); * expect(content).toMatch(/Chapter Id: 1/); * * element(by.partialLinkText('Scarlet')).click(); * * content = element(by.css('[ng-view]')).getText(); * expect(content).toMatch(/controller: BookController/); * expect(content).toMatch(/Book Id: Scarlet/); * }); * *
*/ /** * @ngdoc event * @name $route#$routeChangeStart * @eventType broadcast on root scope * @description * Broadcasted before a route change. At this point the route services starts * resolving all of the dependencies needed for the route change to occur. * Typically this involves fetching the view template as well as any dependencies * defined in `resolve` route property. Once all of the dependencies are resolved * `$routeChangeSuccess` is fired. * * The route change (and the `$location` change that triggered it) can be prevented * by calling `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} * for more details about event object. * * @param {Object} angularEvent Synthetic event object. * @param {Route} next Future route information. * @param {Route} current Current route information. */ /** * @ngdoc event * @name $route#$routeChangeSuccess * @eventType broadcast on root scope * @description * Broadcasted after a route change has happened successfully. * The `resolve` dependencies are now available in the `current.locals` property. * * {@link ngRoute.directive:ngView ngView} listens for the directive * to instantiate the controller and render the view. * * @param {Object} angularEvent Synthetic event object. * @param {Route} current Current route information. * @param {Route|Undefined} previous Previous route information, or undefined if current is * first route entered. */ /** * @ngdoc event * @name $route#$routeChangeError * @eventType broadcast on root scope * @description * Broadcasted if a redirection function fails or any redirection or resolve promises are * rejected. * * @param {Object} angularEvent Synthetic event object * @param {Route} current Current route information. * @param {Route} previous Previous route information. * @param {Route} rejection The thrown error or the rejection reason of the promise. Usually * the rejection reason is the error that caused the promise to get rejected. */ /** * @ngdoc event * @name $route#$routeUpdate * @eventType broadcast on root scope * @description * Broadcasted if the same instance of a route (including template, controller instance, * resolved dependencies, etc.) is being reused. This can happen if either `reloadOnSearch` or * `reloadOnUrl` has been set to `false`. * * @param {Object} angularEvent Synthetic event object * @param {Route} current Current/previous route information. */ var forceReload = false, preparedRoute, preparedRouteIsUpdateOnly, $route = { routes: routes, /** * @ngdoc method * @name $route#reload * * @description * Causes `$route` service to reload the current route even if * {@link ng.$location $location} hasn't changed. * * As a result of that, {@link ngRoute.directive:ngView ngView} * creates new scope and reinstantiates the controller. */ reload: function() { forceReload = true; var fakeLocationEvent = { defaultPrevented: false, preventDefault: function fakePreventDefault() { this.defaultPrevented = true; forceReload = false; } }; $rootScope.$evalAsync(function() { prepareRoute(fakeLocationEvent); if (!fakeLocationEvent.defaultPrevented) commitRoute(); }); }, /** * @ngdoc method * @name $route#updateParams * * @description * Causes `$route` service to update the current URL, replacing * current route parameters with those specified in `newParams`. * Provided property names that match the route's path segment * definitions will be interpolated into the location's path, while * remaining properties will be treated as query params. * * @param {!Object} newParams mapping of URL parameter names to values */ updateParams: function(newParams) { if (this.current && this.current.$$route) { newParams = angular.extend({}, this.current.params, newParams); $location.path(interpolate(this.current.$$route.originalPath, newParams)); // interpolate modifies newParams, only query params are left $location.search(newParams); } else { throw $routeMinErr('norout', 'Tried updating route with no current route'); } } }; $rootScope.$on('$locationChangeStart', prepareRoute); $rootScope.$on('$locationChangeSuccess', commitRoute); return $route; ///////////////////////////////////////////////////// /** * @param on {string} current url * @param route {Object} route regexp to match the url against * @return {?Object} * * @description * Check if the route matches the current url. * * Inspired by match in * visionmedia/express/lib/router/router.js. */ function switchRouteMatcher(on, route) { var keys = route.keys, params = {}; if (!route.regexp) return null; var m = route.regexp.exec(on); if (!m) return null; for (var i = 1, len = m.length; i < len; ++i) { var key = keys[i - 1]; var val = m[i]; if (key && val) { params[key.name] = val; } } return params; } function prepareRoute($locationEvent) { var lastRoute = $route.current; preparedRoute = parseRoute(); preparedRouteIsUpdateOnly = isNavigationUpdateOnly(preparedRoute, lastRoute); if (!preparedRouteIsUpdateOnly && (lastRoute || preparedRoute)) { if ($rootScope.$broadcast('$routeChangeStart', preparedRoute, lastRoute).defaultPrevented) { if ($locationEvent) { $locationEvent.preventDefault(); } } } } function commitRoute() { var lastRoute = $route.current; var nextRoute = preparedRoute; if (preparedRouteIsUpdateOnly) { lastRoute.params = nextRoute.params; angular.copy(lastRoute.params, $routeParams); $rootScope.$broadcast('$routeUpdate', lastRoute); } else if (nextRoute || lastRoute) { forceReload = false; $route.current = nextRoute; var nextRoutePromise = $q.resolve(nextRoute); $browser.$$incOutstandingRequestCount('$route'); nextRoutePromise. then(getRedirectionData). then(handlePossibleRedirection). then(function(keepProcessingRoute) { return keepProcessingRoute && nextRoutePromise. then(resolveLocals). then(function(locals) { // after route change if (nextRoute === $route.current) { if (nextRoute) { nextRoute.locals = locals; angular.copy(nextRoute.params, $routeParams); } $rootScope.$broadcast('$routeChangeSuccess', nextRoute, lastRoute); } }); }).catch(function(error) { if (nextRoute === $route.current) { $rootScope.$broadcast('$routeChangeError', nextRoute, lastRoute, error); } }).finally(function() { // Because `commitRoute()` is called from a `$rootScope.$evalAsync` block (see // `$locationWatch`), this `$$completeOutstandingRequest()` call will not cause // `outstandingRequestCount` to hit zero. This is important in case we are redirecting // to a new route which also requires some asynchronous work. $browser.$$completeOutstandingRequest(noop, '$route'); }); } } function getRedirectionData(route) { var data = { route: route, hasRedirection: false }; if (route) { if (route.redirectTo) { if (angular.isString(route.redirectTo)) { data.path = interpolate(route.redirectTo, route.params); data.search = route.params; data.hasRedirection = true; } else { var oldPath = $location.path(); var oldSearch = $location.search(); var newUrl = route.redirectTo(route.pathParams, oldPath, oldSearch); if (angular.isDefined(newUrl)) { data.url = newUrl; data.hasRedirection = true; } } } else if (route.resolveRedirectTo) { return $q. resolve($injector.invoke(route.resolveRedirectTo)). then(function(newUrl) { if (angular.isDefined(newUrl)) { data.url = newUrl; data.hasRedirection = true; } return data; }); } } return data; } function handlePossibleRedirection(data) { var keepProcessingRoute = true; if (data.route !== $route.current) { keepProcessingRoute = false; } else if (data.hasRedirection) { var oldUrl = $location.url(); var newUrl = data.url; if (newUrl) { $location. url(newUrl). replace(); } else { newUrl = $location. path(data.path). search(data.search). replace(). url(); } if (newUrl !== oldUrl) { // Exit out and don't process current next value, // wait for next location change from redirect keepProcessingRoute = false; } } return keepProcessingRoute; } function resolveLocals(route) { if (route) { var locals = angular.extend({}, route.resolve); angular.forEach(locals, function(value, key) { locals[key] = angular.isString(value) ? $injector.get(value) : $injector.invoke(value, null, null, key); }); var template = getTemplateFor(route); if (angular.isDefined(template)) { locals['$template'] = template; } return $q.all(locals); } } function getTemplateFor(route) { var template, templateUrl; if (angular.isDefined(template = route.template)) { if (angular.isFunction(template)) { template = template(route.params); } } else if (angular.isDefined(templateUrl = route.templateUrl)) { if (angular.isFunction(templateUrl)) { templateUrl = templateUrl(route.params); } if (angular.isDefined(templateUrl)) { route.loadedTemplateUrl = $sce.valueOf(templateUrl); template = $templateRequest(templateUrl); } } return template; } /** * @returns {Object} the current active route, by matching it against the URL */ function parseRoute() { // Match a route var params, match; angular.forEach(routes, function(route, path) { if (!match && (params = switchRouteMatcher($location.path(), route))) { match = inherit(route, { params: angular.extend({}, $location.search(), params), pathParams: params}); match.$$route = route; } }); // No route matched; fallback to "otherwise" route return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}}); } /** * @param {Object} newRoute - The new route configuration (as returned by `parseRoute()`). * @param {Object} oldRoute - The previous route configuration (as returned by `parseRoute()`). * @returns {boolean} Whether this is an "update-only" navigation, i.e. the URL maps to the same * route and it can be reused (based on the config and the type of change). */ function isNavigationUpdateOnly(newRoute, oldRoute) { // IF this is not a forced reload return !forceReload // AND both `newRoute`/`oldRoute` are defined && newRoute && oldRoute // AND they map to the same Route Definition Object && (newRoute.$$route === oldRoute.$$route) // AND `reloadOnUrl` is disabled && (!newRoute.reloadOnUrl // OR `reloadOnSearch` is disabled || (!newRoute.reloadOnSearch // AND both routes have the same path params && angular.equals(newRoute.pathParams, oldRoute.pathParams) ) ); } /** * @returns {string} interpolation of the redirect path with the parameters */ function interpolate(string, params) { var result = []; angular.forEach((string || '').split(':'), function(segment, i) { if (i === 0) { result.push(segment); } else { var segmentMatch = segment.match(/(\w+)(?:[?*])?(.*)/); var key = segmentMatch[1]; result.push(params[key]); result.push(segmentMatch[2] || ''); delete params[key]; } }); return result.join(''); } }]; } instantiateRoute.$inject = ['$injector']; function instantiateRoute($injector) { if (isEagerInstantiationEnabled) { // Instantiate `$route` $injector.get('$route'); } } ngRouteModule.provider('$routeParams', $RouteParamsProvider); /** * @ngdoc service * @name $routeParams * @requires $route * @this * * @description * The `$routeParams` service allows you to retrieve the current set of route parameters. * * Requires the {@link ngRoute `ngRoute`} module to be installed. * * The route parameters are a combination of {@link ng.$location `$location`}'s * {@link ng.$location#search `search()`} and {@link ng.$location#path `path()`}. * The `path` parameters are extracted when the {@link ngRoute.$route `$route`} path is matched. * * In case of parameter name collision, `path` params take precedence over `search` params. * * The service guarantees that the identity of the `$routeParams` object will remain unchanged * (but its properties will likely change) even when a route change occurs. * * Note that the `$routeParams` are only updated *after* a route change completes successfully. * This means that you cannot rely on `$routeParams` being correct in route resolve functions. * Instead you can use `$route.current.params` to access the new route's parameters. * * @example * ```js * // Given: * // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby * // Route: /Chapter/:chapterId/Section/:sectionId * // * // Then * $routeParams ==> {chapterId:'1', sectionId:'2', search:'moby'} * ``` */ function $RouteParamsProvider() { this.$get = function() { return {}; }; } ngRouteModule.directive('ngView', ngViewFactory); ngRouteModule.directive('ngView', ngViewFillContentFactory); /** * @ngdoc directive * @name ngView * @restrict ECA * * @description * `ngView` is a directive that complements the {@link ngRoute.$route $route} service by * including the rendered template of the current route into the main layout (`index.html`) file. * Every time the current route changes, the included view changes with it according to the * configuration of the `$route` service. * * Requires the {@link ngRoute `ngRoute`} module to be installed. * * @animations * | Animation | Occurs | * |----------------------------------|-------------------------------------| * | {@link ng.$animate#enter enter} | when the new element is inserted to the DOM | * | {@link ng.$animate#leave leave} | when the old element is removed from to the DOM | * * The enter and leave animation occur concurrently. * * @scope * @priority 400 * @param {string=} onload Expression to evaluate whenever the view updates. * * @param {string=} autoscroll Whether `ngView` should call {@link ng.$anchorScroll * $anchorScroll} to scroll the viewport after the view is updated. * * - If the attribute is not set, disable scrolling. * - If the attribute is set without value, enable scrolling. * - Otherwise enable scrolling only if the `autoscroll` attribute value evaluated * as an expression yields a truthy value. * @example
Choose: Moby | Moby: Ch1 | Gatsby | Gatsby: Ch4 | Scarlet Letter

$location.path() = {{main.$location.path()}}
$route.current.templateUrl = {{main.$route.current.templateUrl}}
$route.current.params = {{main.$route.current.params}}
$routeParams = {{main.$routeParams}}
controller: {{book.name}}
Book Id: {{book.params.bookId}}
controller: {{chapter.name}}
Book Id: {{chapter.params.bookId}}
Chapter Id: {{chapter.params.chapterId}}
.view-animate-container { position:relative; height:100px!important; background:white; border:1px solid black; height:40px; overflow:hidden; } .view-animate { padding:10px; } .view-animate.ng-enter, .view-animate.ng-leave { transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s; display:block; width:100%; border-left:1px solid black; position:absolute; top:0; left:0; right:0; bottom:0; padding:10px; } .view-animate.ng-enter { left:100%; } .view-animate.ng-enter.ng-enter-active { left:0; } .view-animate.ng-leave.ng-leave-active { left:-100%; } angular.module('ngViewExample', ['ngRoute', 'ngAnimate']) .config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) { $routeProvider .when('/Book/:bookId', { templateUrl: 'book.html', controller: 'BookCtrl', controllerAs: 'book' }) .when('/Book/:bookId/ch/:chapterId', { templateUrl: 'chapter.html', controller: 'ChapterCtrl', controllerAs: 'chapter' }); $locationProvider.html5Mode(true); }]) .controller('MainCtrl', ['$route', '$routeParams', '$location', function MainCtrl($route, $routeParams, $location) { this.$route = $route; this.$location = $location; this.$routeParams = $routeParams; }]) .controller('BookCtrl', ['$routeParams', function BookCtrl($routeParams) { this.name = 'BookCtrl'; this.params = $routeParams; }]) .controller('ChapterCtrl', ['$routeParams', function ChapterCtrl($routeParams) { this.name = 'ChapterCtrl'; this.params = $routeParams; }]); it('should load and compile correct template', function() { element(by.linkText('Moby: Ch1')).click(); var content = element(by.css('[ng-view]')).getText(); expect(content).toMatch(/controller: ChapterCtrl/); expect(content).toMatch(/Book Id: Moby/); expect(content).toMatch(/Chapter Id: 1/); element(by.partialLinkText('Scarlet')).click(); content = element(by.css('[ng-view]')).getText(); expect(content).toMatch(/controller: BookCtrl/); expect(content).toMatch(/Book Id: Scarlet/); });
*/ /** * @ngdoc event * @name ngView#$viewContentLoaded * @eventType emit on the current ngView scope * @description * Emitted every time the ngView content is reloaded. */ ngViewFactory.$inject = ['$route', '$anchorScroll', '$animate']; function ngViewFactory($route, $anchorScroll, $animate) { return { restrict: 'ECA', terminal: true, priority: 400, transclude: 'element', link: function(scope, $element, attr, ctrl, $transclude) { var currentScope, currentElement, previousLeaveAnimation, autoScrollExp = attr.autoscroll, onloadExp = attr.onload || ''; scope.$on('$routeChangeSuccess', update); update(); function cleanupLastView() { if (previousLeaveAnimation) { $animate.cancel(previousLeaveAnimation); previousLeaveAnimation = null; } if (currentScope) { currentScope.$destroy(); currentScope = null; } if (currentElement) { previousLeaveAnimation = $animate.leave(currentElement); previousLeaveAnimation.done(function(response) { if (response !== false) previousLeaveAnimation = null; }); currentElement = null; } } function update() { var locals = $route.current && $route.current.locals, template = locals && locals.$template; if (angular.isDefined(template)) { var newScope = scope.$new(); var current = $route.current; // Note: This will also link all children of ng-view that were contained in the original // html. If that content contains controllers, ... they could pollute/change the scope. // However, using ng-view on an element with additional content does not make sense... // Note: We can't remove them in the cloneAttchFn of $transclude as that // function is called before linking the content, which would apply child // directives to non existing elements. var clone = $transclude(newScope, function(clone) { $animate.enter(clone, null, currentElement || $element).done(function onNgViewEnter(response) { if (response !== false && angular.isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) { $anchorScroll(); } }); cleanupLastView(); }); currentElement = clone; currentScope = current.scope = newScope; currentScope.$emit('$viewContentLoaded'); currentScope.$eval(onloadExp); } else { cleanupLastView(); } } } }; } // This directive is called during the $transclude call of the first `ngView` directive. // It will replace and compile the content of the element with the loaded template. // We need this directive so that the element content is already filled when // the link function of another directive on the same element as ngView // is called. ngViewFillContentFactory.$inject = ['$compile', '$controller', '$route']; function ngViewFillContentFactory($compile, $controller, $route) { return { restrict: 'ECA', priority: -400, link: function(scope, $element) { var current = $route.current, locals = current.locals; $element.html(locals.$template); var link = $compile($element.contents()); if (current.controller) { locals.$scope = scope; var controller = $controller(current.controller, locals); if (current.controllerAs) { scope[current.controllerAs] = controller; } $element.data('$ngControllerController', controller); $element.children().data('$ngControllerController', controller); } scope[current.resolveAs || '$resolve'] = locals; link(scope); } }; } })(window, window.angular);
Jackpot Games
Bang Gacor 1000
Bang Gacor 1000
NEKO X NEKO
NEKO X NEKO
Tokyo Drift Nitro
Tokyo Drift Nitro
Mines+
Mines+
Koi Gate
Koi Gate
The Crypt
The Crypt
New Games
Fortune of Olympus
Fortune of Olympus
Roma Legacy
Roma Legacy
Hot Hot Fruit
Hot Hot Fruit
Wild Bandito
Wild Bandito
Wanted Dead Or Wild
Wanted Dead Or Wild
Wild Beans
Wild Beans
Game Populer
Mahjong Wins 2
Mahjong Wins 2
Fortune Monkey
Fortune Monkey
The Great Icescape
The Great Icescape
Wukong Black Scatter
Wukong Black Scatter
Crypto Mania
Crypto Mania
Trump Card
Trump Card

Casinos That Accept Litecoin UK 2026: The Truth Behind the Search

Type “casinos that accept litecoin uk 2026” into Google and you will get a long list of sites promising fast crypto deposits and big bonuses. The first thing to understand is that none of those sites are licensed by the UK Gambling Commission. As of March 2026, not a single UKGC-licensed casino accepts Litecoin deposits or withdrawals. That gap between what people search for and what UK law allows is exactly why this guide exists.

The UK market runs on strict anti-money-laundering rules. Litecoin, like other cryptocurrencies, does not fit neatly into the source-of-funds checks the Commission expects from operators. The result is a two-tier market: licensed UK casinos stick to debit cards and e-wallets, while offshore crypto casinos accept Litecoin from anywhere they can legally reach. If you are in the UK and still want to use LTC, you need to know what you are actually getting into.

The Legal Reality in the UK: Why UKGC Casinos Won’t Touch Litecoin

The Gambling Act 2005 and the UK Gambling Commission’s licence conditions impose a duty on operators to establish the source of customers’ funds. Crypto wallets are pseudonymous. A casino cannot easily verify that the Litecoin you deposit came from your salary, a legitimate sale, or a previous win. Banks and payment processors in the UK also refuse to handle crypto transactions for gambling businesses because of chargeback and compliance risk. No UKGC operator has been willing to take on that burden for a payment method that only a tiny fraction of UK players use.

The Commission has not banned cryptocurrencies outright. But its guidance on remote gambling and software technical standards makes clear that any payment method must support robust customer due diligence. Litecoin does not. That is the practical reason why you will not find Bet365, William Hill, or LeoVegas advertising LTC deposits. They would rather lose a few crypto enthusiasts than risk a regulatory penalty.

Can I use Litecoin at a UK-licensed online casino?

No. UKGC-licensed casinos do not accept Litecoin or any other cryptocurrency for deposits or withdrawals as of early 2026. The regulator’s source-of-funds requirements make crypto payments operationally unworkable for licensed operators. Any site claiming to be a UK-licensed Litecoin casino is either misrepresenting its licence or using a payment processor that does not reflect the casino’s true legal status.

What You Actually Find When Searching for Litecoin Casinos in the UK

Search results for “casinos that accept litecoin uk 2026” are dominated by offshore brands with Curacao or Costa Rica licences. These sites have no UK Gambling Commission oversight, no obligation to join GamStop, and no requirement to follow UK advertising standards. They target UK-facing keywords because the search volume is there. The language is polished; the bonus offers are generous. But the legal protection you get from a UKGC licence is absent.

That does not mean every offshore Litecoin casino is a scam. Some have operated for years, process withdrawals quickly, and maintain decent reputations among crypto gamblers. But calling them “UK casinos” is misleading. They are international casinos that happen to accept UK players, often without checking location too carefully. The moment you deposit LTC, you are playing under a foreign regulator that will not help you in a dispute.

One of the more cynical tricks is the “free spins” or “no deposit bonus” advertised for Litecoin players. Casinos are not charities. A no-deposit bonus is a voucher to try the slots, but the wagering requirements attached to it often make withdrawing any winnings almost impossible. Treat those offers like a free sample at the dentist: nice to have, but you are still in the chair for the real cost.

Comparison Table: Recognized Litecoin Casino Brands (Offshore, Not UKGC Licensed)

The table below lists eight recognizable casino brands that accept Litecoin and are often discussed by UK-facing crypto gambling communities. They are not licensed in the UK. Use this table only as a starting point for your own research, and never deposit money you cannot afford to lose.

Casino/Operator Licence Litecoin Bonus Withdrawal Speed
BitStarz Curacao Welcome bonus + free spins Up to 10 minutes
Cloudbet Curacao Deposit match welcome bonus Instant to 1 hour
Stake Curacao Deposit bonus (casino/sports) Instant
BC.Game Curacao Deposit match + cashback 10–20 minutes
FortuneJack Curacao Welcome package + free spins Up to 1 hour
mBit Casino Curacao Welcome bonus + cashback Instant
7BitCasino Curacao Welcome package + free spins Up to 1 hour
Metaspins Curacao Deposit bonus + rakeback Instant

All eight brands have been active in the crypto casino space for at least two years. None hold a UKGC licence. If a brand above later obtains one, check its current payment methods before assuming LTC is still supported.

How to Deposit Litecoin at an Offshore Casino (Step-by-Step)

If you decide to proceed with an offshore Litecoin casino, the mechanics are simple. You need a Litecoin wallet with some LTC, an account at the casino, and a copied deposit address. The process takes less than two minutes on most sites. But speed is not the same as safety.

First, register at the casino using an email address and a strong password. Many crypto casinos do not require identity verification for small deposits, but they may later demand KYC for withdrawals. Second, go to the cashier, select Litecoin as your deposit method, and copy the wallet address shown. Third, open your external wallet, paste the address, enter the amount, and send. The casino usually credits the balance after one confirmation on the Litecoin network, which takes around two to three minutes.

Withdrawals follow the same route in reverse. Enter your Litecoin wallet address, choose an amount, and confirm. Offshore casinos often process crypto withdrawals within minutes, unlike UKGC sites that take one to three business days for bank transfers. That speed is one reason some UK players tolerate the legal grey area. But the trade-off is real: no UK ombudsman, no GamStop, no Commission to complain to if your withdrawal is frozen.

How do I deposit Litecoin at an online casino?

Create an account at a casino that advertises Litecoin support, go to the cashier, select Litecoin, and copy the deposit address shown. Then use your personal Litecoin wallet to send the desired amount to that address. The deposit is typically credited after one network confirmation, which takes about two and a half minutes. Always double-check the address before confirming the transaction.

Alternatives to Litecoin for UK Casino Players

If you want to stay within UK Gambling Commission protection, forget Litecoin. Licensed UK casinos accept Visa, Mastercard, PayPal, Skrill, Neteller, and bank transfers. Some also offer Apple Pay and Google Pay. These methods allow the operator to comply with source-of-funds checks and give you access to GamStop self-exclusion and dispute resolution through the Commission.

The trade-off is speed and privacy. A debit card deposit is instant, but withdrawals to a bank account often take one to three business days. E-wallets like PayPal and Skrill can be faster, but still not as quick as a crypto transfer. If speed is your priority and you are willing to give up UK legal protection, Litecoin remains an option—just not at a licensed site.

What are the best alternatives to Litecoin for UK players?

For players who want full UK Gambling Commission protection, the best alternatives are Visa debit, Mastercard debit, PayPal, Skrill, and Neteller. These methods are accepted at all major UKGC casinos and comply with source-of-funds checks. Bank transfer is slower but widely available. Avoid any payment method that obscures your identity if you want the regulator to be able to help you later.

Are There Any Future Changes Coming for UK Crypto Gambling?

The UK Gambling Commission has shown no sign of relaxing its stance on cryptocurrency payments. The Financial Conduct Authority has tightened crypto promotion rules, and the Treasury has indicated it wants to bring crypto assets under the same AML framework as traditional finance. That makes it even less likely that a UKGC casino will start accepting Litecoin in the near term.

Some industry commentators argue that the UK could eventually allow crypto if it mandates full wallet screening by regulated payment providers. But that would require legal changes and a shift in banking attitudes. For 2026, the safe assumption is that UKGC casinos will continue to avoid Litecoin. Anyone claiming otherwise is probably selling you something else.

Will UK casinos ever accept Litecoin?

There is no credible sign that UKGC-licensed casinos will accept Litecoin in the next few years. The regulator’s source-of-funds requirements and banks’ refusal to process crypto gambling payments make it operationally unattractive. A legislative change or a regulated crypto payment rail could alter that, but nothing in the current pipeline suggests it will happen before 2028 at the earliest.

Responsible Gambling When Using Offshore Crypto Casinos

Offshore Litecoin casinos do not participate in GamStop. You cannot self-exclude across sites through the UK system, and the Curacao regulator does not offer the same level of player protection. If you struggle with gambling, the lack of these safeguards can make things worse. Set your own deposit limits, use a separate wallet with only gambling funds, and do not chase losses.

The UK has good free resources: GamCare, BeGambleAware, and the National Gambling Helpline. They work regardless of which casino you use. The moment you feel that Litecoin deposits are becoming too easy, that is a signal to stop. Crypto removes friction, and friction is sometimes the only thing that slows a bad habit.

Is it safe to play at offshore Litecoin casinos?

Offshore Litecoin casinos are not subject to UK Gambling Commission oversight, so player protection is weaker. Some have operated for years without major issues, but you have no UK ombudsman to appeal to if a withdrawal is withheld. Only deposit small amounts, verify the casino’s reputation in crypto gambling communities, and never treat an offshore site as equivalent to a UKGC-licensed operator.

That covers the main questions UK players ask about Litecoin casinos in 2026. The headline remains simple: no UKGC casino accepts LTC, and the offshore options are a separate risk category. Choose accordingly.

Casinos That Accept Litecoin UK 2026: The Truth Behind the Search