Save worktree changes

This commit is contained in:
2026-07-25 02:29:19 +01:00
parent 8d3b7d557b
commit db9d718cd8
170 changed files with 11719 additions and 3414 deletions
+183 -33
View File
@@ -3,6 +3,7 @@ import {
BlockQuote,
Bold,
ClassicEditor,
Base64UploadAdapter,
ClipboardPipeline,
Essentials,
FontBackgroundColor,
@@ -11,6 +12,20 @@ import {
FontSize,
Heading,
HorizontalLine,
Image,
ImageBlockEditing,
ImageCaption,
ImageInlineEditing,
ImageInsert,
ImageInsertUI,
ImageInsertViaUrl,
ImageInsertViaUrlUI,
ImageResize,
ImageResizeEditing,
ImageResizeHandles,
ImageStyle,
ImageTextAlternative,
ImageUpload,
Indent,
IndentBlock,
Italic,
@@ -25,6 +40,8 @@ import {
import { createTemplateSelectorLockController } from '/assets/js/slides/slide-form-template-lock.js';
(function () {
var DEFAULT_FONT_SIZE = 32;
var dataElement = document.getElementById('slide-editor-data');
if (!dataElement) {
return;
@@ -94,7 +111,7 @@ import { createTemplateSelectorLockController } from '/assets/js/slides/slide-fo
function getCurrentFontSizeValue() {
var value = fontSizeCommand.value;
if (value === null || value === undefined || value === '') {
return '';
return String(DEFAULT_FONT_SIZE);
}
var parsed = Math.round(Number(String(value).replace(/[^0-9.]/g, '')));
@@ -118,6 +135,7 @@ import { createTemplateSelectorLockController } from '/assets/js/slides/slide-fo
view.element.inputMode = 'numeric';
view.element.autocomplete = 'off';
view.element.spellcheck = false;
view.element.style.width = '3.5em';
syncValue();
});
@@ -170,6 +188,10 @@ import { createTemplateSelectorLockController } from '/assets/js/slides/slide-fo
var clipboardPipeline = editor.plugins.get(ClipboardPipeline);
this.listenTo(clipboardPipeline, 'inputTransformation', function (_event, data) {
if (clipboardContainsImageContent(data.dataTransfer)) {
return;
}
var plainText = data.dataTransfer.getData('text/plain');
data.content = editor.data.processor.toView(plainTextToHtml(plainText));
}, { priority: 'high' });
@@ -211,6 +233,22 @@ import { createTemplateSelectorLockController } from '/assets/js/slides/slide-fo
return paragraphs.length ? paragraphs.join('') : '<p></p>';
}
function clipboardContainsImageContent(dataTransfer) {
if (!dataTransfer) {
return false;
}
var files = Array.from(dataTransfer.files || []);
if (files.some(function (file) {
return file && String(file.type || '').indexOf('image/') === 0;
})) {
return true;
}
var html = dataTransfer.getData('text/html') || '';
return /<img\b|<figure\b[^>]*\bclass=["'][^"']*\bimage\b/i.test(html);
}
function getTemplateById(id) {
return templates.find(function (item) { return Number(item.id) === Number(id); }) || null;
}
@@ -240,30 +278,108 @@ import { createTemplateSelectorLockController } from '/assets/js/slides/slide-fo
}
function sanitizePreviewHtml(html) {
var output = String(html || '');
output = output.replace(/<script[\s\S]*?<\/script>/gi, '');
output = output.replace(/<style[\s\S]*?<\/style>/gi, '');
return output.replace(/<[^>]+>/g, function (tag) {
var match = tag.match(/^<\s*(\/?)\s*([a-z0-9]+)([\s\S]*?)(\/?)>$/i);
if (!match) {
return '';
var container = document.createElement('div');
container.innerHTML = String(html || '');
return sanitizePreviewNode(container);
}
function sanitizePreviewNode(node) {
var allowed = ['a', 'b', 'blockquote', 'br', 'code', 'div', 'em', 'figure', 'figcaption', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'li', 'ol', 'p', 'pre', 'span', 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'th', 'thead', 'tr', 'u', 'ul'];
var output = '';
Array.from(node.childNodes || []).forEach(function (child) {
if (child.nodeType === Node.TEXT_NODE) {
output += escapeHtml(child.textContent);
return;
}
var closing = Boolean(match[1]);
var name = String(match[2] || '').toLowerCase();
var attrText = String(match[3] || '');
var selfClosing = Boolean(match[4]) || name === 'br' || name === 'hr';
var allowed = ['a', 'b', 'blockquote', 'br', 'code', 'div', 'em', 'figure', 'figcaption', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'li', 'ol', 'p', 'pre', 'span', 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'th', 'thead', 'tr', 'u', 'ul'];
if (child.nodeType !== Node.ELEMENT_NODE) {
return;
}
var name = String(child.tagName || '').toLowerCase();
if (allowed.indexOf(name) === -1) {
return '';
return;
}
if (closing) {
return '</' + name + '>';
if (name === 'br' || name === 'hr') {
output += '<' + name + '>';
return;
}
if (selfClosing) {
return '<' + name + sanitizeTagAttributes(name, attrText) + '>';
var attrs = sanitizePreviewElementAttributes(child, name);
if (name === 'img') {
output += '<img' + attrs + '>';
return;
}
return '<' + name + sanitizeTagAttributes(name, attrText) + '>';
output += '<' + name + attrs + '>' + sanitizePreviewNode(child) + '</' + name + '>';
});
return output;
}
function sanitizePreviewElementAttributes(element, tagName) {
var allowedAttributes = {
a: ['href', 'title', 'target', 'rel', 'class', 'style'],
blockquote: ['class', 'style'],
div: ['class', 'style'],
figure: ['class', 'style'],
figcaption: ['class', 'style'],
h1: ['class', 'style'],
h2: ['class', 'style'],
h3: ['class', 'style'],
h4: ['class', 'style'],
h5: ['class', 'style'],
h6: ['class', 'style'],
img: ['alt', 'class', 'decoding', 'height', 'loading', 'src', 'style', 'title', 'width'],
li: ['class', 'style'],
ol: ['class', 'style', 'start'],
p: ['class', 'style'],
pre: ['class', 'style'],
span: ['class', 'style'],
table: ['class', 'style'],
td: ['class', 'style', 'colspan', 'rowspan'],
th: ['class', 'style', 'colspan', 'rowspan', 'scope'],
tr: ['class', 'style'],
ul: ['class', 'style']
};
var allowed = allowedAttributes[tagName] || [];
var attrs = [];
Array.from(element.attributes || []).forEach(function (attribute) {
var lowerKey = String(attribute.name || '').toLowerCase();
if (allowed.indexOf(lowerKey) === -1) {
return;
}
var value = String(attribute.value || '');
if (tagName === 'img' && lowerKey === 'src') {
value = sanitizeImageSrc(value);
}
if (lowerKey === 'href' && /^(?:\s*javascript:|\s*data:)/i.test(value)) {
return;
}
if (tagName === 'img' && lowerKey === 'src' && !value) {
return;
}
if (lowerKey === 'style' && /(?:expression\s*\(|javascript:|url\s*\()/i.test(value)) {
return;
}
if (lowerKey === 'target') {
var targetValue = value.trim();
if (targetValue === '_blank') {
attrs.push(' target="_blank"');
if (attrs.indexOf(' rel="noreferrer noopener"') === -1) {
attrs.push(' rel="noreferrer noopener"');
}
return;
}
}
attrs.push(' ' + lowerKey + '="' + escapeHtml(value) + '"');
});
return attrs.join('');
}
function sanitizeTagAttributes(tagName, attrText) {
@@ -279,6 +395,7 @@ import { createTemplateSelectorLockController } from '/assets/js/slides/slide-fo
h4: ['class', 'style'],
h5: ['class', 'style'],
h6: ['class', 'style'],
img: ['alt', 'class', 'decoding', 'height', 'loading', 'src', 'style', 'title', 'width'],
li: ['class', 'style'],
ol: ['class', 'style', 'start'],
p: ['class', 'style'],
@@ -302,9 +419,15 @@ import { createTemplateSelectorLockController } from '/assets/js/slides/slide-fo
return '';
}
var value = doubleQuoted !== undefined ? doubleQuoted : singleQuoted !== undefined ? singleQuoted : bareValue !== undefined ? bareValue : '';
if (tagName === 'img' && lowerKey === 'src') {
value = sanitizeImageSrc(value);
}
if (lowerKey === 'href' && /^(?:\s*javascript:|\s*data:)/i.test(String(value || ''))) {
return '';
}
if (tagName === 'img' && lowerKey === 'src' && !value) {
return '';
}
if (lowerKey === 'style' && /(?:expression\s*\(|javascript:|url\s*\()/i.test(String(value || ''))) {
return '';
}
@@ -325,6 +448,23 @@ import { createTemplateSelectorLockController } from '/assets/js/slides/slide-fo
return attrs.join('');
}
function sanitizeImageSrc(value) {
var raw = String(value || '').trim();
if (!raw) {
return '';
}
if (/^(?:https?:|\/|\.\.?\/|\/\/)/i.test(raw)) {
return raw;
}
if (/^data:image\/(?:png|jpe?g|gif|webp|bmp);base64,/i.test(raw)) {
return raw;
}
return '';
}
function renderPreviewListItem(item, tag) {
if (item && typeof item === 'object') {
var content = item.content !== undefined ? item.content : (item.text !== undefined ? item.text : item.value !== undefined ? item.value : '');
@@ -442,7 +582,7 @@ import { createTemplateSelectorLockController } from '/assets/js/slides/slide-fo
var current = existingContent[region.region_key] || {};
return {
font_family: String(current.font_family || region.font_family || 'Arial').trim() || 'Arial',
font_size: Math.max(8, Number(current.font_size || 24)),
font_size: Math.max(8, Number(current.font_size || DEFAULT_FONT_SIZE)),
font_color: String(current.font_color || region.font_color || '#000000').trim() || '#000000'
};
}
@@ -869,8 +1009,6 @@ import { createTemplateSelectorLockController } from '/assets/js/slides/slide-fo
'undo',
'redo',
'|',
'heading',
'|',
'fontSizeInput',
'fontFamily',
'fontColor',
@@ -889,12 +1027,20 @@ import { createTemplateSelectorLockController } from '/assets/js/slides/slide-fo
'alignment',
'|',
'outdent',
'indent'
'indent',
'|',
'imageInsert',
'imageInsertViaUrl',
'imageStyle:block',
'imageStyle:inline',
'imageTextAlternative',
'imageResize'
],
shouldNotGroupWhenFull: false
},
plugins: [
Alignment,
Base64UploadAdapter,
BlockQuote,
Bold,
Essentials,
@@ -904,11 +1050,24 @@ import { createTemplateSelectorLockController } from '/assets/js/slides/slide-fo
FontFamily,
FontSize,
FontSizeInputUI,
Heading,
HorizontalLine,
Indent,
IndentBlock,
Italic,
Image,
ImageBlockEditing,
ImageCaption,
ImageInlineEditing,
ImageInsert,
ImageInsertUI,
ImageInsertViaUrl,
ImageInsertViaUrlUI,
ImageResize,
ImageResizeEditing,
ImageResizeHandles,
ImageStyle,
ImageTextAlternative,
ImageUpload,
Paragraph,
Strikethrough,
Subscript,
@@ -922,15 +1081,6 @@ import { createTemplateSelectorLockController } from '/assets/js/slides/slide-fo
options: [20, 24, 28, 32, 36, 40, 44],
supportAllValues: true
},
heading: {
options: [
{ model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },
{ model: 'heading1', view: 'h1', title: 'Heading 1', class: 'ck-heading_heading1' },
{ model: 'heading2', view: 'h2', title: 'Heading 2', class: 'ck-heading_heading2' },
{ model: 'heading3', view: 'h3', title: 'Heading 3', class: 'ck-heading_heading3' },
{ model: 'heading4', view: 'h4', title: 'Heading 4', class: 'ck-heading_heading4' }
]
},
initialData: normalizeEditorData((source && source.value) || (hidden ? hidden.value : ''))
};