X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=src%2Ftemplate%2Fauthorization-request-html.js;h=b23fb9207665077ce54743e39563ff3fe2b9e4a8;hb=f0bf29c75b0fd405ff92fa76f058e61162b87e43;hp=3e312af683721642a18357b1a6e99084aa98daca;hpb=b0103b0d496262c438b40bc20304081dbfe41e73;p=squeep-indie-auther diff --git a/src/template/authorization-request-html.js b/src/template/authorization-request-html.js index 3e312af..b23fb92 100644 --- a/src/template/authorization-request-html.js +++ b/src/template/authorization-request-html.js @@ -1,16 +1,16 @@ 'use strict'; const th = require('./template-helper'); - +const { sessionNavLinks } = require('@squeep/authentication-module'); /** - * @param {Object} hApp - * @param {Object} hApp.properties - * @param {String[]=} hApp.properties.url - * @param {String[]=} hApp.properties.summary - * @param {String[]=} hApp.properties.logo - * @param {String[]=} hApp.properties.name - * @returns {String} + * @param {object} hApp client identifier h-app + * @param {object} hApp.properties properties + * @param {string[]=} hApp.properties.url url + * @param {string[]=} hApp.properties.summary summary + * @param {string[]=} hApp.properties.logo logo + * @param {string[]=} hApp.properties.name name + * @returns {string} span */ function renderClientIdentifierProperties(hApp) { const properties = hApp.properties || {}; @@ -19,13 +19,13 @@ function renderClientIdentifierProperties(hApp) { const { url, summary, logo, name } = properties; parts.push(''); - if (url && url.length) { + if (url?.length) { parts.push(``); } - if (summary && summary.length) { + if (summary?.length) { imgTitle = ` title="${summary[0]}"`; } - if (logo && logo.length) { + if (logo?.length) { let src, alt; if (typeof logo[0] === 'string') { src = logo[0]; @@ -35,10 +35,10 @@ function renderClientIdentifierProperties(hApp) { } parts.push(`${alt}`); } - if (name && name.length) { + if (name?.length) { parts.push(properties['name'][0]); } - if (url && url.length) { + if (url?.length) { parts.push(''); } parts.push(''); @@ -47,20 +47,20 @@ function renderClientIdentifierProperties(hApp) { /** - * @param {Object} clientIdentifier - * @param {Object[]} clientIdentifier.items - * @returns {String} + * @param {object} clientIdentifier client identifier + * @param {object[]} clientIdentifier.items items + * @returns {string} spans */ function renderClientIdentifier(clientIdentifier) { - const hAppEntries = clientIdentifier && clientIdentifier.items || []; + const hAppEntries = clientIdentifier?.items || []; return hAppEntries.map(renderClientIdentifierProperties).join(''); } /** - * @param {String} profile - * @param {Boolean} selected - * @returns {String} + * @param {string} profile profile + * @param {boolean} selected is selected + * @returns {string} option */ function renderProfileOption(profile, selected) { return ``; @@ -68,13 +68,13 @@ function renderProfileOption(profile, selected) { /** - * @param {String[]} availableProfiles - * @param {String} hintProfile - * @returns {String} + * @param {string[]} availableProfiles profiles + * @param {string} hintProfile profile + * @returns {string} fieldset */ function renderProfileFieldset(availableProfiles, hintProfile) { if (!availableProfiles || availableProfiles.length <= 1) { - const profile = availableProfiles && availableProfiles[0] || hintProfile; + const profile = availableProfiles?.[0] || hintProfile; return ``; } return ` @@ -93,12 +93,16 @@ ${availableProfiles.map((profile) => renderProfileOption(profile, profile === hi /** - * @param {ScopeDetails} scope - * @param {String} scope.scope - * @param {String} scope.description - * @param {String[]} scope.profiles - * @param {Boolean} checked - * @returns {String} + * @typedef {object} ScopeDetails + * @property {string} scope scope + * @property {string} description description + * @property {string[]} profiles profiles + */ + +/** + * @param {ScopeDetails} scope scope details + * @param {boolean} checked is checked + * @returns {string} scope li */ function renderScopeCheckboxLI(scope, checked) { let scopeDescription; @@ -109,21 +113,26 @@ function renderScopeCheckboxLI(scope, checked) { scopeDescription = ''; } let profileClass; - if (scope.profiles && scope.profiles.length) { - profileClass = ['profile-scope'].concat(scope.profiles.map((profile) => th.escapeCSS(profile))).join(' '); + if (scope.profiles?.length) { + profileClass = ['profile-scope'].concat(scope.profiles).join(' '); } else { profileClass = ''; } return `
  • - + ${scopeDescription}
  • `; } +/** + * + * @param {ScopeDetails[]=} requestedScopes scope details + * @returns {string} fieldset + */ function renderRequestedScopes(requestedScopes) { - if (!requestedScopes || !requestedScopes.length) { + if (!requestedScopes?.length) { return ''; } return ` @@ -140,8 +149,8 @@ ${requestedScopes.map((scopeDetails) => renderScopeCheckboxLI(scopeDetails, true } /** - * @param {ScopeDetails[]} additionalScopes - * @returns {String} + * @param {ScopeDetails[]} additionalScopes scopes + * @returns {string} fieldset */ function renderAdditionalScopes(additionalScopes) { const parts = []; @@ -165,7 +174,7 @@ ${additionalScopes.map((scopeDetails) => renderScopeCheckboxLI(scopeDetails, fal You may also specify a space-separated list of any additional ad hoc scopes you would like to associate with this authorization request, which were not explicitly requested by the client application. - + `); return parts.join(''); } @@ -173,6 +182,8 @@ ${additionalScopes.map((scopeDetails) => renderScopeCheckboxLI(scopeDetails, fal /** * + * @param {string[]} requestedScopes scopes + * @returns {string} fieldset */ function renderExpiration(requestedScopes) { const tokenableScopes = requestedScopes.filter((s) => !['profile', 'email'].includes(s)); @@ -189,18 +200,10 @@ function renderExpiration(requestedScopes) { \t\t
    \t\t
    \t\t\tSet Expiration -\t\t\t
    \t\t\t\t${radioButton('expires', 'never', 'Never', true)} -\t\t\t
    -\t\t\t
    \t\t\t\t${radioButton('expires', '1d', '1 Day')} -\t\t\t
    -\t\t\t
    \t\t\t\t${radioButton('expires', '1w', '1 Week')} -\t\t\t
    -\t\t\t
    \t\t\t\t${radioButton('expires', '1m', '1 Month')} -\t\t\t
    \t\t\t
    \t\t\t\t${radioButton('expires', 'custom', 'Other:')} \t\t\t\t @@ -210,26 +213,28 @@ function renderExpiration(requestedScopes) { \t\t\t
    \t\t\t\tTokens with expirations may be allowed to be renewed for a fresh token for an amount of time after they expire. \t\t\t
    -\t\t\t
    \t\t\t\t${radioButton('refresh', 'none', 'Not Refreshable', true)} -\t\t\t
    -\t\t\t
    \t\t\t\t${radioButton('refresh', '1d', '1 Day')} -\t\t\t
    -\t\t\t
    \t\t\t\t${radioButton('refresh', '1w', '1 Week')} -\t\t\t
    -\t\t\t
    \t\t\t\t${radioButton('refresh', '1m', '1 Month')} \t\t\t
    \t\t\t\t${radioButton('refresh', 'custom', 'Other:')} \t\t\t\t \t\t\t\t -\t\t\t
    +\t\t\t
    \t\t
    \t`; } +/** + * + * @param {string} name name + * @param {string} value value + * @param {string} label label + * @param {boolean} checked is checked + * @param {number} indent indent + * @returns {string} div + */ function radioButton(name, value, label, checked = false, indent = 0) { const id = `${name}-${value}`; return th.indented(indent, [ @@ -240,35 +245,41 @@ function radioButton(name, value, label, checked = false, indent = 0) { ]).join(''); } +/** + * @alias {object} ScopeIndex + */ + /** * - * @param {Object} ctx - * @param {Object[]} ctx.notifications - * @param {Object} ctx.session - * @param {String[]=} ctx.session.scope - * @param {URL=} ctx.session.me - * @param {String[]} ctx.session.profiles - * @param {ScopeIndex} ctx.session.scopeIndex - * @param {Object} ctx.session.clientIdentifier - * @param {Object[]} ctx.session.clientIdentifier.items - * @param {Object} ctx.session.clientIdentifier.items.properties - * @param {String[]=} ctx.session.clientIdentifier.items.properties.url - * @param {String[]=} ctx.session.clientIdentifier.items.properties.summary - * @param {String[]=} ctx.session.clientIdentifier.items.properties.logo - * @param {String[]=} ctx.session.clientIdentifier.items.properties.name - * @param {String} ctx.session.clientId - * @param {String} ctx.session.persist - * @param {String} ctx.session.redirectUri - * @param {Object} options - * @returns {String} + * @param {object} ctx context + * @param {object[]} ctx.notifications notifications + * @param {object} ctx.session session + * @param {string[]=} ctx.session.scope scopes + * @param {URL=} ctx.session.me profile + * @param {string[]} ctx.session.profiles profiles + * @param {ScopeIndex} ctx.session.scopeIndex scopes structure + * @param {object} ctx.session.clientIdentifier client identifier + * @param {object[]} ctx.session.clientIdentifier.items items + * @param {object} ctx.session.clientIdentifier.items.properties properties + * @param {string[]=} ctx.session.clientIdentifier.items.properties.url url + * @param {string[]=} ctx.session.clientIdentifier.items.properties.summary sumamry + * @param {string[]=} ctx.session.clientIdentifier.items.properties.logo logo + * @param {string[]=} ctx.session.clientIdentifier.items.properties.name name + * @param {string} ctx.session.clientId client id + * @param {string} ctx.session.persist persist + * @param {string} ctx.session.redirectUri redirect + * @param {object} options options + * @returns {string} section */ function mainContent(ctx, options) { // eslint-disable-line no-unused-vars const session = ctx.session || {}; - const hintedProfile = (session.me && session.me.href) || (session.profiles && session.profiles.length && session.profiles[0]) || ''; + const hintedProfile = session.me?.href || session.profiles?.[0] || ''; const scopeIndex = session.scopeIndex || {}; - // Add requested scopes to index, if not already present, - // and de-associate requested scopes from profiles. + /** + * Add requested scopes to index, if not already present, + * and de-associate requested scopes from profiles. + */ const scopes = session.scope || []; scopes.forEach((scopeName) => { if ((scopeName in scopeIndex)) { @@ -296,9 +307,7 @@ function mainContent(ctx, options) { // eslint-disable-line no-unused-vars return [ `
    -\tThe application client -\t${renderClientIdentifier(session.clientIdentifier)} -\tat ${session.clientId} would like to identify you as ${hintedProfile}. +\tThe application client ${renderClientIdentifier(session.clientIdentifier)} at ${session.clientId} would like to identify you as ${hintedProfile || '(unspecified)'}.
    \t \t
    \t
    -\t\tYou will be redirected to ${session.redirectUri}. +\t\tYou will be redirected to ${session.redirectUri}. \t
    `, ]; @@ -325,23 +334,24 @@ function mainContent(ctx, options) { // eslint-disable-line no-unused-vars /** * - * @param {Object} ctx - * @param {Object} ctx.session - * @param {String[]=} ctx.session.scope - * @param {URL=} ctx.session.me - * @param {String[]} ctx.session.profiles - * @param {ScopeIndex} ctx.session.scopeIndex - * @param {Object} ctx.session.clientIdentifier - * @param {String} ctx.session.clientId - * @param {String} ctx.session.persist - * @param {String} ctx.session.redirectUri - * @param {Object} options - * @param {Object} options.manager - * @param {String} options.manager.pageTitle - * @param {String} options.manager.footerEntries - * @returns {String} + * @param {object} ctx context + * @param {object} ctx.session session object + * @param {string[]=} ctx.session.scope scopes + * @param {URL=} ctx.session.me url + * @param {string[]} ctx.session.profiles profiles + * @param {ScopeIndex} ctx.session.scopeIndex scopes structure + * @param {object} ctx.session.clientIdentifier client identifier + * @param {string} ctx.session.clientId client id + * @param {string} ctx.session.persist persist + * @param {string} ctx.session.redirectUri redirect url + * @param {object} options options + * @param {object} options.manager manager options + * @param {string} options.manager.pageTitle page title + * @param {string} options.manager.footerEntries footer entries + * @returns {string} page */ module.exports = (ctx, options) => { + const pagePathLevel = 0; const htmlOptions = { pageTitle: `${options.manager.pageTitle} — Authorization Request`, logoUrl: options.manager.logoUrl, @@ -355,22 +365,23 @@ function queryAll(query, fn) { } function profileSelected(element) { const profileClass = CSS.escape(element.value); - console.log('new profile:', element.value, profileClass); - queryAll('.profile-scope input', (n) => n.setAttribute('disabled', true)); + // queryAll('.profile-scope input', (n) => n.setAttribute('disabled', '')); queryAll('.profile-scope', (n) => n.classList.add('disabled')); const profileQuery = '.profile-scope.' + profileClass; - queryAll(profileQuery + ' input', (n) => n.setAttribute('disabled', false)); + // queryAll(profileQuery + ' input', (n) => n.removeAttribute('disabled')); queryAll(profileQuery, (n) => n.classList.remove('disabled')); } function onLoad() { - return; // The escaped class selection does not seem to work, so ignore it all for now. const profileSelect = document.getElementById('me'); profileSelect.onchange = () => profileSelected(profileSelect); profileSelected(profileSelect); } +window.onload = onLoad; `, ], }; + th.navLinks(pagePathLevel, ctx, htmlOptions); + sessionNavLinks(pagePathLevel, ctx, htmlOptions); const content = mainContent(ctx, options); - return th.htmlPage(0, ctx, htmlOptions, content); + return th.htmlPage(pagePathLevel, ctx, htmlOptions, content); };