ppt_rs/generator/
notes_xml.rs1use crate::core::escape_xml;
4
5fn generate_field_guid(slide_num: usize) -> String {
8 format!("{{B0E4A5D7-2C3F-4A8B-9E1D-{:012X}}}", slide_num)
10}
11
12pub fn create_notes_xml(slide_num: usize, notes_text: &str) -> String {
14 let escaped_notes = escape_xml(notes_text);
15 let field_guid = generate_field_guid(slide_num);
16
17 format!(r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
18<p:notes xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
19<p:cSld>
20<p:spTree>
21<p:nvGrpSpPr>
22<p:cNvPr id="1" name=""/>
23<p:cNvGrpSpPr/>
24<p:nvPr/>
25</p:nvGrpSpPr>
26<p:grpSpPr>
27<a:xfrm>
28<a:off x="0" y="0"/>
29<a:ext cx="0" cy="0"/>
30<a:chOff x="0" y="0"/>
31<a:chExt cx="0" cy="0"/>
32</a:xfrm>
33</p:grpSpPr>
34<p:sp>
35<p:nvSpPr>
36<p:cNvPr id="2" name="Slide Image Placeholder 1"/>
37<p:cNvSpPr>
38<a:spLocks noGrp="1" noRot="1" noChangeAspect="1"/>
39</p:cNvSpPr>
40<p:nvPr>
41<p:ph type="sldImg"/>
42</p:nvPr>
43</p:nvSpPr>
44<p:spPr/>
45</p:sp>
46<p:sp>
47<p:nvSpPr>
48<p:cNvPr id="3" name="Notes Placeholder 2"/>
49<p:cNvSpPr>
50<a:spLocks noGrp="1"/>
51</p:cNvSpPr>
52<p:nvPr>
53<p:ph type="body" idx="1"/>
54</p:nvPr>
55</p:nvSpPr>
56<p:spPr/>
57<p:txBody>
58<a:bodyPr/>
59<a:lstStyle/>
60<a:p>
61<a:r>
62<a:rPr lang="en-US" dirty="0"/>
63<a:t>{escaped_notes}</a:t>
64</a:r>
65</a:p>
66</p:txBody>
67</p:sp>
68<p:sp>
69<p:nvSpPr>
70<p:cNvPr id="4" name="Slide Number Placeholder 3"/>
71<p:cNvSpPr>
72<a:spLocks noGrp="1"/>
73</p:cNvSpPr>
74<p:nvPr>
75<p:ph type="sldNum" sz="quarter" idx="10"/>
76</p:nvPr>
77</p:nvSpPr>
78<p:spPr/>
79<p:txBody>
80<a:bodyPr/>
81<a:lstStyle/>
82<a:p>
83<a:fld id="{field_guid}" type="slidenum">
84<a:rPr lang="en-US"/>
85<a:t>{slide_num}</a:t>
86</a:fld>
87<a:endParaRPr lang="en-US"/>
88</a:p>
89</p:txBody>
90</p:sp>
91</p:spTree>
92</p:cSld>
93<p:clrMapOvr>
94<a:masterClrMapping/>
95</p:clrMapOvr>
96</p:notes>"#)
97}
98
99pub fn create_notes_rels_xml(slide_num: usize) -> String {
101 format!(r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
102<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
103<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide" Target="../slides/slide{slide_num}.xml"/>
104<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster" Target="../notesMasters/notesMaster1.xml"/>
105</Relationships>"#)
106}
107
108pub fn create_notes_master_xml() -> String {
110 r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
111<p:notesMaster xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
112<p:cSld>
113<p:bg><p:bgRef idx="1001"><a:schemeClr val="bg1"/></p:bgRef></p:bg>
114<p:spTree>
115<p:nvGrpSpPr>
116<p:cNvPr id="1" name=""/>
117<p:cNvGrpSpPr/>
118<p:nvPr/>
119</p:nvGrpSpPr>
120<p:grpSpPr>
121<a:xfrm>
122<a:off x="0" y="0"/>
123<a:ext cx="0" cy="0"/>
124<a:chOff x="0" y="0"/>
125<a:chExt cx="0" cy="0"/>
126</a:xfrm>
127</p:grpSpPr>
128<p:sp>
129<p:nvSpPr>
130<p:cNvPr id="2" name="Header Placeholder 1"/>
131<p:cNvSpPr>
132<a:spLocks noGrp="1"/>
133</p:cNvSpPr>
134<p:nvPr>
135<p:ph type="hdr" sz="quarter"/>
136</p:nvPr>
137</p:nvSpPr>
138<p:spPr>
139<a:xfrm>
140<a:off x="0" y="0"/>
141<a:ext cx="2971800" cy="458788"/>
142</a:xfrm>
143<a:prstGeom prst="rect">
144<a:avLst/>
145</a:prstGeom>
146</p:spPr>
147<p:txBody>
148<a:bodyPr vert="horz" lIns="91440" tIns="45720" rIns="91440" bIns="45720" rtlCol="0"/>
149<a:lstStyle>
150<a:lvl1pPr algn="l">
151<a:defRPr sz="1200"/>
152</a:lvl1pPr>
153</a:lstStyle>
154<a:p>
155<a:endParaRPr lang="en-US"/>
156</a:p>
157</p:txBody>
158</p:sp>
159<p:sp>
160<p:nvSpPr>
161<p:cNvPr id="3" name="Slide Image Placeholder 2"/>
162<p:cNvSpPr>
163<a:spLocks noGrp="1" noRot="1" noChangeAspect="1"/>
164</p:cNvSpPr>
165<p:nvPr>
166<p:ph type="sldImg" idx="2"/>
167</p:nvPr>
168</p:nvSpPr>
169<p:spPr>
170<a:xfrm>
171<a:off x="685800" y="1143000"/>
172<a:ext cx="5486400" cy="3086100"/>
173</a:xfrm>
174<a:prstGeom prst="rect">
175<a:avLst/>
176</a:prstGeom>
177<a:noFill/>
178<a:ln w="12700">
179<a:solidFill>
180<a:prstClr val="black"/>
181</a:solidFill>
182</a:ln>
183</p:spPr>
184<p:txBody>
185<a:bodyPr vert="horz" lIns="91440" tIns="45720" rIns="91440" bIns="45720" rtlCol="0" anchor="ctr"/>
186<a:lstStyle/>
187<a:p>
188<a:endParaRPr lang="en-US"/>
189</a:p>
190</p:txBody>
191</p:sp>
192<p:sp>
193<p:nvSpPr>
194<p:cNvPr id="4" name="Notes Placeholder 3"/>
195<p:cNvSpPr>
196<a:spLocks noGrp="1"/>
197</p:cNvSpPr>
198<p:nvPr>
199<p:ph type="body" sz="quarter" idx="3"/>
200</p:nvPr>
201</p:nvSpPr>
202<p:spPr>
203<a:xfrm>
204<a:off x="685800" y="4400550"/>
205<a:ext cx="5486400" cy="3600450"/>
206</a:xfrm>
207<a:prstGeom prst="rect">
208<a:avLst/>
209</a:prstGeom>
210</p:spPr>
211<p:txBody>
212<a:bodyPr vert="horz" lIns="91440" tIns="45720" rIns="91440" bIns="45720" rtlCol="0"/>
213<a:lstStyle/>
214<a:p>
215<a:pPr lvl="0"/>
216<a:r>
217<a:rPr lang="en-US"/>
218<a:t>Click to edit Master text styles</a:t>
219</a:r>
220</a:p>
221</p:txBody>
222</p:sp>
223</p:spTree>
224</p:cSld>
225<p:clrMap bg1="lt1" tx1="dk1" bg2="lt2" tx2="dk2" accent1="accent1" accent2="accent2" accent3="accent3" accent4="accent4" accent5="accent5" accent6="accent6" hlink="hlink" folHlink="folHlink"/>
226<p:notesStyle>
227<a:lvl1pPr marL="0" algn="l" defTabSz="914400" rtl="0" eaLnBrk="1" latinLnBrk="0" hangingPunct="1">
228<a:defRPr sz="1200" kern="1200">
229<a:solidFill>
230<a:schemeClr val="tx1"/>
231</a:solidFill>
232<a:latin typeface="+mn-lt"/>
233<a:ea typeface="+mn-ea"/>
234<a:cs typeface="+mn-cs"/>
235</a:defRPr>
236</a:lvl1pPr>
237</p:notesStyle>
238</p:notesMaster>"#.to_string()
239}
240
241pub fn create_notes_master_rels_xml() -> String {
243 r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
244<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
245<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="../theme/theme2.xml"/>
246</Relationships>"#.to_string()
247}
248
249#[cfg(test)]
250mod tests {
251 use super::*;
252
253 #[test]
254 fn test_create_notes_xml() {
255 let xml = create_notes_xml(1, "These are my speaker notes");
256 assert!(xml.contains("p:notes"));
257 assert!(xml.contains("These are my speaker notes"));
258 assert!(xml.contains("Notes Placeholder"));
259 }
260
261 #[test]
262 fn test_create_notes_xml_escapes_special_chars() {
263 let xml = create_notes_xml(1, "Notes with <special> & \"chars\"");
264 assert!(xml.contains("<special>"));
265 assert!(xml.contains("&"));
266 assert!(xml.contains(""chars""));
267 }
268
269 #[test]
270 fn test_create_notes_rels_xml() {
271 let xml = create_notes_rels_xml(3);
272 assert!(xml.contains("slide3.xml"));
273 assert!(xml.contains("notesMaster1.xml"));
274 }
275
276 #[test]
277 fn test_create_notes_master_xml() {
278 let xml = create_notes_master_xml();
279 assert!(xml.contains("p:notesMaster"));
280 assert!(xml.contains("<p:bg>"));
281 assert!(xml.contains("Notes Placeholder"));
282 }
283
284 #[test]
285 fn test_create_notes_master_rels_xml() {
286 let xml = create_notes_master_rels_xml();
287 assert!(xml.contains("theme2.xml"));
288 }
289}