UNPKG

@craftercms/studio-ui

Version:

Services, components, models & utils to build CrafterCMS authoring extensions.

176 lines (174 loc) 6.63 kB
/* * Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ import { createLookupTable } from './object'; import Jabber from 'jabber'; import { generatePlaceholderImageDataUrl } from './content'; import { toColor } from './string'; // TODO: Not used. export function getRelatedContentTypeIds(contentType) { return Object.values(contentType.fields).reduce((accumulator, field) => { if ( field.type === 'array' && field.validations != null && 'validations' in field && 'allowedContentTypes' in field.validations ) { Object.keys(field.validations.allowedContentTypes.value).forEach( (ctid) => !accumulator.includes(ctid) && accumulator.push(ctid) ); } return accumulator; }, []); } export function isGroupItem(contentType, fieldId) { return fieldId.includes('.'); } export function isComponentHolder(contentType, fieldId) { return getField(contentType, fieldId).type === 'node-selector'; } export function isGroup(contentType, fieldId) { return getField(contentType, fieldId).type === 'repeat'; } export function doesFieldAccept(contentType, fieldId) { // const field = ContentType.getField(contentType, fieldId); throw new Error('[doesFieldAccept] Not implemented'); } export function getField(type, fieldId, contentTypes) { const fields = fieldId.split('.'); let accumulator = Array.isArray(type.fields) ? createLookupTable(type.fields) : type.fields; let parsedFieldId = []; fields.forEach((field) => { parsedFieldId.push(field); if (accumulator.type === 'node-selector') { if (!contentTypes) { throw new Error( `Content types not provided to content type helper \`getField\` method. ` + `Unable to retrieve the field \`${fieldId}\` without full list of content types.` ); } const contentTypeWithTargetFieldId = Object.keys(accumulator.validations.allowedContentTypes.value).find((ct) => Boolean(contentTypes[ct].fields[field]) ); accumulator = contentTypes[contentTypeWithTargetFieldId].fields[field]; } else { if (accumulator.type === 'repeat') { // For repeat groups, the field inside the repeat group field will be // under {repeatName}.fields.{fieldName}. To abstract this complexity from devs // we parse it here. accumulator = accumulator.fields[field]; } else { accumulator = accumulator[field]; } } }); return accumulator; } export function getFields(type, ...ids) { return ids.map((id) => getField(type, id)); } export function getFieldsByType(contentType, fieldType) { return Object.values(contentType.fields).filter((field) => field.type === fieldType); } // TODO: See variable.js for additional case items to possibly include here export function getDefaultValue(field) { if (field.defaultValue) { return field.defaultValue; } else if (field.validations.required?.value) { switch (field.type) { case 'image': { const width = field.validations.width?.value ?? field.validations.minWidth?.value ?? 150; const height = field.validations.height?.value ?? field.validations.minHeight?.value ?? width; return generatePlaceholderImageDataUrl({ width, height, font: `24px Arial`, text: width > 100 ? `${width} x ${height}` : ':)', textPositionY: height / 2, textPositionX: width / 2 }); } case 'text': case 'textarea': { const maxLength = parseInt(field.validations.maxLength?.value); const textGen = new Jabber(); return maxLength ? `${textGen.createParagraph(50).substring(0, maxLength)}.`.replace(/\.+/, '.') : textGen.createParagraph(10); } case 'html': { const textGen = new Jabber(); return textGen.createParagraph(10); } case 'numeric-input': { return field.validations.minValue?.value ?? 1; } case 'boolean': { return 'false'; } case 'date-time': { return new Date().toISOString(); } case 'repeat': { const repeat = []; if (field.validations.minCount && field.fields) { new Array(field.validations.minCount).fill(null).forEach(() => { const item = {}; for (const subFieldId in field.fields) { item[subFieldId] = getDefaultValue(field.fields[subFieldId]); } repeat.push(item); }); } return repeat; } case 'node-selector': // TODO: CHECK MIN/MAX COUNT return []; default: { return null; } } } } // TODO: This could be used to more generic location. What it does is not specific to content types. /** * It takes a string and generates a colour and contrast colour for it. * Applies a darkening effect when the theme is dark. */ export function getAvatarWithIconColors(colourBaseString, theme, darkenFn) { if (!(colourBaseString && theme && darkenFn)) { return { backgroundColor: '', textColor: '' }; } const base = toColor(colourBaseString); const backgroundColor = theme.palette.mode === 'dark' ? darkenFn(base, 0.2) : base; const textColor = theme.palette.getContrastText(base); return { backgroundColor, textColor }; }