diff --git a/package.json b/package.json index f41b69a4b..369ef8174 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "module": "lib-esm/index.js", "typings": "lib/index.d.ts", "dependencies": { - "@uirouter/core": "6.0.7" + "@uirouter/core": "v7beta" }, "peerDependencies": { "angular": ">=1.2.0" @@ -129,11 +129,11 @@ "Interfaces": [ "Ng1StateDeclaration" ], - "Components": [ - "uiView", - "UISref", - "UISrefActive", - "uiStateDirective" + "Directives": [ + { "name": "uiView", "kindString": "Variable" }, + { "name": "uiSref", "kindString": "Variable" }, + { "name": "uiSrefActive", "kindString": "Variable" }, + { "name": "uiState", "kindString": "Variable" } ], "Other": [ "Transition", @@ -144,7 +144,7 @@ { "pkg": "@uirouter/core", "repo": "https://github.com/ui-router/core", - "branch": "master" + "branch": "v7" } ] } diff --git a/src/directives/stateDirectives.ts b/src/directives/stateDirectives.ts index 07540e813..48f9aa58a 100644 --- a/src/directives/stateDirectives.ts +++ b/src/directives/stateDirectives.ts @@ -281,8 +281,8 @@ function bindEvents(element: IAugmentedJQuery, scope: IScope, hookFn: EventListe * - 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. */ -let uiSrefDirective: ng1_directive; -uiSrefDirective = [ +export let uiSref: ng1_directive; +uiSref = [ '$uiRouter', '$timeout', function $StateRefDirective($uiRouter: UIRouter, $timeout: ITimeoutService) { @@ -419,8 +419,8 @@ uiSrefDirective = [ * - A middle-click, right-click, or ctrl-click is handled (natively) by the browser to open the href in a new window, for example. * ``` */ -let uiStateDirective: ng1_directive; -uiStateDirective = [ +export let uiState: ng1_directive; +uiState = [ '$uiRouter', '$timeout', function $StateRefDynamicDirective($uiRouter: UIRouter, $timeout: ITimeoutService) { @@ -569,8 +569,8 @@ uiStateDirective = [ * * - Multiple classes may be specified in a space-separated format: `ui-sref-active='class1 class2 class3'` */ -let uiSrefActiveDirective: ng1_directive; -uiSrefActiveDirective = [ +export let uiSrefActive: ng1_directive; +uiSrefActive = [ '$state', '$stateParams', '$interpolate', @@ -726,7 +726,7 @@ interface StateData { angular .module('ui.router.state') - .directive('uiSref', uiSrefDirective) - .directive('uiSrefActive', uiSrefActiveDirective) - .directive('uiSrefActiveEq', uiSrefActiveDirective) - .directive('uiState', uiStateDirective); + .directive('uiSref', uiSref) + .directive('uiSrefActive', uiSrefActive) + .directive('uiSrefActiveEq', uiSrefActive) + .directive('uiState', uiState); diff --git a/src/directives/viewDirective.ts b/src/directives/viewDirective.ts index c8cd41662..452420792 100644 --- a/src/directives/viewDirective.ts +++ b/src/directives/viewDirective.ts @@ -1,7 +1,7 @@ /** @publicapi @module directives */ /** */ import { $QLike, - ActiveUIView, + Category, extend, filter, HookRegOptions, @@ -9,6 +9,7 @@ import { isFunction, isString, kebobString, + maxLength, noop, Obj, Param, @@ -21,9 +22,13 @@ import { Transition, TransitionService, TypedMap, + UIViewPortalRenderCommand, unnestR, + ViewConfig, + ViewContext, ViewService, } from '@uirouter/core'; +import { UIViewPortalRegistration } from '@uirouter/core/lib/view/interface'; import { IAugmentedJQuery, IInterpolateService, IScope, ITranscludeFunction } from 'angular'; import { ng as angular } from '../angular'; import { Ng1Controller, Ng1StateDeclaration } from '../interface'; @@ -33,8 +38,9 @@ import { ng1_directive } from './stateDirectives'; /** @hidden */ export type UIViewData = { - $cfg: Ng1ViewConfig; - $uiView: ActiveUIView; + $renderCommand: UIViewPortalRenderCommand; + $cfg: Ng1ViewConfig; // for backwards compat + $uiView: ActiveUIView; // for backwards compat }; /** @hidden */ @@ -170,6 +176,26 @@ export type UIViewAnimData = { * ``` */ export let uiView: ng1_directive; + +// No longer exported from @uirouter/core +// for backwards compat only +export interface ActiveUIView { + /** type of framework, e.g., "ng1" or "ng2" */ + $type: string; + /** An auto-incremented id */ + id: number | string; + /** The ui-view short name */ + name: string; + /** The ui-view's fully qualified name */ + fqn: string; + /** The ViewConfig that is currently loaded into the ui-view */ + config: ViewConfig; + /** The state context in which the ui-view tag was created. */ + creationContext: ViewContext; + /** A callback that should apply a ViewConfig (or clear the ui-view, if config is undefined) */ + configUpdated: (config: ViewConfig) => void; +} + // eslint-disable-next-line prefer-const uiView = [ '$view', @@ -203,17 +229,12 @@ uiView = [ }; } - function configsEqual(config1: Ng1ViewConfig, config2: Ng1ViewConfig) { - return config1 === config2; - } - const rootData = { $cfg: { viewDecl: { $context: $view._pluginapi._rootViewContext() } }, $uiView: {}, }; const directive = { - count: 0, restrict: 'ECA', terminal: true, priority: 400, @@ -226,62 +247,63 @@ uiView = [ inherited = $element.inheritedData('$uiView') || rootData, name = $interpolate(attrs['uiView'] || attrs['name'] || '')(scope) || '$default'; - let previousEl: JQuery, currentEl: JQuery, currentScope: IScope, viewConfig: Ng1ViewConfig; + let previousEl: JQuery, currentEl: JQuery, currentScope: IScope; const activeUIView: ActiveUIView = { $type: 'ng1', - id: directive.count++, // Global sequential ID for ui-view tags added to DOM + id: null, // filled in later name: name, // ui-view name (
fqn: inherited.$uiView.fqn ? inherited.$uiView.fqn + '.' + name : name, // fully qualified name, describes location in DOM config: null, // The ViewConfig loaded (from a state.views definition) - configUpdated: configUpdatedCallback, // Called when the matching ViewConfig changes - get creationContext() { - // The context in which this ui-view "tag" was created - const fromParentTagConfig = parse('$cfg.viewDecl.$context')(inherited); - // Allow - // See https://github.com/angular-ui/ui-router/issues/3355 - const fromParentTag = parse('$uiView.creationContext')(inherited); - return fromParentTagConfig || fromParentTag; - }, + configUpdated: undefined, // unused in core + creationContext: undefined, // unused in core + // configUpdated: configUpdatedCallback, // Called when the matching ViewConfig changes + // get creationContext() { + // The context in which this ui-view "tag" was created + // const fromParentTagConfig = parse('$cfg.viewDecl.$context')(inherited); + // Allow + // See https://github.com/angular-ui/ui-router/issues/3355 + // const fromParentTag = parse('$uiView.creationContext')(inherited); + // return fromParentTagConfig || fromParentTag; + // }, }; - trace.traceUIViewEvent('Linking', activeUIView); - - function configUpdatedCallback(config?: Ng1ViewConfig) { - if (config && !(config instanceof Ng1ViewConfig)) return; - if (configsEqual(viewConfig, config)) return; - trace.traceUIViewConfigUpdated(activeUIView, config && config.viewDecl && config.viewDecl.$context); - - viewConfig = config; - updateView(config); - } + const uiViewId = $view._pluginapi._registerView( + 'ng1', + inherited.$uiView.id, + name, + renderContentIntoUIViewPortal + ); - $element.data('$uiView', { $uiView: activeUIView }); + const traceUiViewEvent = (message: string, extra?: string) => + $view._pluginapi._traceUIViewEvent(uiViewId, message, extra); - updateView(); + traceUiViewEvent('Linking'); - const unregister = $view.registerUIView(activeUIView); scope.$on('$destroy', function () { - trace.traceUIViewEvent('Destroying/Unregistering', activeUIView); - unregister(); + traceUiViewEvent('Destroying/Unregistering'); + $view._pluginapi._deregisterView(uiViewId); }); + // backwards compat + $element.data('$uiView', { $uiView: activeUIView }); + function cleanupLastView() { if (previousEl) { - trace.traceUIViewEvent('Removing (previous) el', previousEl.data('$uiView')); + traceUiViewEvent('Removing (previous) el', previousEl.data('$uiView')); previousEl.remove(); previousEl = null; } if (currentScope) { - trace.traceUIViewEvent('Destroying scope', activeUIView); + traceUiViewEvent('Destroying scope'); currentScope.$destroy(); currentScope = null; } if (currentEl) { const _viewData = currentEl.data('$uiViewAnim'); - trace.traceUIViewEvent('Animate out', _viewData); + traceUiViewEvent('Animate out', _viewData); renderer.leave(currentEl, function () { _viewData.$$animLeave.resolve(); previousEl = null; @@ -292,13 +314,27 @@ uiView = [ } } - function updateView(config?: Ng1ViewConfig) { + function renderContentIntoUIViewPortal(renderCommand: UIViewPortalRenderCommand) { + const renderCmdViewId = renderCommand.uiViewPortalRegistration.id; + if (isString(activeUIView.id) && activeUIView.id !== renderCmdViewId) { + throw new Error( + `Received a render command for wrong UIView. Render command id: ${renderCmdViewId}, but this UIView id: ${activeUIView.id}` + ); + } + + activeUIView.id = renderCmdViewId; + const viewConfig = + renderCommand.portalContentType === 'RENDER_ROUTED_VIEW' + ? (renderCommand.uiViewPortalRegistration.viewConfig as Ng1ViewConfig) + : undefined; + const newScope = scope.$new(); const animEnter = $q.defer(), animLeave = $q.defer(); const $uiViewData: UIViewData = { - $cfg: config, + $renderCommand: renderCommand, + $cfg: viewConfig, $uiView: activeUIView, }; @@ -349,7 +385,7 @@ uiView = [ * * @param {Object} event Event object. */ - currentScope.$emit('$viewContentLoaded', config || viewConfig); + currentScope.$emit('$viewContentLoaded', viewConfig); currentScope.$eval(onloadExp); } }; @@ -381,17 +417,27 @@ function $ViewDirectiveFill( tElement.empty(); return function (scope: IScope, $element: JQuery) { - const data: UIViewData = $element.data('$uiView'); - if (!data) { + const data: UIViewData = $element.data('$uiView') || {}; + const { $renderCommand, $uiView } = data; + if (!$renderCommand || $renderCommand.portalContentType === 'RENDER_DEFAULT_CONTENT') { $element.html(initial); $compile($element.contents() as any)(scope); return; + } else if ($renderCommand.portalContentType === 'RENDER_INTEROP_DIV') { + $element.html('
'); + $renderCommand.giveDiv($element.find('div')[0]); + return; } - const cfg: Ng1ViewConfig = data.$cfg || { viewDecl: {}, getTemplate: noop }; + const { uiViewPortalRegistration } = $renderCommand; + const { viewConfig } = uiViewPortalRegistration; + const cfg: Ng1ViewConfig = viewConfig || ({ viewDecl: {}, getTemplate: noop } as any); const resolveCtx: ResolveContext = cfg.path && new ResolveContext(cfg.path); $element.html(cfg.getTemplate($element, resolveCtx) || initial); - trace.traceUIViewFill(data.$uiView, $element.html()); + + if (trace.enabled(Category.UIVIEW)) { + $view._pluginapi._traceUIViewEvent($uiView.id as string, 'Fill', ` with: ${maxLength(200, $element.html())}`); + } const link = $compile($element.contents() as any); const controller = cfg.controller as angular.IControllerService; diff --git a/src/services.ts b/src/services.ts index 6d8decb35..c31df5e75 100644 --- a/src/services.ts +++ b/src/services.ts @@ -146,13 +146,6 @@ const getUrlRouterProvider = (uiRouter: UIRouter) => (uiRouter.urlRouterProvider // $urlRouter service and $urlRouterProvider const getStateProvider = () => extend(router.stateProvider, { $get: () => router.stateService }); -watchDigests.$inject = ['$rootScope']; -export function watchDigests($rootScope: IRootScopeService) { - $rootScope.$watch(function () { - trace.approximateDigests++; - }); -} - mod_init.provider('$uiRouter', $uiRouterProvider); mod_rtr.provider('$urlRouter', ['$uiRouterProvider', getUrlRouterProvider]); mod_util.provider('$urlService', getProviderFor('urlService')); @@ -167,7 +160,6 @@ mod_state.factory('$stateParams', ['$uiRouter', ($uiRouter: UIRouter) => $uiRout mod_main.factory('$view', () => router.viewService); mod_main.service('$trace', () => trace); -mod_main.run(watchDigests); mod_util.run(['$urlMatcherFactory', function ($urlMatcherFactory: UrlMatcherFactory) {}]); mod_state.run(['$state', function ($state: StateService) {}]); mod_rtr.run(['$urlRouter', function ($urlRouter: UrlRouter) {}]); diff --git a/test/stateSpec.ts b/test/stateSpec.ts index 6c9629a7d..ffc4fedf5 100644 --- a/test/stateSpec.ts +++ b/test/stateSpec.ts @@ -928,6 +928,7 @@ describe('state', function () { $rootScope, $compile ) { + debugger; $compile('
')($rootScope); $state.transitionTo('logA.logB.logC'); $q.flush(); diff --git a/yarn.lock b/yarn.lock index 5fd398a23..7a5851e53 100644 --- a/yarn.lock +++ b/yarn.lock @@ -735,10 +735,10 @@ dependencies: eslint-visitor-keys "^1.1.0" -"@uirouter/core@6.0.7": - version "6.0.7" - resolved "https://registry.yarnpkg.com/@uirouter/core/-/core-6.0.7.tgz#a66743dceb13a56d8908474ff891d63e5d5a2b01" - integrity sha512-KUTJxL+6q0PiBnFx4/Z+Hsyg0pSGiaW5yZQeJmUxknecjpTbnXkLU8H2EqRn9N2B+qDRa7Jg8RcgeNDPY72O1w== +"@uirouter/core@v7beta": + version "7.0.0-beta.3" + resolved "https://registry.yarnpkg.com/@uirouter/core/-/core-7.0.0-beta.3.tgz#a4df98267d5aa4f512b545cc1535f20192270f8e" + integrity sha512-T4UT0V2MgadE+Z/ZaB8bc/QhZdvw0foQWWb/BrVCxoKDZJMghxAk7/7PI3KGRTBvJkk+Py0n2INafwGlPH4M+w== "@uirouter/publish-scripts@2.5.5": version "2.5.5"