Add template animation editor
This commit is contained in:
+61
-2
@@ -1,6 +1,7 @@
|
||||
// Template data access helpers and region normalization logic.
|
||||
|
||||
const { parseJsonSafe, readFormArray } = require('./utils');
|
||||
const animationPresets = require('../web/public/js/templates/animation-presets');
|
||||
|
||||
function sanitizeBackgroundColor(value) {
|
||||
const raw = String(value || '').trim();
|
||||
@@ -23,6 +24,61 @@ function normalizeTemplateRegionLockRatio(value) {
|
||||
return rawRatio.replace(/\s+/g, '');
|
||||
}
|
||||
|
||||
function normalizeTemplateRegionAnimation(value) {
|
||||
if (animationPresets && typeof animationPresets.normalize === 'function') {
|
||||
return animationPresets.normalize(value);
|
||||
}
|
||||
|
||||
const allowed = new Set(
|
||||
Array.isArray(animationPresets && animationPresets.allValues) && animationPresets.allValues.length
|
||||
? animationPresets.allValues
|
||||
: ['none', 'fadeIn', 'fadeInDown', 'fadeInLeft', 'fadeInRight', 'fadeInUp', 'zoomIn', 'zoomInDown', 'zoomInLeft', 'zoomInRight', 'zoomInUp', 'slideInDown', 'slideInLeft', 'slideInRight', 'slideInUp', 'fadeOut', 'fadeOutDown', 'fadeOutLeft', 'fadeOutRight', 'fadeOutUp', 'zoomOut', 'zoomOutDown', 'zoomOutLeft', 'zoomOutRight', 'zoomOutUp', 'slideOutDown', 'slideOutLeft', 'slideOutRight', 'slideOutUp', 'backInDown', 'backInLeft', 'backInRight', 'backInUp', 'backOutDown', 'backOutLeft', 'backOutRight', 'backOutUp', 'bounceIn', 'bounceInDown', 'bounceInLeft', 'bounceInRight', 'bounceInUp', 'bounceOut', 'bounceOutDown', 'bounceOutLeft', 'bounceOutRight', 'bounceOutUp', 'flip', 'flipInX', 'flipInY', 'flipOutX', 'flipOutY', 'lightSpeedInLeft', 'lightSpeedInRight', 'lightSpeedOutLeft', 'lightSpeedOutRight', 'rotateIn', 'rotateInDownLeft', 'rotateInDownRight', 'rotateInUpLeft', 'rotateInUpRight', 'rotateOut', 'rotateOutDownLeft', 'rotateOutDownRight', 'rotateOutUpLeft', 'rotateOutUpRight', 'hinge', 'jackInTheBox', 'rollIn', 'rollOut', 'flash', 'pulse', 'rubberBand', 'shakeX', 'shakeY', 'headShake', 'swing', 'tada', 'wobble', 'jello', 'heartBeat', 'bounce']
|
||||
);
|
||||
const raw = String(value || '').trim().toLowerCase();
|
||||
return allowed.has(raw) ? raw : 'none';
|
||||
}
|
||||
|
||||
function normalizeTemplateRegionAnimationStep(value, fallbackPreset) {
|
||||
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
||||
const normalized = {};
|
||||
Object.keys(value).forEach((key) => {
|
||||
normalized[key] = value[key];
|
||||
});
|
||||
normalized.preset = normalizeTemplateRegionAnimation(value.preset !== undefined ? value.preset : fallbackPreset || 'none');
|
||||
return normalized;
|
||||
}
|
||||
|
||||
return {
|
||||
preset: normalizeTemplateRegionAnimation(typeof value === 'string' ? value : fallbackPreset || 'none')
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeTemplateRegionAnimationConfig(value) {
|
||||
let raw = value;
|
||||
if (typeof raw === 'string') {
|
||||
const text = String(raw || '').trim();
|
||||
if (!text) {
|
||||
raw = null;
|
||||
} else {
|
||||
try {
|
||||
raw = JSON.parse(text);
|
||||
} catch (_error) {
|
||||
raw = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
||||
raw = {};
|
||||
}
|
||||
|
||||
return {
|
||||
intro: normalizeTemplateRegionAnimationStep(raw.intro, 'none'),
|
||||
outro: normalizeTemplateRegionAnimationStep(raw.outro !== undefined ? raw.outro : raw.out, 'none'),
|
||||
loop: normalizeTemplateRegionAnimationStep(raw.loop, 'none')
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeTemplateRegionName(value) {
|
||||
return String(value || '').trim();
|
||||
}
|
||||
@@ -57,7 +113,7 @@ async function fetchTemplateById(pool, id) {
|
||||
return null;
|
||||
}
|
||||
const template = templates[0];
|
||||
const [regions] = await pool.query('SELECT id, template_id, region_key, region_type, label, lock_ratio, x, y, width, height, z_index, created_at, modified_at, created_by, modified_by FROM c_template_regions WHERE template_id = ? ORDER BY z_index ASC, id ASC', [id]);
|
||||
const [regions] = await pool.query('SELECT id, template_id, region_key, region_type, label, lock_ratio, animation_json, x, y, width, height, z_index, created_at, modified_at, created_by, modified_by FROM c_template_regions WHERE template_id = ? ORDER BY z_index ASC, id ASC', [id]);
|
||||
template.regions = regions;
|
||||
return template;
|
||||
}
|
||||
@@ -70,7 +126,7 @@ async function fetchTemplatesData(pool) {
|
||||
LEFT JOIN c_canvas_sizes cs ON cs.id = st.canvas_size_id
|
||||
ORDER BY st.id DESC
|
||||
`);
|
||||
const [templateRegions] = await pool.query('SELECT id, template_id, region_key, region_type, label, lock_ratio, x, y, width, height, z_index, created_at, modified_at, created_by, modified_by FROM c_template_regions ORDER BY template_id ASC, z_index ASC, id ASC');
|
||||
const [templateRegions] = await pool.query('SELECT id, template_id, region_key, region_type, label, lock_ratio, animation_json, x, y, width, height, z_index, created_at, modified_at, created_by, modified_by FROM c_template_regions ORDER BY template_id ASC, z_index ASC, id ASC');
|
||||
return { templates, templateRegions };
|
||||
}
|
||||
|
||||
@@ -86,6 +142,7 @@ function extractTemplateRegions(body) {
|
||||
region_type: regionType,
|
||||
label: String(region.region_name || region.label || region.region_key || '').trim(),
|
||||
lock_ratio: normalizeTemplateRegionLockRatio(region.lock_ratio),
|
||||
animation_json: normalizeTemplateRegionAnimationConfig(region.animation_json),
|
||||
x: Number(region.x || 0),
|
||||
y: Number(region.y || 0),
|
||||
width: Number(region.width || 100),
|
||||
@@ -101,6 +158,7 @@ function extractTemplateRegions(body) {
|
||||
const labels = readFormArray(body, 'region_label[]');
|
||||
const types = readFormArray(body, 'region_type[]');
|
||||
const ratios = readFormArray(body, 'region_lock_ratio[]');
|
||||
const animationJsons = readFormArray(body, 'region_animation_json[]');
|
||||
const xs = readFormArray(body, 'region_x[]');
|
||||
const ys = readFormArray(body, 'region_y[]');
|
||||
const widths = readFormArray(body, 'region_width[]');
|
||||
@@ -120,6 +178,7 @@ function extractTemplateRegions(body) {
|
||||
region_type: regionType,
|
||||
label: name,
|
||||
lock_ratio: normalizeTemplateRegionLockRatio(ratios[i]),
|
||||
animation_json: normalizeTemplateRegionAnimationConfig(animationJsons[i]),
|
||||
x: Number(xs[i] || 0),
|
||||
y: Number(ys[i] || 0),
|
||||
width: Number(widths[i] || 100),
|
||||
|
||||
Reference in New Issue
Block a user