@mcpher/gas-fakes 2.5.2 → 2.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +17 -3
  2. package/package.json +1 -1
  3. package/pngs/srv.jpg +0 -0
  4. package/src/cli/app.js +1 -0
  5. package/src/cli/togas.js +23 -14
  6. package/src/index.js +1 -0
  7. package/src/services/advslides/fakeadvslides.js +11 -5
  8. package/src/services/base/app.js +9 -0
  9. package/src/services/base/fakebase.js +28 -0
  10. package/src/services/common/fakeadvresource.js +3 -2
  11. package/src/services/content/contentservice.js +3 -2
  12. package/src/services/enums/baseenums.js +47 -0
  13. package/src/services/enums/contentenums.js +1 -3
  14. package/src/services/enums/scriptenums.js +31 -4
  15. package/src/services/enums/slidesenums.js +3 -1
  16. package/src/services/enums/xmlenums.js +14 -0
  17. package/src/services/html/serverworker.js +1 -1
  18. package/src/services/scriptapp/app.js +14 -7
  19. package/src/services/scriptapp/fakeauthorizationinfo.js +4 -4
  20. package/src/services/slidesapp/app.js +5 -0
  21. package/src/services/slidesapp/fakeautofit.js +1 -1
  22. package/src/services/slidesapp/fakeborder.js +106 -0
  23. package/src/services/slidesapp/fakecolorscheme.js +1 -1
  24. package/src/services/slidesapp/fakefill.js +216 -0
  25. package/src/services/slidesapp/fakegroup.js +35 -0
  26. package/src/services/slidesapp/fakeimage.js +118 -0
  27. package/src/services/slidesapp/fakelayout.js +351 -0
  28. package/src/services/slidesapp/fakeline.js +2 -2
  29. package/src/services/slidesapp/fakelinefill.js +15 -16
  30. package/src/services/slidesapp/fakelink.js +20 -3
  31. package/src/services/slidesapp/fakelist.js +36 -0
  32. package/src/services/slidesapp/fakeliststyle.js +105 -0
  33. package/src/services/slidesapp/fakemaster.js +358 -0
  34. package/src/services/slidesapp/fakenotesmaster.js +125 -0
  35. package/src/services/slidesapp/fakenotespage.js +102 -2
  36. package/src/services/slidesapp/fakepagebackground.js +109 -1
  37. package/src/services/slidesapp/fakepageelement.js +157 -18
  38. package/src/services/slidesapp/fakepageelementrange.js +28 -0
  39. package/src/services/slidesapp/fakepagerange.js +28 -0
  40. package/src/services/slidesapp/fakeparagraphstyle.js +139 -0
  41. package/src/services/slidesapp/fakepicturefill.js +32 -0
  42. package/src/services/slidesapp/fakepresentation.js +126 -2
  43. package/src/services/slidesapp/fakeshape.js +9 -0
  44. package/src/services/slidesapp/fakeslide.js +216 -24
  45. package/src/services/slidesapp/fakesolidfill.js +45 -0
  46. package/src/services/slidesapp/fakespeakerspotlight.js +18 -0
  47. package/src/services/slidesapp/faketable.js +55 -9
  48. package/src/services/slidesapp/faketablecell.js +141 -12
  49. package/src/services/slidesapp/faketablecellrange.js +28 -0
  50. package/src/services/slidesapp/faketablecolumn.js +72 -0
  51. package/src/services/slidesapp/faketablerow.js +31 -0
  52. package/src/services/slidesapp/faketextrange.js +179 -135
  53. package/src/services/slidesapp/faketextstyle.js +158 -0
  54. package/src/services/slidesapp/fakevideo.js +35 -0
  55. package/src/services/slidesapp/fakewordart.js +22 -0
  56. package/src/services/slidesapp/pageelementfactory.js +24 -1
  57. package/src/services/spreadsheetapp/fakeembeddedchartbuilder.js +92 -12
  58. package/src/services/spreadsheetapp/fakespreadsheet.js +360 -62
  59. package/src/services/spreadsheetapp/fakespreadsheettheme.js +53 -0
  60. package/src/services/urlfetchapp/app.js +216 -175
  61. package/src/services/xmlservice/app.js +3 -78
  62. package/src/services/xmlservice/fakeattribute.js +15 -0
  63. package/src/services/xmlservice/fakecdata.js +40 -0
  64. package/src/services/xmlservice/fakecomment.js +34 -0
  65. package/src/services/xmlservice/fakecontent.js +51 -0
  66. package/src/services/xmlservice/fakedoctype.js +68 -0
  67. package/src/services/xmlservice/fakedocument.js +110 -13
  68. package/src/services/xmlservice/fakeelement.js +297 -82
  69. package/src/services/xmlservice/fakeentityref.js +54 -0
  70. package/src/services/xmlservice/fakeformat.js +67 -22
  71. package/src/services/xmlservice/fakeprocessinginstruction.js +44 -0
  72. package/src/services/xmlservice/faketext.js +39 -0
  73. package/src/services/xmlservice/fakexmlservice.js +118 -0
  74. package/src/support/sxfetch.js +60 -0
  75. package/tools/omlx.env.example +6 -0
  76. package/tools/omlx_mcp_server.cjs +157 -0
