Compare commits
2
Commits
34d0460130
...
0f8a797b7a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f8a797b7a | ||
|
|
ca1e4dfa72 |
+104
-19
@@ -158,7 +158,7 @@ async function main() {
|
||||
// DashiAI format: .ppt-deck > .ppt-slide
|
||||
var deck = document.querySelector('.ppt-deck');
|
||||
if (deck) {
|
||||
slides = deck.querySelectorAll('.ppt-slide');
|
||||
slides = deck.querySelectorAll(':scope > .ppt-slide');
|
||||
}
|
||||
if (!slides || slides.length <= 1) {
|
||||
slides = document.querySelectorAll(
|
||||
@@ -170,9 +170,37 @@ async function main() {
|
||||
}
|
||||
slides = Array.from(slides).filter(function (s) {
|
||||
var r = s.getBoundingClientRect();
|
||||
return r.width > 0 && r.height > 0;
|
||||
var style = window.getComputedStyle(s);
|
||||
return r.width > 0 && r.height > 0 &&
|
||||
style.opacity !== '0' &&
|
||||
style.display !== 'none' &&
|
||||
style.visibility !== 'hidden';
|
||||
});
|
||||
|
||||
// Recursively extract inline text runs with computed styles
|
||||
function extractRuns(node) {
|
||||
var runs = [];
|
||||
for (var ri = 0; ri < node.childNodes.length; ri++) {
|
||||
var child = node.childNodes[ri];
|
||||
if (child.nodeType === 3) {
|
||||
var t = (child.textContent || '').trim();
|
||||
if (t) runs.push({ text: t });
|
||||
} else if (child.nodeType === 1) {
|
||||
var cs = window.getComputedStyle(child);
|
||||
var childRuns = extractRuns(child);
|
||||
for (var cj = 0; cj < childRuns.length; cj++) {
|
||||
childRuns[cj].bold = childRuns[cj].bold || parseInt(cs.fontWeight) >= 600;
|
||||
childRuns[cj].italic = childRuns[cj].italic || cs.fontStyle === 'italic';
|
||||
childRuns[cj].color = childRuns[cj].color || cs.color;
|
||||
childRuns[cj].fontSize = childRuns[cj].fontSize || parseFloat(cs.fontSize);
|
||||
childRuns[cj].fontFamily = childRuns[cj].fontFamily || cs.fontFamily;
|
||||
}
|
||||
runs = runs.concat(childRuns);
|
||||
}
|
||||
}
|
||||
return runs.length > 0 ? runs : [{ text: node.textContent || '' }];
|
||||
}
|
||||
|
||||
// Tags whose full text content should be a single text box
|
||||
var TEXT_BLOCK_TAGS = new Set([
|
||||
'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
|
||||
@@ -203,7 +231,9 @@ async function main() {
|
||||
}
|
||||
if (skip) continue;
|
||||
|
||||
var text = (el.textContent || '').trim();
|
||||
var runs = extractRuns(el);
|
||||
if (!runs || runs.length === 0) continue;
|
||||
var text = runs.map(function (r) { return r.text || ''; }).join(' ').trim();
|
||||
if (!text) continue;
|
||||
|
||||
var rect = el.getBoundingClientRect();
|
||||
@@ -211,7 +241,13 @@ async function main() {
|
||||
|
||||
var style = window.getComputedStyle(el);
|
||||
|
||||
// Truncate overly long runs
|
||||
runs.forEach(function (r) {
|
||||
if (r.text && r.text.length > 2000) r.text = r.text.substring(0, 2000);
|
||||
});
|
||||
|
||||
elements.push({
|
||||
runs: runs,
|
||||
text: text.substring(0, 2000),
|
||||
x: rect.left - slideRect.left,
|
||||
y: rect.top - slideRect.top,
|
||||
@@ -281,25 +317,74 @@ async function main() {
|
||||
var w = Math.max(el.width * scaleX, 0.3);
|
||||
var h = Math.max(el.height * scaleY, 0.2);
|
||||
|
||||
// Font size: CSS px → pt (1pt = 1/72in, CSS 1px = 1/96in, so px × 72/96 = pt)
|
||||
// Bounds constraints: prevent textbox from overflowing slide
|
||||
var MAX_W = 10 - x;
|
||||
var MAX_H = 5.625 - y;
|
||||
w = Math.min(w, MAX_W);
|
||||
h = Math.min(h, MAX_H);
|
||||
|
||||
// Base font size: CSS px → pt (1pt = 1/72in, CSS 1px = 1/96in)
|
||||
var fontSize = el.fontSize * 72 / 96;
|
||||
fontSize = Math.max(fontSize, 8);
|
||||
|
||||
slide.addText(t, {
|
||||
x: x,
|
||||
y: y,
|
||||
w: w,
|
||||
h: h,
|
||||
fontSize: fontSize,
|
||||
fontFace: (el.fontFamily || 'Arial').split(',')[0].trim().replace(/['"]/g, ''),
|
||||
color: parseCSSColor(el.color, '#000000'),
|
||||
bold: parseFontWeight(el.fontWeight),
|
||||
italic: el.fontStyle === 'italic' || el.fontStyle === 'oblique',
|
||||
align: normalizeAlign(el.textAlign),
|
||||
valign: 'top',
|
||||
wrap: true,
|
||||
margin: 0,
|
||||
});
|
||||
// Check if rich text is needed (runs with differing styles)
|
||||
var hasRuns = el.runs && el.runs.length > 0;
|
||||
var isSimpleRun = hasRuns && el.runs.length === 1 &&
|
||||
el.runs[0].bold === undefined &&
|
||||
el.runs[0].italic === undefined &&
|
||||
el.runs[0].color === undefined &&
|
||||
el.runs[0].fontSize === undefined &&
|
||||
el.runs[0].fontFamily === undefined;
|
||||
|
||||
if (hasRuns && !isSimpleRun && el.runs.length > 1) {
|
||||
// Rich text: render each run with its own style
|
||||
var pptxRuns = el.runs.map(function (run) {
|
||||
if (!run.text || !run.text.trim()) return null;
|
||||
var baseSize = el.fontSize * 72 / 96;
|
||||
return {
|
||||
text: run.text,
|
||||
options: {
|
||||
fontSize: run.fontSize ? Math.max(run.fontSize * 72 / 96, 8) : baseSize,
|
||||
bold: run.bold === true || (run.bold === undefined && parseFontWeight(el.fontWeight)),
|
||||
italic: run.italic === true || (run.italic === undefined && (el.fontStyle === 'italic' || el.fontStyle === 'oblique')),
|
||||
color: run.color ? parseCSSColor(run.color, '#000000') : parseCSSColor(el.color, '#000000'),
|
||||
fontFace: run.fontFamily
|
||||
? run.fontFamily.split(',')[0].trim().replace(/['"]/g, '')
|
||||
: (el.fontFamily || 'Arial').split(',')[0].trim().replace(/['"]/g, ''),
|
||||
},
|
||||
};
|
||||
}).filter(Boolean);
|
||||
|
||||
if (pptxRuns.length > 0) {
|
||||
slide.addText(pptxRuns, {
|
||||
x: x,
|
||||
y: y,
|
||||
w: w,
|
||||
h: h,
|
||||
align: normalizeAlign(el.textAlign),
|
||||
valign: 'top',
|
||||
wrap: true,
|
||||
margin: 0,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Plain text: original single-style logic
|
||||
slide.addText(t, {
|
||||
x: x,
|
||||
y: y,
|
||||
w: w,
|
||||
h: h,
|
||||
fontSize: fontSize,
|
||||
fontFace: (el.fontFamily || 'Arial').split(',')[0].trim().replace(/['"]/g, ''),
|
||||
color: parseCSSColor(el.color, '#000000'),
|
||||
bold: parseFontWeight(el.fontWeight),
|
||||
italic: el.fontStyle === 'italic' || el.fontStyle === 'oblique',
|
||||
align: normalizeAlign(el.textAlign),
|
||||
valign: 'top',
|
||||
wrap: true,
|
||||
margin: 0,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
// Skip individual element failure
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user