UNPKG

scrivito

Version:

Scrivito is a professional, yet easy to use SaaS Enterprise Content Management Service, built for digital agencies and medium to large businesses. It is completely maintenance-free, cost-effective, and has unprecedented performance and security.

382 lines (324 loc) 9.53 kB
import escape from 'lodash-es/escape'; import isDate from 'lodash-es/isDate'; import { currentSiteId } from 'scrivito_sdk/app_support/current_page'; import { getDetailsPageAndQuery } from 'scrivito_sdk/app_support/get_details_page_url'; import { hasComponent } from 'scrivito_sdk/app_support/has_component'; import { InternalError, assumeString, convertToFloat, convertToInteger, isPresent, logError, } from 'scrivito_sdk/common'; import { DataItem, DataScope, DataStack, applyDataLocator, } from 'scrivito_sdk/data_integration'; import { BasicLink, BasicObj, BasicTypeInfo, BasicWidget, CmsAttributeType, getContentValueOrConnection, isContentConnection, } from 'scrivito_sdk/models'; import { useDataStackOrThrow } from 'scrivito_sdk/react/data_context_container'; import { AttributeDefinitions, AttributeValueOf, Obj, Schema, Widget, unwrapAppClass, wrapInAppClass, } from 'scrivito_sdk/realm'; /** @public */ export function useContent<A extends keyof AttributeDefinitions & string>( content: Obj | Widget, attributeName: string ): AttributeValueOf<AttributeDefinitions, A> { return resolveContent(content, attributeName, useDataStackOrThrow()); } // Exported for test purpose only export function resolveContent( content: Obj | Widget, attributeName: string, dataStack: DataStack ): ReturnType<typeof useContent> { const typeInfo = getTypeInfo(content, attributeName); if (!typeInfo) return null; return wrapInAppClass( resolveBasicContent( unwrapAppClass(content), attributeName, typeInfo, dataStack ) ); } function resolveBasicContent<T extends CmsAttributeType>( basicContent: BasicObj | BasicWidget, attributeName: string, typeInfo: BasicTypeInfo<T>, dataStack: DataStack ) { const valueOrConnection = getContentValueOrConnection( basicContent, attributeName, typeInfo ); if (isContentConnection(valueOrConnection)) { return toBasicValue( applyDataLocator(dataStack, valueOrConnection[1]), typeInfo ); } return valueOrConnection[1]; } function toBasicValue<T extends CmsAttributeType>( dataScope: DataScope, typeInfo: BasicTypeInfo<T> ) { const itemAttribute = dataScope.dataItemAttribute(); if (itemAttribute) { return itemAttributeToBasicValue( itemAttribute.dataItem(), itemAttribute.attributeName(), typeInfo ); } const dataItem = dataScope.dataItem(); if (dataItem) return itemToBasicValue(dataItem, typeInfo[0]); return scopeToBasicValue(dataScope, typeInfo); } function scopeToBasicValue<T extends CmsAttributeType>( dataScope: DataScope, [attributeType]: BasicTypeInfo<T> ) { const items = dataScope.take(); if (attributeType === 'linklist') { return items.map(itemToLink).filter(isPresent); } if (attributeType === 'referencelist') { return items.map(itemToReference).filter(isPresent); } return toDefaultValue(attributeType); } function itemAttributeToBasicValue<T extends CmsAttributeType>( dataItem: DataItem, attributeName: string, typeInfo: BasicTypeInfo<T> ) { const obj = dataItem.obj(); if (obj) { return objAttributeToBasicValue(obj, attributeName, typeInfo); } return externalAttributeToBasicValue(dataItem, attributeName, typeInfo); } function itemToBasicValue<T extends CmsAttributeType>( dataItem: DataItem, attributeType: T ) { switch (attributeType) { case 'reference': return itemToReference(dataItem); case 'referencelist': return toList(itemToReference(dataItem)); case 'link': return itemToLink(dataItem); case 'linklist': return toList(itemToLink(dataItem)); default: return null; } } function itemToReference(dataItem: DataItem) { return unwrapAppClass(dataItem.obj()) || null; } function itemToLink(dataItem: DataItem) { const obj = dataItem.obj(); let link: BasicLink | null = null; if (obj && (hasComponent(obj.objClass()) || obj.isBinary())) { link = new BasicLink({ objId: obj.id() }); } const detailsPageAndQuery = getDetailsPageAndQuery(dataItem, currentSiteId()); if (detailsPageAndQuery) { const { detailsPage, queryString } = detailsPageAndQuery; link = new BasicLink({ objId: detailsPage.id(), query: queryString }); } return link; } function toList<T>(value: T | null): [T] | [] { return value === null ? [] : [value]; } function objAttributeToBasicValue<T extends CmsAttributeType>( obj: Obj, attributeName: string, typeInfo: BasicTypeInfo<T> ) { const basicObj = unwrapAppClass(obj); if (getTypeInfo(obj, attributeName)?.[0] === 'datalocator') { logError('Connecting a "datalocator" attribute is not possible'); return null; } return basicObj.get(attributeName, typeInfo); } function externalAttributeToBasicValue<T extends CmsAttributeType>( dataItem: DataItem, attributeName: string, typeInfo: BasicTypeInfo<T> ) { const externalAttributeType = dataItem.dataClass().attributeDefinitions()[ attributeName ]?.[0]; const unknownValue = dataItem.get(attributeName); if (externalAttributeType === 'string') { return externalStringAttributeToBasicValue(unknownValue, typeInfo); } if (externalAttributeType === 'enum') { return externalEnumAttributeToBasicValue(unknownValue, typeInfo); } if (externalAttributeType === 'number') { return externalNumberAttributeToBasicValue(unknownValue, typeInfo); } if (externalAttributeType === 'boolean') { return externalBooleanAttributeToBasicValue(unknownValue, typeInfo); } if (externalAttributeType === 'date') { return externalDateAttributeToBasicValue(unknownValue, typeInfo); } if (externalAttributeType === 'reference') { return externalReferenceAttributeToBasicValue(unknownValue, typeInfo); } return null; } function externalStringAttributeToBasicValue<T extends CmsAttributeType>( unknownValue: unknown, typeInfo: BasicTypeInfo<T> ) { const value = assumeString(unknownValue); const [targetAttributeType, targetTypeInfoConfig] = typeInfo; switch (targetAttributeType) { case 'string': return value; case 'html': return escape(value); case 'enum': return externalStringAttributeToEnumValue(value, targetTypeInfoConfig); case 'multienum': return toList( externalStringAttributeToEnumValue(value, targetTypeInfoConfig) ); case 'stringlist': return toList(value); default: return null; } } function externalEnumAttributeToBasicValue<T extends CmsAttributeType>( unknownValue: unknown, typeInfo: BasicTypeInfo<T> ) { const value = assumeStringOrNull(unknownValue); const [targetAttributeType] = typeInfo; if (value === null) { switch (targetAttributeType) { case 'string': return ''; case 'multienum': return []; default: return null; } } return externalStringAttributeToBasicValue(unknownValue, typeInfo); } function externalNumberAttributeToBasicValue<T extends CmsAttributeType>( unknownValue: unknown, typeInfo: BasicTypeInfo<T> ) { const value = assumeNumber(unknownValue); const [targetAttributeType] = typeInfo; switch (targetAttributeType) { case 'float': return convertToFloat(value); case 'integer': return convertToInteger(value); default: return null; } } function externalBooleanAttributeToBasicValue<T extends CmsAttributeType>( unknownValue: unknown, typeInfo: BasicTypeInfo<T> ) { const value = assumeBoolean(unknownValue); const [targetAttributeType] = typeInfo; return targetAttributeType === 'boolean' ? value : toDefaultValue('boolean'); } function externalDateAttributeToBasicValue<T extends CmsAttributeType>( unknownValue: unknown, typeInfo: BasicTypeInfo<T> ) { const value = assumeDateOrNull(unknownValue); const [targetAttributeType] = typeInfo; return targetAttributeType === 'date' || targetAttributeType === 'datetime' ? value : null; } function externalReferenceAttributeToBasicValue<T extends CmsAttributeType>( unknownValue: unknown, typeInfo: BasicTypeInfo<T> ) { if (unknownValue instanceof DataItem) { switch (typeInfo[0]) { case 'link': return itemToLink(unknownValue); case 'linklist': return toList(itemToLink(unknownValue)); default: null; } } return null; } function externalStringAttributeToEnumValue( value: string, typeInfoConfig: BasicTypeInfo<'enum'>[1] ) { return typeInfoConfig.values.includes(value) ? value : null; } function toDefaultValue<T extends CmsAttributeType>(attributeType: T) { switch (attributeType) { case 'linklist': case 'referencelist': return []; case 'boolean': return false; default: return null; } } function getTypeInfo(content: Obj | Widget, attributeName: string) { return Schema.forInstance(content)?.attributes()[attributeName]; } function assumeStringOrNull(value: unknown): string | null { if (value === null || typeof value === 'string') return value; throw new InternalError(); } function assumeBoolean(value: unknown) { if (typeof value === 'boolean') return value; throw new InternalError(); } function assumeNumber(value: unknown) { if (typeof value === 'number') return value; throw new InternalError(); } function assumeDateOrNull(value: unknown): Date | null { if (value === null || isDate(value)) return value; throw new InternalError(); }