@@ -1,6 +1,8 @@
1
1
  import { Proxies } from '../../support/proxies.js';
2
2
  import { newFakeSlide } from './fakeslide.js';
3
3
  import { newFakeMaster } from './fakemaster.js';
4
+ import { newFakeNotesMaster } from './fakenotesmaster.js';
5
+ import { newFakeLayout } from './fakelayout.js';
4
6
  import { newFakeColorScheme } from './fakecolorscheme.js';
5
7
 
6
8
  export const newFakePresentation = (...args) => {
@@ -28,6 +30,45 @@ export class FakePresentation {
28
30
  saveAndClose() {
29
31
  // this is a no-op in fake environment since it is stateless
30
32
  }
33
+
34
+ addEditor(emailAddress) {
35
+ this.__file.addEditor(emailAddress);
36
+ return this;
37
+ }
38
+
39
+ addEditors(emailAddresses) {
40
+ this.__file.addEditors(emailAddresses);
41
+ return this;
42
+ }
43
+
44
+ addViewer(emailAddress) {
45
+ this.__file.addViewer(emailAddress);
46
+ return this;
47
+ }
48
+
49
+ addViewers(emailAddresses) {
50
+ this.__file.addViewers(emailAddresses);
51
+ return this;
52
+ }
53
+
54
+ getEditors() {
55
+ return this.__file.getEditors();
56
+ }
57
+
58
+ getViewers() {
59
+ return this.__file.getViewers();
60
+ }
61
+
62
+ removeEditor(emailAddress) {
63
+ this.__file.removeEditor(emailAddress);
64
+ return this;
65
+ }
66
+
67
+ removeViewer(emailAddress) {
68
+ this.__file.removeViewer(emailAddress);
69
+ return this;
70
+ }
71
+
31
72
  /**
32
73
  * Gets the ID of the presentation.
33
74
  * @returns {string} The presentation ID.
@@ -44,6 +85,10 @@ export class FakePresentation {
44
85
  return this.__resource.title;
45
86
  }
46
87
 
88
+ setName(name) {
89
+ this.__file.setName(name);
90
+ }
91
+
47
92
  /**
48
93
  * Gets the URL of the presentation.
49
94
  * @returns {string} The presentation URL.
@@ -52,6 +97,38 @@ export class FakePresentation {
52
97
  return `https://docs.google.com/presentation/d/${this.getId()}/edit`;
53
98
  }
54
99
 
100
+ getPageHeight() {
101
+ const size = this.__resource.pageSize;
102
+ return this.__normalize(size?.height);
103
+ }
104
+
105
+ getPageWidth() {
106
+ const size = this.__resource.pageSize;
107
+ return this.__normalize(size?.width);
108
+ }
109
+
110
+ getNotesPageHeight() {
111
+ const size = this.__resource.notesMaster?.notesVisualProperties?.pageSize || this.__resource.pageSize;
112
+ return this.__normalize(size?.height);
113
+ }
114
+
115
+ getNotesPageWidth() {
116
+ const size = this.__resource.notesMaster?.notesVisualProperties?.pageSize || this.__resource.pageSize;
117
+ return this.__normalize(size?.width);
118
+ }
119
+
120
+ __normalize(val) {
121
+ if (!val) return 0;
122
+ if (typeof val === 'number') {
123
+ return val > 5000 ? val / 12700 : val;
124
+ }
125
+ if (typeof val.magnitude === 'number') {
126
+ const isEMU = val.unit === 'EMU' || val.magnitude > 5000;
127
+ return isEMU ? val.magnitude / 12700 : val.magnitude;
128
+ }
129
+ return val || 0;
130
+ }
131
+
55
132
  /**
56
133
  * Gets the masters in the presentation.
57
134
  * @returns {FakeMaster[]} The masters.
@@ -60,6 +137,14 @@ export class FakePresentation {
60
137
  return (this.__resource.masters || []).map(m => newFakeMaster(m, this));
61
138
  }
62
139
 
140
+ /**
141
+ * Gets the layouts in the presentation.
142
+ * @returns {FakeLayout[]} The layouts.
143
+ */
144
+ getLayouts() {
145
+ return (this.__resource.layouts || []).map(l => newFakeLayout(l, this));
146
+ }
147
+
63
148
  /**
64
149
  * Gets a master by its ID.
65
150
  * @param {string} id The master ID.
@@ -69,6 +154,15 @@ export class FakePresentation {
69
154
  return this.getMasters().find(m => m.getObjectId() === id) || null;
70
155
  }
71
156
 
157
+ /**
158
+ * Gets the notes master in the presentation.
159
+ * @returns {FakeNotesMaster | null} The notes master.
160
+ */
161
+ getNotesMaster() {
162
+ const notesMaster = this.__resource.notesMaster;
163
+ return notesMaster ? newFakeNotesMaster(notesMaster, this) : null;
164
+ }
165
+
72
166
  /**
73
167
  * Gets the slides in the presentation.
74
168
  * @returns {FakeSlide[]} The slides.
@@ -86,6 +180,36 @@ export class FakePresentation {
86
180
  return this.getSlides().find(s => s.getObjectId() === id) || null;
87
181
  }
88
182
 
183
+ getPageElementById(id) {
184
+ const pages = [...this.getSlides(), ...this.getLayouts(), ...this.getMasters()];
185
+ const nm = this.getNotesMaster();
186
+ if (nm) pages.push(nm);
187
+
188
+ for (const page of pages) {
189
+ const el = page.getPageElementById(id);
190
+ if (el) return el;
191
+ }
192
+ return null;
193
+ }
194
+
195
+ getSelection() {
196
+ return null; // Mock
197
+ }
198
+
199
+ replaceAllText(findText, replaceText, matchCase = false) {
200
+ const requests = [{
201
+ replaceAllText: {
202
+ replaceText,
203
+ containsText: {
204
+ text: findText,
205
+ matchCase
206
+ }
207
+ }
208
+ }];
209
+ const response = Slides.Presentations.batchUpdate({ requests }, this.getId());
210
+ return response.replies[0].replaceAllText.occurrencesChanged || 0;
211
+ }
212
+
89
213
  /**
90
214
  * Appends a new slide to the presentation.
91
215
  * @param {string} [layout] The layout to use (optional).
@@ -100,7 +224,7 @@ export class FakePresentation {
100
224
  }
101
225
  }];
102
226
  try {
103
- Slides.Presentations.batchUpdate(requests, this.getId());
227
+ Slides.Presentations.batchUpdate({ requests }, this.getId());
104
228
  } catch (err) {
105
229
  // If it already exists, it means a previous attempt succeeded but timed out
106
230
  if (!err?.message?.includes('already exists')) throw err;
@@ -124,7 +248,7 @@ export class FakePresentation {
124
248
  }
125
249
  }];
126
250
  try {
127
- Slides.Presentations.batchUpdate(requests, this.getId());
251
+ Slides.Presentations.batchUpdate({ requests }, this.getId());
128
252
  } catch (err) {
129
253
  if (!err?.message?.includes('already exists')) throw err;
130
254
  }
@@ -3,6 +3,7 @@ import { newFakeTextRange } from './faketextrange.js';
3
3
  import { newFakeAutofit } from './fakeautofit.js';
4
4
  import { newFakeConnectionSite } from './fakeconnectionsite.js';
5
5
  import { FakePageElement, PageElementRegistry } from './fakepageelement.js';
6
+ import { newFakeFill } from './fakefill.js';
6
7
 
7
8
  export const newFakeShape = (...args) => {
8
9
  const shape = Proxies.guard(new FakeShape(...args));
@@ -33,6 +34,14 @@ export class FakeShape extends FakePageElement {
33
34
  return newFakeAutofit(this);
34
35
  }
35
36
 
37
+ /**
38
+ * Gets the fill of the shape.
39
+ * @returns {FakeFill} The fill object.
40
+ */
41
+ getFill() {
42
+ return newFakeFill(this);
43
+ }
44
+
36
45
  /**
37
46
  * Gets the connection sites on the shape.
38
47
  * @returns {FakeConnectionSite[]} The connection sites.
@@ -5,7 +5,6 @@ import { newFakeMaster } from './fakemaster.js';
5
5
  import { newFakePageElement } from './fakepageelement.js';
6
6
  import { newFakePageBackground } from './fakepagebackground.js';
7
7
  import { newFakeColorScheme } from './fakecolorscheme.js';
8
- import { asSpecificPageElement } from './pageelementfactory.js';
9
8
 
10
9
  export const newFakeSlide = (...args) => {
11
10
  return Proxies.guard(new FakeSlide(...args));
@@ -75,7 +74,11 @@ export class FakeSlide {
75
74
  * @returns {FakePageElement[]} The page elements.
76
75
  */
77
76
  getPageElements() {
78
- return (this.__resource.pageElements || []).map(pe => asSpecificPageElement(newFakePageElement(pe, this)));
77
+ return (this.__resource.pageElements || []).map(pe => newFakePageElement(pe, this));
78
+ }
79
+
80
+ getPageElementById(id) {
81
+ return this.getPageElements().find(pe => pe.getObjectId() === id) || null;
79
82
  }
80
83
 
81
84
  /**
@@ -83,8 +86,7 @@ export class FakeSlide {
83
86
  * @returns {FakePageBackground} The background.
84
87
  */
85
88
  getBackground() {
86
- const background = this.__resource.pageBackgroundFill;
87
- return background ? newFakePageBackground(this) : null;
89
+ return newFakePageBackground(this);
88
90
  }
89
91
 
90
92
  /**
@@ -101,7 +103,7 @@ export class FakeSlide {
101
103
  */
102
104
  getTables() {
103
105
  return this.getPageElements()
104
- .filter(pe => pe.toString() === 'Table')
106
+ .filter(pe => pe.getPageElementType().toString() === 'TABLE')
105
107
  .map(pe => pe.asTable());
106
108
  }
107
109
 
@@ -111,21 +113,186 @@ export class FakeSlide {
111
113
  */
112
114
  getShapes() {
113
115
  return this.getPageElements()
114
- .filter(pe => pe.toString() === 'Shape')
116
+ .filter(pe => pe.getPageElementType().toString() === 'SHAPE')
115
117
  .map(pe => pe.asShape());
116
118
  }
117
119
 
120
+ /**
121
+ * Gets the list of images on the slide.
122
+ * @returns {FakeImage[]} The images.
123
+ */
124
+ getImages() {
125
+ return this.getPageElements()
126
+ .filter(pe => pe.getPageElementType().toString() === 'IMAGE')
127
+ .map(pe => pe.asImage());
128
+ }
129
+
130
+ /**
131
+ * Inserts a Google Sheets chart on the slide.
132
+ * @param {EmbeddedChart} chart The chart.
133
+ * @returns {SheetsChart} The inserted chart.
134
+ */
135
+ insertSheetsChart(chart) {
136
+ const presentationId = this.__presentation.getId();
137
+ const objectId = `chart_${Math.random().toString(36).substring(2, 11)}`;
138
+ const spreadsheetId = chart.getSpreadsheetId ? chart.getSpreadsheetId() : '';
139
+ const chartId = chart.getChartId ? chart.getChartId() : 0;
140
+
141
+ const requests = [{
142
+ createSheetsChart: {
143
+ objectId,
144
+ spreadsheetId,
145
+ chartId,
146
+ linkingMode: 'LINKED',
147
+ elementProperties: {
148
+ pageObjectId: this.getObjectId(),
149
+ size: {
150
+ width: { magnitude: 400, unit: 'PT' },
151
+ height: { magnitude: 300, unit: 'PT' }
152
+ }
153
+ }
154
+ }
155
+ }];
156
+
157
+ Slides.Presentations.batchUpdate({ requests }, presentationId);
158
+ return this.getPageElementById(objectId).asSheetsChart();
159
+ }
160
+
161
+ /**
162
+ * Inserts a Google Sheets chart as an image on the slide.
163
+ * @param {EmbeddedChart} chart The chart.
164
+ * @returns {Image} The inserted image.
165
+ */
166
+ insertSheetsChartAsImage(chart) {
167
+ // In GAS, this is usually implemented as a static image capture.
168
+ // For the fake, we'll just insert it as a non-linked chart or a placeholder image.
169
+ const presentationId = this.__presentation.getId();
170
+ const objectId = `chart_img_${Math.random().toString(36).substring(2, 11)}`;
171
+
172
+ const requests = [{
173
+ createImage: {
174
+ objectId,
175
+ url: 'https://via.placeholder.com/400x300?text=Sheets+Chart',
176
+ elementProperties: {
177
+ pageObjectId: this.getObjectId()
178
+ }
179
+ }
180
+ }];
181
+ Slides.Presentations.batchUpdate({ requests }, presentationId);
182
+ return this.getPageElementById(objectId).asImage();
183
+ }
184
+
185
+ /**
186
+ * Inserts a video at the top left corner of the page with a default size from the provided URL.
187
+ * @param {string} videoUrl The video URL.
188
+ * @param {number} [left]
189
+ * @param {number} [top]
190
+ * @param {number} [width]
191
+ * @param {number} [height]
192
+ * @returns {FakeVideo} The inserted video.
193
+ */
194
+ insertVideo(videoUrl, left = 0, top = 0, width = 300, height = 200) {
195
+ const presentationId = this.__presentation.getId();
196
+ const objectId = `video_${Math.random().toString(36).substring(2, 11)}`;
197
+
198
+ // Standard YouTube URL parsing
199
+ let videoId = videoUrl;
200
+ if (videoUrl.includes('v=')) {
201
+ videoId = videoUrl.split('v=')[1].split('&')[0];
202
+ } else if (videoUrl.includes('youtu.be/')) {
203
+ videoId = videoUrl.split('youtu.be/')[1].split('?')[0];
204
+ }
205
+
206
+ const requests = [{
207
+ createVideo: {
208
+ objectId,
209
+ source: 'YOUTUBE',
210
+ id: videoId,
211
+ elementProperties: {
212
+ pageObjectId: this.getObjectId(),
213
+ size: {
214
+ width: { magnitude: width, unit: 'PT' },
215
+ height: { magnitude: height, unit: 'PT' }
216
+ },
217
+ transform: {
218
+ scaleX: 1,
219
+ scaleY: 1,
220
+ translateX: left,
221
+ translateY: top,
222
+ unit: 'PT'
223
+ }
224
+ }
225
+ }
226
+ }];
227
+
228
+ Slides.Presentations.batchUpdate({ requests }, presentationId);
229
+ return this.getPageElementById(objectId).asVideo();
230
+ }
231
+
232
+ /**
233
+ * Inserts an image.
234
+ * @param {string|FakeBlob|FakeImage} urlOrBlobOrImage The image to insert.
235
+ * @param {number} [left]
236
+ * @param {number} [top]
237
+ * @param {number} [width]
238
+ * @param {number} [height]
239
+ * @returns {FakeImage} The new image.
240
+ */
241
+ insertImage(urlOrBlobOrImage, left = 0, top = 0, width = 300, height = 300) {
242
+ const presentationId = this.__presentation.getId();
243
+ const objectId = `image_${Math.random().toString(36).substring(2, 11)}`;
244
+ let sourceUrl = '';
245
+
246
+ if (typeof urlOrBlobOrImage === 'string') {
247
+ sourceUrl = urlOrBlobOrImage;
248
+ } else if (urlOrBlobOrImage && urlOrBlobOrImage.getSourceUrl) {
249
+ sourceUrl = urlOrBlobOrImage.getSourceUrl();
250
+ }
251
+
252
+ const requests = [{
253
+ createImage: {
254
+ objectId,
255
+ url: sourceUrl || 'https://via.placeholder.com/150', // Fallback URL
256
+ elementProperties: {
257
+ pageObjectId: this.getObjectId(),
258
+ size: {
259
+ width: { magnitude: width, unit: 'PT' },
260
+ height: { magnitude: height, unit: 'PT' }
261
+ },
262
+ transform: {
263
+ scaleX: 1,
264
+ scaleY: 1,
265
+ translateX: left,
266
+ translateY: top,
267
+ unit: 'PT'
268
+ }
269
+ }
270
+ }
271
+ }];
272
+
273
+ try {
274
+ Slides.Presentations.batchUpdate({ requests }, presentationId);
275
+ } catch (err) {
276
+ if (!err?.message?.includes('already exists')) throw err;
277
+ }
278
+
279
+ const elements = this.getPageElements();
280
+ const newElement = elements.find(e => e.getObjectId() === objectId);
281
+ if (!newElement) throw new Error('New image not found');
282
+ return newElement.asImage();
283
+ }
284
+
118
285
  /**
119
286
  * Deletes the slide.
120
287
  */
121
288
  remove() {
122
289
  const presentationId = this.__presentation.getId();
123
290
  try {
124
- Slides.Presentations.batchUpdate([{
291
+ Slides.Presentations.batchUpdate({ requests: [{
125
292
  deleteObject: {
126
293
  objectId: this.getObjectId()
127
294
  }
128
- }], presentationId);
295
+ }] }, presentationId);
129
296
  } catch (err) {
130
297
  // If not found, it's already deleted (perhaps on a previous timeouted attempt)
131
298
  if (!err?.message?.includes('not found')) throw err;
@@ -168,7 +335,7 @@ export class FakeSlide {
168
335
  }];
169
336
 
170
337
  try {
171
- Slides.Presentations.batchUpdate(requests, presentationId);
338
+ Slides.Presentations.batchUpdate({ requests }, presentationId);
172
339
  } catch (err) {
173
340
  if (!err?.message?.includes('already exists')) throw err;
174
341
  }
@@ -196,6 +363,31 @@ export class FakeSlide {
196
363
  return newElement.asShape();
197
364
  }
198
365
 
366
+ /**
367
+ * Groups all the specified page elements.
368
+ * @param {FakePageElement[]} elements The elements to group.
369
+ * @returns {FakeGroup} The new group.
370
+ */
371
+ group(elements) {
372
+ const presentationId = this.__presentation.getId();
373
+ const objectId = `group_${Math.random().toString(36).substring(2, 11)}`;
374
+ const childrenObjectIds = elements.map(e => e.getObjectId());
375
+
376
+ const requests = [{
377
+ groupObjects: {
378
+ groupObjectId: objectId,
379
+ childrenObjectIds
380
+ }
381
+ }];
382
+
383
+ Slides.Presentations.batchUpdate({ requests }, presentationId);
384
+
385
+ const allElements = this.getPageElements();
386
+ const newElement = allElements.find(e => e.getObjectId() === objectId);
387
+ if (!newElement) throw new Error('New group not found after batchUpdate');
388
+ return newElement.asGroup();
389
+ }
390
+
199
391
  /**
200
392
  * Inserts a text box.
201
393
  * @param {string} text The text to insert.
@@ -247,7 +439,7 @@ export class FakeSlide {
247
439
  }];
248
440
 
249
441
  try {
250
- Slides.Presentations.batchUpdate(requests, presentationId);
442
+ Slides.Presentations.batchUpdate({ requests }, presentationId);
251
443
  } catch (err) {
252
444
  if (!err?.message?.includes('already exists')) throw err;
253
445
  }
@@ -324,7 +516,7 @@ export class FakeSlide {
324
516
  }
325
517
 
326
518
  try {
327
- Slides.Presentations.batchUpdate([request], presentationId);
519
+ Slides.Presentations.batchUpdate({ requests: [request] }, presentationId);
328
520
  } catch (err) {
329
521
  if (!err?.message?.includes('already exists')) throw err;
330
522
  }
@@ -339,16 +531,16 @@ export class FakeSlide {
339
531
  if (typeof rowsOrTable !== 'number') {
340
532
  const sourceTable = rowsOrTable;
341
533
  const targetTable = newTable;
342
- const rows = sourceTable.getRows();
343
- const targetRows = targetTable.getRows();
344
-
345
- for (let r = 0; r < rows.length; r++) {
346
- const cells = rows[r].getCells();
347
- const targetCells = targetRows[r].getCells();
348
- for (let c = 0; c < cells.length; c++) {
349
- const text = cells[c].getText().asString();
534
+ const numRows = sourceTable.getNumRows();
535
+
536
+ for (let r = 0; r < numRows; r++) {
537
+ const sourceRow = sourceTable.getRow(r);
538
+ const targetRow = targetTable.getRow(r);
539
+ const numCells = sourceRow.getNumCells();
540
+ for (let c = 0; c < numCells; c++) {
541
+ const text = sourceRow.getCell(c).getText().asString();
350
542
  if (text) {
351
- targetCells[c].getText().setText(text);
543
+ targetRow.getCell(c).getText().setText(text);
352
544
  }
353
545
  }
354
546
  }
@@ -370,7 +562,7 @@ export class FakeSlide {
370
562
  }];
371
563
 
372
564
  try {
373
- Slides.Presentations.batchUpdate(requests, presentationId);
565
+ Slides.Presentations.batchUpdate({ requests }, presentationId);
374
566
  } catch (err) {
375
567
  if (!err?.message?.includes('already exists')) throw err;
376
568
  }
@@ -388,12 +580,12 @@ export class FakeSlide {
388
580
  move(index) {
389
581
  const presentationId = this.__presentation.getId();
390
582
 
391
- Slides.Presentations.batchUpdate([{
583
+ Slides.Presentations.batchUpdate({ requests: [{
392
584
  updateSlidesPosition: {
393
585
  slideObjectIds: [this.getObjectId()],
394
586
  insertionIndex: index
395
587
  }
396
- }], presentationId);
588
+ }] }, presentationId);
397
589
  }
398
590
 
399
591
  /**
@@ -416,7 +608,7 @@ export class FakeSlide {
416
608
  }
417
609
  }];
418
610
 
419
- const response = Slides.Presentations.batchUpdate(requests, presentationId);
611
+ const response = Slides.Presentations.batchUpdate({ requests }, presentationId);
420
612
  return response.replies[0].replaceAllText.occurrencesChanged || 0;
421
613
  }
422
614
 
@@ -0,0 +1,45 @@
1
+ import { Proxies } from '../../support/proxies.js';
2
+ import { newFakeColorBuilder } from '../common/fakecolorbuilder.js';
3
+ import { ThemeColorType } from '../enums/slidesenums.js';
4
+
5
+ export const newFakeSolidFill = (...args) => {
6
+ return Proxies.guard(new FakeSolidFill(...args));
7
+ };
8
+
9
+ export class FakeSolidFill {
10
+ constructor(fill) {
11
+ this.__fill = fill;
12
+ }
13
+
14
+ get __solidFill() {
15
+ return this.__fill.__fill.solidFill || {};
16
+ }
17
+
18
+ getAlpha() {
19
+ return this.__solidFill.alpha !== undefined ? this.__solidFill.alpha : 1.0;
20
+ }
21
+
22
+ getColor() {
23
+ const apiColor = this.__solidFill.color || {};
24
+ const builder = newFakeColorBuilder();
25
+
26
+ const rgb = apiColor.rgbColor;
27
+ if (rgb) {
28
+ const hex = '#' + [rgb.red, rgb.green, rgb.blue].map(v => {
29
+ const val = Math.round((v || 0) * 255);
30
+ const hex = val.toString(16);
31
+ return hex.length === 1 ? '0' + hex : hex;
32
+ }).join('');
33
+ builder.setRgbColor(hex);
34
+ } else if (apiColor.themeColor) {
35
+ builder.setThemeColor(ThemeColorType[apiColor.themeColor]);
36
+ } else {
37
+ builder.setRgbColor('#FFFFFF');
38
+ }
39
+ return builder.build();
40
+ }
41
+
42
+ toString() {
43
+ return 'SolidFill';
44
+ }
45
+ }
@@ -0,0 +1,18 @@
1
+ import { Proxies } from '../../support/proxies.js';
2
+ import { FakePageElement, PageElementRegistry } from './fakepageelement.js';
3
+
4
+ export const newFakeSpeakerSpotlight = (...args) => {
5
+ return Proxies.guard(new FakeSpeakerSpotlight(...args));
6
+ };
7
+
8
+ PageElementRegistry.newFakeSpeakerSpotlight = newFakeSpeakerSpotlight;
9
+
10
+ export class FakeSpeakerSpotlight extends FakePageElement {
11
+ constructor(resource, page) {
12
+ super(resource, page);
13
+ }
14
+
15
+ toString() {
16
+ return 'SpeakerSpotlight';
17
+ }
18
+ }