diff --git a/static/js/pages/app-view.js b/static/js/pages/app-view.js index 287b5dc70..e4c54a797 100644 --- a/static/js/pages/app-view.js +++ b/static/js/pages/app-view.js @@ -10,7 +10,7 @@ }); }]); - function AppViewCtrl($scope, $routeParams, $location, $timeout, ApiService, UserService, AngularPollChannel, ImageLoaderService, CookieService) { + function AppViewCtrl($scope, $routeParams, $rootScope, ApiService, UtilService) { $scope.namespace = $routeParams.namespace; $scope.name = $routeParams.name; @@ -29,8 +29,13 @@ }; $scope.repositoryResource = ApiService.getRepoAsResource(params).get(function(repo) { - $scope.repository = repo; - $scope.viewScope.repository = repo; + if (repo != undefined) { + $scope.repository = repo; + $scope.viewScope.repository = repo; + + // Update the page description for SEO + $rootScope.description = UtilService.getFirstMarkdownLineAsString(repo.description); + } }); }; diff --git a/static/js/pages/repo-view.js b/static/js/pages/repo-view.js index e66a10248..1081cff71 100644 --- a/static/js/pages/repo-view.js +++ b/static/js/pages/repo-view.js @@ -10,7 +10,8 @@ }); }]); - function RepoViewCtrl($scope, $routeParams, $location, $timeout, ApiService, UserService, AngularPollChannel, ImageLoaderService, CookieService) { + function RepoViewCtrl($scope, $routeParams, $rootScope, $timeout, ApiService, + UserService, AngularPollChannel, ImageLoaderService, UtilService) { $scope.namespace = $routeParams.namespace; $scope.name = $routeParams.name; @@ -59,22 +60,22 @@ }; $scope.repositoryResource = ApiService.getRepoAsResource(params).get(function(repo) { - $scope.repository = repo; - $scope.viewScope.repository = repo; - $scope.publicRepoExperiment = CookieService.get('quay.public-repo-exp') == 'true'; + if (repo != undefined) { + $scope.repository = repo; + $scope.viewScope.repository = repo; - // Flag for new repo page experiment - $scope.newRepoExperiment = $scope.repository.is_public && $scope.user.username != $scope.repository.namespace && $scope.publicRepoExperiment; + // Update the page description for SEO + $rootScope.description = UtilService.getFirstMarkdownLineAsString(repo.description); - // Load the remainder of the data async, so we don't block the initial view from - // showing. - $timeout(function() { - $scope.setTags($routeParams.tag); + // Load the remainder of the data async, so we don't block the initial view from showing + $timeout(function() { + $scope.setTags($routeParams.tag); - // Track builds. - buildPollChannel = AngularPollChannel.create($scope, loadRepositoryBuilds, 30000 /* 30s */); - buildPollChannel.start(); - }, 10); + // Track builds. + buildPollChannel = AngularPollChannel.create($scope, loadRepositoryBuilds, 30000 /* 30s */); + buildPollChannel.start(); + }, 10); + } }); }; diff --git a/static/js/quay-run.ts b/static/js/quay-run.ts index 561a2cca9..3c2eb3499 100644 --- a/static/js/quay-run.ts +++ b/static/js/quay-run.ts @@ -16,21 +16,21 @@ provideRun.$inject = [ 'MetaService', ]; export function provideRun($rootScope: QuayRunScope, - Restangular: any, - PlanService: any, + restangular: any, + planService: any, $http: ng.IHttpService, - CookieService: any, - Features: any, + cookieService: any, + features: any, $anchorScroll: ng.IAnchorScrollService, - MetaService: any): void { + metaService: any): void { const defaultTitle: string = INJECTED_CONFIG['REGISTRY_TITLE'] || 'Quay Container Registry'; // Handle session security. - Restangular.setDefaultRequestParams(['post', 'put', 'remove', 'delete'], + restangular.setDefaultRequestParams(['post', 'put', 'remove', 'delete'], {'_csrf_token': (window).__token || ''}); // Handle session expiration. - Restangular.setErrorInterceptor(function(response) { + restangular.setErrorInterceptor(function(response) { if (response !== undefined && response.status == 503) { ($('#cannotContactService')).modal({}); return false; @@ -59,20 +59,20 @@ export function provideRun($rootScope: QuayRunScope, }); // Check if we need to redirect based on a previously chosen plan. - const result: boolean = PlanService.handleNotedPlan(); + const result: boolean = planService.handleNotedPlan(); // Check to see if we need to show a redirection page. - const redirectUrl: string = CookieService.get('quay.redirectAfterLoad'); - CookieService.clear('quay.redirectAfterLoad'); + const redirectUrl: string = cookieService.get('quay.redirectAfterLoad'); + cookieService.clear('quay.redirectAfterLoad'); if (!result && redirectUrl && redirectUrl.indexOf((window).location.href) == 0) { (window).location = redirectUrl; return; } - $rootScope.$watch('description', function(description: string) { + $rootScope.$watch('description', (description: string) => { if (!description) { - description = `Hosted private docker repositories. Includes full user management and history. + description = `Hosted private Docker repositories. Includes full user management and history. Free for public repositories.`; } @@ -82,18 +82,7 @@ export function provideRun($rootScope: QuayRunScope, $('#descriptionTag').attr('content', description); }); - // Listen for scope changes and update the title and description accordingly. - $rootScope.$watch(function() { - const title: string = MetaService.getTitle($rootScope.currentPage) || defaultTitle; - $rootScope.title = title; - - const description: string = MetaService.getDescription($rootScope.currentPage) || ''; - if ($rootScope.description != description) { - $rootScope.description = description; - } - }); - - $rootScope.$on('$routeChangeSuccess', function(event, current, previous) { + $rootScope.$on('$routeChangeSuccess', (event, current, previous) => { $rootScope.current = current.$$route; $rootScope.currentPage = current; $rootScope.pageClass = ''; @@ -102,7 +91,7 @@ export function provideRun($rootScope: QuayRunScope, var pageClass: string | Function = current.$$route.pageClass || ''; if (typeof pageClass != 'string') { - pageClass = pageClass(Features); + pageClass = pageClass(features); } $rootScope.pageClass = pageClass; @@ -112,6 +101,16 @@ export function provideRun($rootScope: QuayRunScope, $anchorScroll(); }); + // Listen for route changes and update the title and description accordingly. + $rootScope.$on('$routeChangeSuccess', async(event, current, previous) => { + $rootScope.title = metaService.getTitle(current) || defaultTitle; + + const description = await metaService.getDescription(current); + if ($rootScope.description != description) { + $rootScope.description = description; + } + }); + var initallyChecked: boolean = false; (window).__isLoading = function() { if (!initallyChecked) { diff --git a/static/js/services/meta-service.js b/static/js/services/meta-service.js index 944e3aa93..cc7b33d35 100644 --- a/static/js/services/meta-service.js +++ b/static/js/services/meta-service.js @@ -1,8 +1,7 @@ /** * Service which helps set the contents of the tags (and the of a page). */ -angular.module('quay').factory('MetaService', ['$interpolate', 'Config', '$rootScope', '$interval', - function($interpolate, Config, $rootScope, $interval) { +angular.module('quay').factory('MetaService', ['$interpolate', '$timeout', function($interpolate, $timeout) { var metaService = {}; var interpolate = function(page, expr) { @@ -28,12 +27,16 @@ angular.module('quay').factory('MetaService', ['$interpolate', 'Config', '$rootS }; metaService.getDescription = function(page) { - if (!page || !page.$$route) { - return null; - } - - var route = page.$$route; - return interpolate(route && route.description); + return new Promise(function(resolve, reject) { + if (!page || !page.$$route) { + resolve(null); + } else { + // Timeout needed because page.scope is undefined + $timeout(function() { + resolve(interpolate(page, page.$$route.description)); + }, 10); + } + }); }; return metaService; diff --git a/static/js/services/util-service.js b/static/js/services/util-service.js index 131bb0d34..48895dbf4 100644 --- a/static/js/services/util-service.js +++ b/static/js/services/util-service.js @@ -75,6 +75,11 @@ angular.module('quay').factory('UtilService', ['$sanitize', 'markdownConverterFa return ''; }; + utilService.getFirstMarkdownLineAsString = function(commentString) { + return utilService.getFirstMarkdownLineAsText(commentString, false).replace('</p>', '') + .replace('<p>', ''); + }; + utilService.escapeHtmlString = function(text) { var textStr = (text || '').toString(); var adjusted = textStr.replace(/&/g, "&") diff --git a/templates/index.html b/templates/index.html index fa157bd37..47708c030 100644 --- a/templates/index.html +++ b/templates/index.html @@ -7,7 +7,7 @@ {% block added_meta %} <base href="/"> - <meta id="descriptionTag" name="description" content="Quay is the best place to build, store, and distribute your containers. Public repositories are always free."></meta> + <meta id="descriptionTag" name="description" content="Quay is the best place to build, store, and distribute your containers. Public repositories are always free." /> <meta name="google-site-verification" content="GalDznToijTsHYmLjJvE4QaB9uk_IP16aaGDz5D75T4" /> <meta name="google-site-verification" content="oio7ioMILUo9QDflvyFz8pWig1ac2eLq5IGyQuzFMh8" /> diff --git a/webpack.config.js b/webpack.config.js index a179c1ceb..bcca94aa0 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -21,7 +21,7 @@ var config = { module: { rules: [ { - test: /\.ts?$/, + test: /\.ts$/, use: ["ts-loader"], exclude: /node_modules/ },