UNPKG

mcs-ng-material

Version:

MCS NG-Meterial is based on mcs-web.

1,140 lines (1,130 loc) 87 kB
/** * State-based routing for AngularJS 1.x * This bundle requires the ui-router-core.js bundle from the @uirouter/core package. * @version v1.0.13 * @link https://ui-router.github.io * @license MIT License, http://www.opensource.org/licenses/MIT */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('angular'), require('@uirouter/core')) : typeof define === 'function' && define.amd ? define(['exports', 'angular', '@uirouter/core'], factory) : (factory((global['@uirouter/angularjs'] = {}),global.angular,global['@uirouter/core'])); }(this, (function (exports,ng_from_import,core) { 'use strict'; var ng_from_global = angular; var ng = (ng_from_import && ng_from_import.module) ? ng_from_import : ng_from_global; function getNg1ViewConfigFactory() { var templateFactory = null; return function (path, view) { templateFactory = templateFactory || core.services.$injector.get('$templateFactory'); return [new Ng1ViewConfig(path, view, templateFactory)]; }; } var hasAnyKey = function (keys, obj) { return keys.reduce(function (acc, key) { return acc || core.isDefined(obj[key]); }, false); }; /** * This is a [[StateBuilder.builder]] function for angular1 `views`. * * When the [[StateBuilder]] builds a [[StateObject]] object from a raw [[StateDeclaration]], this builder * handles the `views` property with logic specific to @uirouter/angularjs (ng1). * * If no `views: {}` property exists on the [[StateDeclaration]], then it creates the `views` object * and applies the state-level configuration to a view named `$default`. */ function ng1ViewsBuilder(state) { // Do not process root state if (!state.parent) return {}; var tplKeys = ['templateProvider', 'templateUrl', 'template', 'notify', 'async'], ctrlKeys = ['controller', 'controllerProvider', 'controllerAs', 'resolveAs'], compKeys = ['component', 'bindings', 'componentProvider'], nonCompKeys = tplKeys.concat(ctrlKeys), allViewKeys = compKeys.concat(nonCompKeys); // Do not allow a state to have both state-level props and also a `views: {}` property. // A state without a `views: {}` property can declare properties for the `$default` view as properties of the state. // However, the `$default` approach should not be mixed with a separate `views: ` block. if (core.isDefined(state.views) && hasAnyKey(allViewKeys, state)) { throw new Error("State '" + state.name + "' has a 'views' object. " + "It cannot also have \"view properties\" at the state level. " + "Move the following properties into a view (in the 'views' object): " + (" " + allViewKeys.filter(function (key) { return core.isDefined(state[key]); }).join(', '))); } var views = {}, viewsObject = state.views || { '$default': core.pick(state, allViewKeys) }; core.forEach(viewsObject, function (config, name) { // Account for views: { "": { template... } } name = name || '$default'; // Account for views: { header: "headerComponent" } if (core.isString(config)) config = { component: config }; // Make a shallow copy of the config object config = core.extend({}, config); // Do not allow a view to mix props for component-style view with props for template/controller-style view if (hasAnyKey(compKeys, config) && hasAnyKey(nonCompKeys, config)) { throw new Error("Cannot combine: " + compKeys.join('|') + " with: " + nonCompKeys.join('|') + " in stateview: '" + name + "@" + state.name + "'"); } config.resolveAs = config.resolveAs || '$resolve'; config.$type = 'ng1'; config.$context = state; config.$name = name; var normalized = core.ViewService.normalizeUIViewTarget(config.$context, config.$name); config.$uiViewName = normalized.uiViewName; config.$uiViewContextAnchor = normalized.uiViewContextAnchor; views[name] = config; }); return views; } var id = 0; var Ng1ViewConfig = /** @class */ (function () { function Ng1ViewConfig(path, viewDecl, factory) { var _this = this; this.path = path; this.viewDecl = viewDecl; this.factory = factory; this.$id = id++; this.loaded = false; this.getTemplate = function (uiView, context) { return _this.component ? _this.factory.makeComponentTemplate(uiView, context, _this.component, _this.viewDecl.bindings) : _this.template; }; } Ng1ViewConfig.prototype.load = function () { var _this = this; var $q = core.services.$q; var context = new core.ResolveContext(this.path); var params = this.path.reduce(function (acc, node) { return core.extend(acc, node.paramValues); }, {}); var promises = { template: $q.when(this.factory.fromConfig(this.viewDecl, params, context)), controller: $q.when(this.getController(context)), }; return $q.all(promises).then(function (results) { core.trace.traceViewServiceEvent('Loaded', _this); _this.controller = results.controller; core.extend(_this, results.template); // Either { template: "tpl" } or { component: "cmpName" } return _this; }); }; /** * Gets the controller for a view configuration. * * @returns {Function|Promise.<Function>} Returns a controller, or a promise that resolves to a controller. */ Ng1ViewConfig.prototype.getController = function (context) { var provider = this.viewDecl.controllerProvider; if (!core.isInjectable(provider)) return this.viewDecl.controller; var deps = core.services.$injector.annotate(provider); var providerFn = core.isArray(provider) ? core.tail(provider) : provider; var resolvable = new core.Resolvable('', providerFn, deps); return resolvable.get(context); }; return Ng1ViewConfig; }()); /** @module view */ /** for typedoc */ /** * Service which manages loading of templates from a ViewConfig. */ var TemplateFactory = /** @class */ (function () { function TemplateFactory() { var _this = this; /** @hidden */ this._useHttp = ng.version.minor < 3; /** @hidden */ this.$get = ['$http', '$templateCache', '$injector', function ($http, $templateCache, $injector) { _this.$templateRequest = $injector.has && $injector.has('$templateRequest') && $injector.get('$templateRequest'); _this.$http = $http; _this.$templateCache = $templateCache; return _this; }]; } /** @hidden */ TemplateFactory.prototype.useHttpService = function (value) { this._useHttp = value; }; /** * Creates a template from a configuration object. * * @param config Configuration object for which to load a template. * The following properties are search in the specified order, and the first one * that is defined is used to create the template: * * @param params Parameters to pass to the template function. * @param context The resolve context associated with the template's view * * @return {string|object} The template html as a string, or a promise for * that string,or `null` if no template is configured. */ TemplateFactory.prototype.fromConfig = function (config, params, context) { var defaultTemplate = '<ui-view></ui-view>'; var asTemplate = function (result) { return core.services.$q.when(result).then(function (str) { return ({ template: str }); }); }; var asComponent = function (result) { return core.services.$q.when(result).then(function (str) { return ({ component: str }); }); }; return (core.isDefined(config.template) ? asTemplate(this.fromString(config.template, params)) : core.isDefined(config.templateUrl) ? asTemplate(this.fromUrl(config.templateUrl, params)) : core.isDefined(config.templateProvider) ? asTemplate(this.fromProvider(config.templateProvider, params, context)) : core.isDefined(config.component) ? asComponent(config.component) : core.isDefined(config.componentProvider) ? asComponent(this.fromComponentProvider(config.componentProvider, params, context)) : asTemplate(defaultTemplate)); }; /** * Creates a template from a string or a function returning a string. * * @param template html template as a string or function that returns an html template as a string. * @param params Parameters to pass to the template function. * * @return {string|object} The template html as a string, or a promise for that * string. */ TemplateFactory.prototype.fromString = function (template, params) { return core.isFunction(template) ? template(params) : template; }; /** * Loads a template from the a URL via `$http` and `$templateCache`. * * @param {string|Function} url url of the template to load, or a function * that returns a url. * @param {Object} params Parameters to pass to the url function. * @return {string|Promise.<string>} The template html as a string, or a promise * for that string. */ TemplateFactory.prototype.fromUrl = function (url, params) { if (core.isFunction(url)) url = url(params); if (url == null) return null; if (this._useHttp) { return this.$http.get(url, { cache: this.$templateCache, headers: { Accept: 'text/html' } }) .then(function (response) { return response.data; }); } return this.$templateRequest(url); }; /** * Creates a template by invoking an injectable provider function. * * @param provider Function to invoke via `locals` * @param {Function} injectFn a function used to invoke the template provider * @return {string|Promise.<string>} The template html as a string, or a promise * for that string. */ TemplateFactory.prototype.fromProvider = function (provider, params, context) { var deps = core.services.$injector.annotate(provider); var providerFn = core.isArray(provider) ? core.tail(provider) : provider; var resolvable = new core.Resolvable('', providerFn, deps); return resolvable.get(context); }; /** * Creates a component's template by invoking an injectable provider function. * * @param provider Function to invoke via `locals` * @param {Function} injectFn a function used to invoke the template provider * @return {string} The template html as a string: "<component-name input1='::$resolve.foo'></component-name>". */ TemplateFactory.prototype.fromComponentProvider = function (provider, params, context) { var deps = core.services.$injector.annotate(provider); var providerFn = core.isArray(provider) ? core.tail(provider) : provider; var resolvable = new core.Resolvable('', providerFn, deps); return resolvable.get(context); }; /** * Creates a template from a component's name * * This implements route-to-component. * It works by retrieving the component (directive) metadata from the injector. * It analyses the component's bindings, then constructs a template that instantiates the component. * The template wires input and output bindings to resolves or from the parent component. * * @param uiView {object} The parent ui-view (for binding outputs to callbacks) * @param context The ResolveContext (for binding outputs to callbacks returned from resolves) * @param component {string} Component's name in camel case. * @param bindings An object defining the component's bindings: {foo: '<'} * @return {string} The template as a string: "<component-name input1='::$resolve.foo'></component-name>". */ TemplateFactory.prototype.makeComponentTemplate = function (uiView, context, component, bindings) { bindings = bindings || {}; // Bind once prefix var prefix = ng.version.minor >= 3 ? '::' : ''; // Convert to kebob name. Add x- prefix if the string starts with `x-` or `data-` var kebob = function (camelCase) { var kebobed = core.kebobString(camelCase); return /^(x|data)-/.exec(kebobed) ? "x-" + kebobed : kebobed; }; var attributeTpl = function (input) { var name = input.name, type = input.type; var attrName = kebob(name); // If the ui-view has an attribute which matches a binding on the routed component // then pass that attribute through to the routed component template. // Prefer ui-view wired mappings to resolve data, unless the resolve was explicitly bound using `bindings:` if (uiView.attr(attrName) && !bindings[name]) return attrName + "='" + uiView.attr(attrName) + "'"; var resolveName = bindings[name] || name; // Pre-evaluate the expression for "@" bindings by enclosing in {{ }} // some-attr="{{ ::$resolve.someResolveName }}" if (type === '@') return attrName + "='{{" + prefix + "$resolve." + resolveName + "}}'"; // Wire "&" callbacks to resolves that return a callback function // Get the result of the resolve (should be a function) and annotate it to get its arguments. // some-attr="$resolve.someResolveResultName(foo, bar)" if (type === '&') { var res = context.getResolvable(resolveName); var fn = res && res.data; var args = fn && core.services.$injector.annotate(fn) || []; // account for array style injection, i.e., ['foo', function(foo) {}] var arrayIdxStr = core.isArray(fn) ? "[" + (fn.length - 1) + "]" : ''; return attrName + "='$resolve." + resolveName + arrayIdxStr + "(" + args.join(',') + ")'"; } // some-attr="::$resolve.someResolveName" return attrName + "='" + prefix + "$resolve." + resolveName + "'"; }; var attrs = getComponentBindings(component).map(attributeTpl).join(' '); var kebobName = kebob(component); return "<" + kebobName + " " + attrs + "></" + kebobName + ">"; }; return TemplateFactory; }()); // Gets all the directive(s)' inputs ('@', '=', and '<') and outputs ('&') function getComponentBindings(name) { var cmpDefs = core.services.$injector.get(name + 'Directive'); // could be multiple if (!cmpDefs || !cmpDefs.length) throw new Error("Unable to find component named '" + name + "'"); return cmpDefs.map(getBindings).reduce(core.unnestR, []); } // Given a directive definition, find its object input attributes // Use different properties, depending on the type of directive (component, bindToController, normal) var getBindings = function (def) { if (core.isObject(def.bindToController)) return scopeBindings(def.bindToController); return scopeBindings(def.scope); }; // for ng 1.2 style, process the scope: { input: "=foo" } // for ng 1.3 through ng 1.5, process the component's bindToController: { input: "=foo" } object var scopeBindings = function (bindingsObj) { return Object.keys(bindingsObj || {}) .map(function (key) { return [key, /^([=<@&])[?]?(.*)/.exec(bindingsObj[key])]; }) .filter(function (tuple) { return core.isDefined(tuple) && core.isArray(tuple[1]); }) .map(function (tuple) { return ({ name: tuple[1][2] || tuple[0], type: tuple[1][1] }); }); }; /** @module ng1 */ /** for typedoc */ /** * The Angular 1 `StateProvider` * * The `$stateProvider` works similar to Angular's v1 router, but it focuses purely * on state. * * A state corresponds to a "place" in the application in terms of the overall UI and * navigation. A state describes (via the controller / template / view properties) what * the UI looks like and does at that place. * * States often have things in common, and the primary way of factoring out these * commonalities in this model is via the state hierarchy, i.e. parent/child states aka * nested states. * * The `$stateProvider` provides interfaces to declare these states for your app. */ var StateProvider = /** @class */ (function () { function StateProvider(stateRegistry, stateService) { this.stateRegistry = stateRegistry; this.stateService = stateService; core.createProxyFunctions(core.val(StateProvider.prototype), this, core.val(this)); } /** * Decorates states when they are registered * * Allows you to extend (carefully) or override (at your own peril) the * `stateBuilder` object used internally by [[StateRegistry]]. * This can be used to add custom functionality to ui-router, * for example inferring templateUrl based on the state name. * * When passing only a name, it returns the current (original or decorated) builder * function that matches `name`. * * The builder functions that can be decorated are listed below. Though not all * necessarily have a good use case for decoration, that is up to you to decide. * * In addition, users can attach custom decorators, which will generate new * properties within the state's internal definition. There is currently no clear * use-case for this beyond accessing internal states (i.e. $state.$current), * however, expect this to become increasingly relevant as we introduce additional * meta-programming features. * * **Warning**: Decorators should not be interdependent because the order of * execution of the builder functions in non-deterministic. Builder functions * should only be dependent on the state definition object and super function. * * * Existing builder functions and current return values: * * - **parent** `{object}` - returns the parent state object. * - **data** `{object}` - returns state data, including any inherited data that is not * overridden by own values (if any). * - **url** `{object}` - returns a {@link ui.router.util.type:UrlMatcher UrlMatcher} * or `null`. * - **navigable** `{object}` - returns closest ancestor state that has a URL (aka is * navigable). * - **params** `{object}` - returns an array of state params that are ensured to * be a super-set of parent's params. * - **views** `{object}` - returns a views object where each key is an absolute view * name (i.e. "viewName@stateName") and each value is the config object * (template, controller) for the view. Even when you don't use the views object * explicitly on a state config, one is still created for you internally. * So by decorating this builder function you have access to decorating template * and controller properties. * - **ownParams** `{object}` - returns an array of params that belong to the state, * not including any params defined by ancestor states. * - **path** `{string}` - returns the full path from the root down to this state. * Needed for state activation. * - **includes** `{object}` - returns an object that includes every state that * would pass a `$state.includes()` test. * * #### Example: * Override the internal 'views' builder with a function that takes the state * definition, and a reference to the internal function being overridden: * ```js * $stateProvider.decorator('views', function (state, parent) { * let result = {}, * views = parent(state); * * angular.forEach(views, function (config, name) { * let autoName = (state.name + '.' + name).replace('.', '/'); * config.templateUrl = config.templateUrl || '/partials/' + autoName + '.html'; * result[name] = config; * }); * return result; * }); * * $stateProvider.state('home', { * views: { * 'contact.list': { controller: 'ListController' }, * 'contact.item': { controller: 'ItemController' } * } * }); * ``` * * * ```js * // Auto-populates list and item views with /partials/home/contact/list.html, * // and /partials/home/contact/item.html, respectively. * $state.go('home'); * ``` * * @param {string} name The name of the builder function to decorate. * @param {object} func A function that is responsible for decorating the original * builder function. The function receives two parameters: * * - `{object}` - state - The state config object. * - `{object}` - super - The original builder function. * * @return {object} $stateProvider - $stateProvider instance */ StateProvider.prototype.decorator = function (name, func) { return this.stateRegistry.decorator(name, func) || this; }; StateProvider.prototype.state = function (name, definition) { if (core.isObject(name)) { definition = name; } else { definition.name = name; } this.stateRegistry.register(definition); return this; }; /** * Registers an invalid state handler * * This is a passthrough to [[StateService.onInvalid]] for ng1. */ StateProvider.prototype.onInvalid = function (callback) { return this.stateService.onInvalid(callback); }; return StateProvider; }()); /** @module ng1 */ /** */ /** * This is a [[StateBuilder.builder]] function for angular1 `onEnter`, `onExit`, * `onRetain` callback hooks on a [[Ng1StateDeclaration]]. * * When the [[StateBuilder]] builds a [[StateObject]] object from a raw [[StateDeclaration]], this builder * ensures that those hooks are injectable for @uirouter/angularjs (ng1). */ var getStateHookBuilder = function (hookName) { return function stateHookBuilder(stateObject, parentFn) { var hook = stateObject[hookName]; var pathname = hookName === 'onExit' ? 'from' : 'to'; function decoratedNg1Hook(trans, state) { var resolveContext = new core.ResolveContext(trans.treeChanges(pathname)); var subContext = resolveContext.subContext(state.$$state()); var locals = core.extend(getLocals(subContext), { $state$: state, $transition$: trans }); return core.services.$injector.invoke(hook, this, locals); } return hook ? decoratedNg1Hook : undefined; }; }; /** * @internalapi * @module ng1 */ /** */ /** * Implements UI-Router LocationServices and LocationConfig using Angular 1's $location service */ var Ng1LocationServices = /** @class */ (function () { function Ng1LocationServices($locationProvider) { // .onChange() registry this._urlListeners = []; this.$locationProvider = $locationProvider; var _lp = core.val($locationProvider); core.createProxyFunctions(_lp, this, _lp, ['hashPrefix']); } /** * Applys ng1-specific path parameter encoding * * The Angular 1 `$location` service is a bit weird. * It doesn't allow slashes to be encoded/decoded bi-directionally. * * See the writeup at https://github.com/angular-ui/ui-router/issues/2598 * * This code patches the `path` parameter type so it encoded/decodes slashes as ~2F * * @param router */ Ng1LocationServices.monkeyPatchPathParameterType = function (router) { var pathType = router.urlMatcherFactory.type('path'); pathType.encode = function (x) { return x != null ? x.toString().replace(/(~|\/)/g, function (m) { return ({ '~': '~~', '/': '~2F' }[m]); }) : x; }; pathType.decode = function (x) { return x != null ? x.toString().replace(/(~~|~2F)/g, function (m) { return ({ '~~': '~', '~2F': '/' }[m]); }) : x; }; }; Ng1LocationServices.prototype.dispose = function () { }; Ng1LocationServices.prototype.onChange = function (callback) { var _this = this; this._urlListeners.push(callback); return function () { return core.removeFrom(_this._urlListeners)(callback); }; }; Ng1LocationServices.prototype.html5Mode = function () { var html5Mode = this.$locationProvider.html5Mode(); html5Mode = core.isObject(html5Mode) ? html5Mode.enabled : html5Mode; return html5Mode && this.$sniffer.history; }; Ng1LocationServices.prototype.url = function (newUrl, replace, state) { if (replace === void 0) { replace = false; } if (core.isDefined(newUrl)) this.$location.url(newUrl); if (replace) this.$location.replace(); if (state) this.$location.state(state); return this.$location.url(); }; Ng1LocationServices.prototype._runtimeServices = function ($rootScope, $location, $sniffer, $browser) { var _this = this; this.$location = $location; this.$sniffer = $sniffer; // Bind $locationChangeSuccess to the listeners registered in LocationService.onChange $rootScope.$on('$locationChangeSuccess', function (evt) { return _this._urlListeners.forEach(function (fn) { return fn(evt); }); }); var _loc = core.val($location); var _browser = core.val($browser); // Bind these LocationService functions to $location core.createProxyFunctions(_loc, this, _loc, ['replace', 'path', 'search', 'hash']); // Bind these LocationConfig functions to $location core.createProxyFunctions(_loc, this, _loc, ['port', 'protocol', 'host']); // Bind these LocationConfig functions to $browser core.createProxyFunctions(_browser, this, _browser, ['baseHref']); }; return Ng1LocationServices; }()); /** @module url */ /** */ /** * Manages rules for client-side URL * * ### Deprecation warning: * This class is now considered to be an internal API * Use the [[UrlService]] instead. * For configuring URL rules, use the [[UrlRulesApi]] which can be found as [[UrlService.rules]]. * * This class manages the router rules for what to do when the URL changes. * * This provider remains for backwards compatibility. * * @deprecated */ var UrlRouterProvider = /** @class */ (function () { /** @hidden */ function UrlRouterProvider(router) { this._router = router; this._urlRouter = router.urlRouter; } UrlRouterProvider.injectableHandler = function (router, handler) { return function (match) { return core.services.$injector.invoke(handler, null, { $match: match, $stateParams: router.globals.params }); }; }; /** @hidden */ UrlRouterProvider.prototype.$get = function () { var urlRouter = this._urlRouter; urlRouter.update(true); if (!urlRouter.interceptDeferred) urlRouter.listen(); return urlRouter; }; /** * Registers a url handler function. * * Registers a low level url handler (a `rule`). * A rule detects specific URL patterns and returns a redirect, or performs some action. * * If a rule returns a string, the URL is replaced with the string, and all rules are fired again. * * #### Example: * ```js * var app = angular.module('app', ['ui.router.router']); * * app.config(function ($urlRouterProvider) { * // Here's an example of how you might allow case insensitive urls * $urlRouterProvider.rule(function ($injector, $location) { * var path = $location.path(), * normalized = path.toLowerCase(); * * if (path !== normalized) { * return normalized; * } * }); * }); * ``` * * @param ruleFn * Handler function that takes `$injector` and `$location` services as arguments. * You can use them to detect a url and return a different url as a string. * * @return [[UrlRouterProvider]] (`this`) */ UrlRouterProvider.prototype.rule = function (ruleFn) { var _this = this; if (!core.isFunction(ruleFn)) throw new Error("'rule' must be a function"); var match = function () { return ruleFn(core.services.$injector, _this._router.locationService); }; var rule = new core.BaseUrlRule(match, core.identity); this._urlRouter.rule(rule); return this; }; /** * Defines the path or behavior to use when no url can be matched. * * #### Example: * ```js * var app = angular.module('app', ['ui.router.router']); * * app.config(function ($urlRouterProvider) { * // if the path doesn't match any of the urls you configured * // otherwise will take care of routing the user to the * // specified url * $urlRouterProvider.otherwise('/index'); * * // Example of using function rule as param * $urlRouterProvider.otherwise(function ($injector, $location) { * return '/a/valid/url'; * }); * }); * ``` * * @param rule * The url path you want to redirect to or a function rule that returns the url path or performs a `$state.go()`. * The function version is passed two params: `$injector` and `$location` services, and should return a url string. * * @return {object} `$urlRouterProvider` - `$urlRouterProvider` instance */ UrlRouterProvider.prototype.otherwise = function (rule) { var _this = this; var urlRouter = this._urlRouter; if (core.isString(rule)) { urlRouter.otherwise(rule); } else if (core.isFunction(rule)) { urlRouter.otherwise(function () { return rule(core.services.$injector, _this._router.locationService); }); } else { throw new Error("'rule' must be a string or function"); } return this; }; /** * Registers a handler for a given url matching. * * If the handler is a string, it is * treated as a redirect, and is interpolated according to the syntax of match * (i.e. like `String.replace()` for `RegExp`, or like a `UrlMatcher` pattern otherwise). * * If the handler is a function, it is injectable. * It gets invoked if `$location` matches. * You have the option of inject the match object as `$match`. * * The handler can return * * - **falsy** to indicate that the rule didn't match after all, then `$urlRouter` * will continue trying to find another one that matches. * - **string** which is treated as a redirect and passed to `$location.url()` * - **void** or any **truthy** value tells `$urlRouter` that the url was handled. * * #### Example: * ```js * var app = angular.module('app', ['ui.router.router']); * * app.config(function ($urlRouterProvider) { * $urlRouterProvider.when($state.url, function ($match, $stateParams) { * if ($state.$current.navigable !== state || * !equalForKeys($match, $stateParams) { * $state.transitionTo(state, $match, false); * } * }); * }); * ``` * * @param what A pattern string to match, compiled as a [[UrlMatcher]]. * @param handler The path (or function that returns a path) that you want to redirect your user to. * @param ruleCallback [optional] A callback that receives the `rule` registered with [[UrlMatcher.rule]] * * Note: the handler may also invoke arbitrary code, such as `$state.go()` */ UrlRouterProvider.prototype.when = function (what, handler) { if (core.isArray(handler) || core.isFunction(handler)) { handler = UrlRouterProvider.injectableHandler(this._router, handler); } this._urlRouter.when(what, handler); return this; }; /** * Disables monitoring of the URL. * * Call this method before UI-Router has bootstrapped. * It will stop UI-Router from performing the initial url sync. * * This can be useful to perform some asynchronous initialization before the router starts. * Once the initialization is complete, call [[listen]] to tell UI-Router to start watching and synchronizing the URL. * * #### Example: * ```js * var app = angular.module('app', ['ui.router']); * * app.config(function ($urlRouterProvider) { * // Prevent $urlRouter from automatically intercepting URL changes; * $urlRouterProvider.deferIntercept(); * }) * * app.run(function (MyService, $urlRouter, $http) { * $http.get("/stuff").then(function(resp) { * MyService.doStuff(resp.data); * $urlRouter.listen(); * $urlRouter.sync(); * }); * }); * ``` * * @param defer Indicates whether to defer location change interception. * Passing no parameter is equivalent to `true`. */ UrlRouterProvider.prototype.deferIntercept = function (defer) { this._urlRouter.deferIntercept(defer); }; return UrlRouterProvider; }()); /** * # Angular 1 types * * UI-Router core provides various Typescript types which you can use for code completion and validating parameter values, etc. * The customizations to the core types for Angular UI-Router are documented here. * * The optional [[$resolve]] service is also documented here. * * @module ng1 * @preferred */ /** for typedoc */ ng.module('ui.router.angular1', []); var mod_init = ng.module('ui.router.init', []); var mod_util = ng.module('ui.router.util', ['ng', 'ui.router.init']); var mod_rtr = ng.module('ui.router.router', ['ui.router.util']); var mod_state = ng.module('ui.router.state', ['ui.router.router', 'ui.router.util', 'ui.router.angular1']); var mod_main = ng.module('ui.router', ['ui.router.init', 'ui.router.state', 'ui.router.angular1']); var mod_cmpt = ng.module('ui.router.compat', ['ui.router']); // tslint:disable-line var router = null; $uiRouterProvider.$inject = ['$locationProvider']; /** This angular 1 provider instantiates a Router and exposes its services via the angular injector */ function $uiRouterProvider($locationProvider) { // Create a new instance of the Router when the $uiRouterProvider is initialized router = this.router = new core.UIRouter(); router.stateProvider = new StateProvider(router.stateRegistry, router.stateService); // Apply ng1 specific StateBuilder code for `views`, `resolve`, and `onExit/Retain/Enter` properties router.stateRegistry.decorator('views', ng1ViewsBuilder); router.stateRegistry.decorator('onExit', getStateHookBuilder('onExit')); router.stateRegistry.decorator('onRetain', getStateHookBuilder('onRetain')); router.stateRegistry.decorator('onEnter', getStateHookBuilder('onEnter')); router.viewService._pluginapi._viewConfigFactory('ng1', getNg1ViewConfigFactory()); var ng1LocationService = router.locationService = router.locationConfig = new Ng1LocationServices($locationProvider); Ng1LocationServices.monkeyPatchPathParameterType(router); // backwards compat: also expose router instance as $uiRouterProvider.router router['router'] = router; router['$get'] = $get; $get.$inject = ['$location', '$browser', '$sniffer', '$rootScope', '$http', '$templateCache']; function $get($location, $browser, $sniffer, $rootScope, $http, $templateCache) { ng1LocationService._runtimeServices($rootScope, $location, $sniffer, $browser); delete router['router']; delete router['$get']; return router; } return router; } var getProviderFor = function (serviceName) { return ['$uiRouterProvider', function ($urp) { var service = $urp.router[serviceName]; service['$get'] = function () { return service; }; return service; }]; }; // This effectively calls $get() on `$uiRouterProvider` to trigger init (when ng enters runtime) runBlock.$inject = ['$injector', '$q', '$uiRouter']; function runBlock($injector, $q, $uiRouter) { core.services.$injector = $injector; core.services.$q = $q; // The $injector is now available. // Find any resolvables that had dependency annotation deferred $uiRouter.stateRegistry.get() .map(function (x) { return x.$$state().resolvables; }) .reduce(core.unnestR, []) .filter(function (x) { return x.deps === 'deferred'; }) .forEach(function (resolvable) { return resolvable.deps = $injector.annotate(resolvable.resolveFn, $injector.strictDi); }); } // $urlRouter service and $urlRouterProvider var getUrlRouterProvider = function (uiRouter) { return uiRouter.urlRouterProvider = new UrlRouterProvider(uiRouter); }; // $state service and $stateProvider // $urlRouter service and $urlRouterProvider var getStateProvider = function () { return core.extend(router.stateProvider, { $get: function () { return router.stateService; } }); }; watchDigests.$inject = ['$rootScope']; function watchDigests($rootScope) { $rootScope.$watch(function () { core.trace.approximateDigests++; }); } mod_init.provider('$uiRouter', $uiRouterProvider); mod_rtr.provider('$urlRouter', ['$uiRouterProvider', getUrlRouterProvider]); mod_util.provider('$urlService', getProviderFor('urlService')); mod_util.provider('$urlMatcherFactory', ['$uiRouterProvider', function () { return router.urlMatcherFactory; }]); mod_util.provider('$templateFactory', function () { return new TemplateFactory(); }); mod_state.provider('$stateRegistry', getProviderFor('stateRegistry')); mod_state.provider('$uiRouterGlobals', getProviderFor('globals')); mod_state.provider('$transitions', getProviderFor('transitionService')); mod_state.provider('$state', ['$uiRouterProvider', getStateProvider]); mod_state.factory('$stateParams', ['$uiRouter', function ($uiRouter) { return $uiRouter.globals.params; }]); mod_main.factory('$view', function () { return router.viewService; }); mod_main.service('$trace', function () { return core.trace; }); mod_main.run(watchDigests); mod_util.run(['$urlMatcherFactory', function ($urlMatcherFactory) { }]); mod_state.run(['$state', function ($state) { }]); mod_rtr.run(['$urlRouter', function ($urlRouter) { }]); mod_init.run(runBlock); /** @hidden TODO: find a place to move this */ var getLocals = function (ctx) { var tokens = ctx.getTokens().filter(core.isString); var tuples = tokens.map(function (key) { var resolvable = ctx.getResolvable(key); var waitPolicy = ctx.getPolicy(resolvable).async; return [key, waitPolicy === 'NOWAIT' ? resolvable.promise : resolvable.data]; }); return tuples.reduce(core.applyPairs, {}); }; /** * The current (or pending) State Parameters * * An injectable global **Service Object** which holds the state parameters for the latest **SUCCESSFUL** transition. * * The values are not updated until *after* a `Transition` successfully completes. * * **Also:** an injectable **Per-Transition Object** object which holds the pending state parameters for the pending `Transition` currently running. * * ### Deprecation warning: * * The value injected for `$stateParams` is different depending on where it is injected. * * - When injected into an angular service, the object injected is the global **Service Object** with the parameter values for the latest successful `Transition`. * - When injected into transition hooks, resolves, or view controllers, the object is the **Per-Transition Object** with the parameter values for the running `Transition`. * * Because of these confusing details, this service is deprecated. * * ### Instead of using the global `$stateParams` service object, * inject [[$uiRouterGlobals]] and use [[UIRouterGlobals.params]] * * ```js * MyService.$inject = ['$uiRouterGlobals']; * function MyService($uiRouterGlobals) { * return { * paramValues: function () { * return $uiRouterGlobals.params; * } * } * } * ``` * * ### Instead of using the per-transition `$stateParams` object, * inject the current `Transition` (as [[$transition$]]) and use [[Transition.params]] * * ```js * MyController.$inject = ['$transition$']; * function MyController($transition$) { * var username = $transition$.params().username; * // .. do something with username * } * ``` * * --- * * This object can be injected into other services. * * #### Deprecated Example: * ```js * SomeService.$inject = ['$http', '$stateParams']; * function SomeService($http, $stateParams) { * return { * getUser: function() { * return $http.get('/api/users/' + $stateParams.username); * } * } * }; * angular.service('SomeService', SomeService); * ``` * @deprecated */ /** * # Angular 1 Directives * * These are the directives included in UI-Router for Angular 1. * These directives are used in templates to create viewports and link/navigate to states. * * @ng1api * @preferred * @module directives */ /** for typedoc */ /** @hidden */ function parseStateRef(ref) { var parsed; var paramsOnly = ref.match(/^\s*({[^}]*})\s*$/); if (paramsOnly) ref = '(' + paramsOnly[1] + ')'; parsed = ref.replace(/\n/g, ' ').match(/^\s*([^(]*?)\s*(\((.*)\))?\s*$/); if (!parsed || parsed.length !== 4) throw new Error("Invalid state ref '" + ref + "'"); return { state: parsed[1] || null, paramExpr: parsed[3] || null }; } /** @hidden */ function stateContext(el) { var $uiView = el.parent().inheritedData('$uiView'); var path = core.parse('$cfg.path')($uiView); return path ? core.tail(path).state.name : undefined; } /** @hidden */ function processedDef($state, $element, def) { var uiState = def.uiState || $state.current.name; var uiStateOpts = core.extend(defaultOpts($element, $state), def.uiStateOpts || {}); var href = $state.href(uiState, def.uiStateParams, uiStateOpts); return { uiState: uiState, uiStateParams: def.uiStateParams, uiStateOpts: uiStateOpts, href: href }; } /** @hidden */ function getTypeInfo(el) { // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute. var isSvg = Object.prototype.toString.call(el.prop('href')) === '[object SVGAnimatedString]'; var isForm = el[0].nodeName === 'FORM'; return { attr: isForm ? 'action' : (isSvg ? 'xlink:href' : 'href'), isAnchor: el.prop('tagName').toUpperCase() === 'A', clickable: !isForm, }; } /** @hidden */ function clickHook(el, $state, $timeout, type, getDef) { return function (e) { var button = e.which || e.button, target = getDef(); if (!(button > 1 || e.ctrlKey || e.metaKey || e.shiftKey || el.attr('target'))) { // HACK: This is to allow ng-clicks to be processed before the transition is initiated: var transition_1 = $timeout(function () { $state.go(target.uiState, target.uiStateParams, target.uiStateOpts); }); e.preventDefault(); // if the state has no URL, ignore one preventDefault from the <a> directive. var ignorePreventDefaultCount_1 = type.isAnchor && !target.href ? 1 : 0; e.preventDefault = function () { if (ignorePreventDefaultCount_1-- <= 0) $timeout.cancel(transition_1); }; } }; } /** @hidden */ function defaultOpts(el, $state) { return { relative: stateContext(el) || $state.$current, inherit: true, source: 'sref', }; } /** @hidden */ function bindEvents(element, scope, hookFn, uiStateOpts) { var events; if (uiStateOpts) { events = uiStateOpts.events; } if (!core.isArray(events)) { events = ['click']; } var on = element.on ? 'on' : 'bind'; for (var _i = 0, events_1 = events; _i < events_1.length; _i++) { var event_1 = events_1[_i]; element[on](event_1, hookFn); } scope.$on('$destroy', function () { var off = element.off ? 'off' : 'unbind'; for (var _i = 0, events_2 = events; _i < events_2.length; _i++) { var event_2 = events_2[_i]; element[off](event_2, hookFn); } }); } /** * `ui-sref`: A directive for linking to a state * * A directive which links to a state (and optionally, parameters). * When clicked, this directive activates the linked state with the supplied parameter values. * * ### Linked State * The attribute value of the `ui-sref` is the name of the state to link to. * * #### Example: * This will activate the `home` state when the link is clicked. * ```html * <a ui-sref="home">Home</a> * ``` * * ### Relative Links * You can also use relative state paths within `ui-sref`, just like a relative path passed to `$state.go()` ([[StateService.go]]). * You just need to be aware that the path is relative to the state that *created* the link. * This allows a state to create a relative `ui-sref` which always targets the same destination. * * #### Example: * Both these links are relative to the parent state, even when a child state is currently active. * ```html * <a ui-sref=".child1">child 1 state</a> * <a ui-sref=".child2">child 2 state</a> * ``` * * This link activates the parent state. * ```html * <a ui-sref="^">Return</a> * ``` * * ### hrefs * If the linked state has a URL, the directive will automatically generate and * update the `href` attribute (using the [[StateService.href]] method). * * #### Example: * Assuming the `users` state has a url of `/users/` * ```html * <a ui-sref="users" href="/users/">Users</a> * ``` * * ### Parameter Values * In addition to the state name, a `ui-sref` can include parameter values which are applied when activating the state. * Param values can be provided in the `ui-sref` value after the state name, enclosed by parentheses. * The content inside the parentheses is an expression, evaluated to the parameter values. * * #### Example: * This example renders a list of links to users. * The state's `userId` parameter value comes from each user's `user.id` property. * ```html * <li ng-repeat="user in users"> * <a ui-sref="users.detail({ userId: user.id })">{{ user.displayName }}</a> * </li> * ``` * * Note: * The parameter values expression is `$watch`ed for updates. * * ### Transition Options * You can specify [[TransitionOptions]] to pass to [[StateService.go]] by using the `ui-sref-opts` attribute. * Options are restricted to `location`, `inherit`, and `reload`. * * #### Example: * ```html * <a ui-sref="home" ui-sref-opts="{ reload: true }">Home</a> * ``` * * ### Other DOM Events * * You can also customize which DOM events to respond to (instead of `click`) by * providing an `events` array in the `ui-sref-opts` attribute. * * #### Example: * ```html * <input type="text" ui-sref="contacts" ui-sref-opts="{ events: ['change', 'blur'] }"> * ``` * * ### Highlighting the active link * This directive can be used in conjunction with [[uiSrefActive]] to highlight the active link. * * ### Examples * If you have the following template: * * ```html * <a ui-sref="home">Home</a> * <a ui-sref="about">About</a> * <a ui-sref="{page: 2}">Next page</a> * * <ul> * <li ng-repeat="contact in contacts"> * <a ui-sref="contacts.detail({ id: contact.id })">{{ contact.name }}</a> * </li> * </ul> * ``` * * Then (assuming the current state is `contacts`) the rendered html including hrefs would be: * * ```html * <a href="#/home" ui-sref="home">Home</a> * <a href="#/about" ui-sref="about">About</a> * <a href="#/contacts?page=2" ui-sref="{page: 2}">Next page</a> * * <ul> * <li ng-repeat="contact in contacts"> * <a href="#/contacts/1" ui-sref="contacts.detail({ id: contact.id })">Joe</a> * </li> * <li ng-repeat="contact in contacts"> * <a href="#/contacts/2" ui-sref="contacts.detail({ id: contact.id })">Alice</a> * </li> * <li ng-repeat="contact in contacts"> * <a href="#/contacts/3" ui-sref="contacts.detail({ id: contact.id })">Bob</a> * </li> * </ul> * * <a href="#/home" ui-sref="home" ui-sref-opts="{reload: true}">Home</a> * ``` * * ### Notes * * - You can use `ui-sref` to change **only the parameter values** by omitting the state name and parentheses. * #### Example: * Sets the `lang` parameter to `en` and remains on the same state. * * ```html * <a ui-sref="{ lang: 'en' }">English</a> * ``` * * - A middle-click, right-click, or ctrl-click is handled (natively) by the browser to open the href in a new window, for example. * * - Unlike the parameter values expression, the state name is not `$watch`ed (for performance reasons). * If you need to dynamically update the state being linked to, use the fully dynamic [[uiState]] directive. */ var uiSrefDirective; uiSrefDirective = ['$uiRouter', '$timeout', function $StateRefDirective($uiRouter, $timeout) { var $state = $uiRouter.stateService; return { restrict: 'A', require: ['?^uiSrefActive', '?^uiSrefActiveEq'], link: function (scope, element, attrs, uiSrefActive) { var type = getTypeInfo(element); var active = uiSrefActive[1] || uiSrefActive[0]; var unlinkInfoFn = null; var hookFn; var rawDef = {}; var getDef = function () { return processedDef($state, element, rawDef); }; var ref = parseStateRef(attrs.ui