mirror of
https://gitlab.com/bramw/baserow.git
synced 2024-11-21 23:37:55 +00:00
107 lines
3.3 KiB
JavaScript
107 lines
3.3 KiB
JavaScript
import { compile } from 'path-to-regexp'
|
|
import {
|
|
ALLOWED_LINK_PROTOCOLS,
|
|
PAGE_PARAM_TYPE_VALIDATION_FUNCTIONS,
|
|
} from '@baserow/modules/builder/enums'
|
|
import { ensureString } from '@baserow/modules/core/utils/validator'
|
|
|
|
/**
|
|
* Responsible for generating the data necessary to resolve an application builder
|
|
* element URL. Used by LinkElement and LinkField to generate URLs, based on the
|
|
* designer's navigation type / page / url choices.
|
|
*
|
|
* @param {Object} element The element's properties we'll use for generating the URL.
|
|
* @param {Object} builder A builder application.
|
|
* @param {Array} pages A list of pages of this application.
|
|
* @param {Function} resolveFormula A resolveFormula function we'll use if the
|
|
* element has page parameters which need to be resolved.
|
|
* @param {String} editorMode A builder application's editor mode.
|
|
* @returns {String} A resolved URL.
|
|
*/
|
|
export default function resolveElementUrl(
|
|
element,
|
|
builder,
|
|
pages,
|
|
resolveFormula,
|
|
editorMode
|
|
) {
|
|
let resolvedUrl = ''
|
|
if (element.navigation_type === 'page') {
|
|
if (!isNaN(element.navigate_to_page_id)) {
|
|
const page = pages.find(({ id }) => id === element.navigate_to_page_id)
|
|
|
|
// The builder page list might be empty or the page has been deleted
|
|
if (!page) {
|
|
return resolvedUrl
|
|
}
|
|
|
|
const paramTypeMap = Object.fromEntries(
|
|
page.path_params.map(({ name, type }) => [name, type])
|
|
)
|
|
|
|
const toPath = compile(page.path, { encode: encodeURIComponent })
|
|
const pageParams = Object.fromEntries(
|
|
element.page_parameters.map(({ name, value }) => [
|
|
name,
|
|
PAGE_PARAM_TYPE_VALIDATION_FUNCTIONS[paramTypeMap[name]](
|
|
resolveFormula(value)
|
|
),
|
|
])
|
|
)
|
|
resolvedUrl = toPath(pageParams)
|
|
}
|
|
} else {
|
|
resolvedUrl = ensureString(resolveFormula(element.navigate_to_url))
|
|
}
|
|
resolvedUrl = prefixInternalResolvedUrl(
|
|
resolvedUrl,
|
|
builder,
|
|
element.navigation_type,
|
|
editorMode
|
|
)
|
|
|
|
// If the protocol is a supported one, return early.
|
|
const protocolRegex = /^[A-Za-z]+:/
|
|
if (protocolRegex.test(resolvedUrl)) {
|
|
for (const protocol of ALLOWED_LINK_PROTOCOLS) {
|
|
if (resolvedUrl.toLowerCase().startsWith(protocol)) {
|
|
return resolvedUrl
|
|
}
|
|
}
|
|
|
|
// Disallow unsupported protocols, e.g. `javascript:`
|
|
return ''
|
|
}
|
|
|
|
return resolvedUrl
|
|
}
|
|
|
|
/**
|
|
* Responsible for prefixing a resolvedUrl with the builder application's preview
|
|
* URI, if it meets certain conditions.
|
|
*
|
|
* @param {String} resolvedUrl A URL which `resolveElementUrl` has generated.
|
|
* @param {Object} builder A builder application.
|
|
* @param {String} navigationType An element's `navigation_type` (custom / page).
|
|
* @param {String} editorMode A builder application's editor mode.
|
|
* @returns {String} A URL we may have prefixed with the application's preview URI.
|
|
*/
|
|
export function prefixInternalResolvedUrl(
|
|
resolvedUrl,
|
|
builder,
|
|
navigationType,
|
|
editorMode
|
|
) {
|
|
if (
|
|
resolvedUrl &&
|
|
editorMode === 'preview' &&
|
|
(navigationType === 'page' ||
|
|
(navigationType === 'custom' && resolvedUrl.startsWith('/')))
|
|
) {
|
|
// Add prefix in preview mode for page navigation or custom URL starting with `/`
|
|
return `/builder/${builder.id}/preview${resolvedUrl}`
|
|
} else {
|
|
return resolvedUrl
|
|
}
|
|
}
|