@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 { newFakeMaster } from './fakemaster.js';
3
3
  import { newFakeColorScheme } from './fakecolorscheme.js';
4
+ import { newFakePageBackground } from './fakepagebackground.js';
5
+ import { newFakePageElement, PageElementRegistry } from './fakepageelement.js';
4
6
 
5
7
  export const newFakeLayout = (...args) => {
6
8
  return Proxies.guard(new FakeLayout(...args));
@@ -21,6 +23,10 @@ export class FakeLayout {
21
23
  return layout;
22
24
  }
23
25
 
26
+ getLayoutName() {
27
+ return this.__resource.layoutProperties?.name || '';
28
+ }
29
+
24
30
  getMaster() {
25
31
  const masterId = this.__resource.layoutProperties?.masterObjectId;
26
32
  if (!masterId) return null;
@@ -34,6 +40,14 @@ export class FakeLayout {
34
40
  return this.__id;
35
41
  }
36
42
 
43
+ /**
44
+ * Gets the background of the layout.
45
+ * @returns {FakePageBackground} The background.
46
+ */
47
+ getBackground() {
48
+ return newFakePageBackground(this);
49
+ }
50
+
37
51
  /**
38
52
  * Gets the color scheme of the layout.
39
53
  * @returns {FakeColorScheme} The color scheme.
@@ -42,6 +56,343 @@ export class FakeLayout {
42
56
  return newFakeColorScheme(this);
43
57
  }
44
58
 
59
+ /**
60
+ * Gets the type of the page.
61
+ * @returns {SlidesApp.PageType}
62
+ */
63
+ getPageType() {
64
+ return SlidesApp.PageType.LAYOUT;
65
+ }
66
+
67
+ /**
68
+ * Gets the list of page elements on the layout.
69
+ * @returns {FakePageElement[]} The page elements.
70
+ */
71
+ getPageElements() {
72
+ return (this.__resource.pageElements || []).map(pe => newFakePageElement(pe, this));
73
+ }
74
+
75
+ /**
76
+ * Gets a page element by ID.
77
+ * @param {string} id The ID.
78
+ * @returns {FakePageElement|null} The element.
79
+ */
80
+ getPageElementById(id) {
81
+ return this.getPageElements().find(pe => pe.getObjectId() === id) || null;
82
+ }
83
+
84
+ getGroups() {
85
+ return this.getPageElements()
86
+ .filter(pe => pe.getPageElementType().toString() === 'GROUP')
87
+ .map(pe => pe.asGroup());
88
+ }
89
+
90
+ getImages() {
91
+ return this.getPageElements()
92
+ .filter(pe => pe.getPageElementType().toString() === 'IMAGE')
93
+ .map(pe => pe.asImage());
94
+ }
95
+
96
+ getLines() {
97
+ return this.getPageElements()
98
+ .filter(pe => pe.getPageElementType().toString() === 'LINE')
99
+ .map(pe => pe.asLine());
100
+ }
101
+
102
+ getShapes() {
103
+ return this.getPageElements()
104
+ .filter(pe => pe.getPageElementType().toString() === 'SHAPE')
105
+ .map(pe => pe.asShape());
106
+ }
107
+
108
+ getTables() {
109
+ return this.getPageElements()
110
+ .filter(pe => pe.getPageElementType().toString() === 'TABLE')
111
+ .map(pe => pe.asTable());
112
+ }
113
+
114
+ getVideos() {
115
+ return this.getPageElements()
116
+ .filter(pe => pe.getPageElementType().toString() === 'VIDEO')
117
+ .map(pe => pe.asVideo());
118
+ }
119
+
120
+ getWordArts() {
121
+ return this.getPageElements()
122
+ .filter(pe => pe.getPageElementType().toString() === 'WORD_ART')
123
+ .map(pe => pe.asWordArt());
124
+ }
125
+
126
+ getSheetsCharts() {
127
+ return this.getPageElements()
128
+ .filter(pe => pe.getPageElementType().toString() === 'SHEETS_CHART')
129
+ .map(pe => pe.asSheetsChart());
130
+ }
131
+
132
+ /**
133
+ * Inserts a Google Sheets chart on the layout.
134
+ * @param {EmbeddedChart} chart The chart.
135
+ * @returns {SheetsChart} The inserted chart.
136
+ */
137
+ insertSheetsChart(chart) {
138
+ const presentationId = this.__presentation.getId();
139
+ const objectId = `chart_${Math.random().toString(36).substring(2, 11)}`;
140
+ const spreadsheetId = chart.getSpreadsheetId ? chart.getSpreadsheetId() : '';
141
+ const chartId = chart.getChartId ? chart.getChartId() : 0;
142
+
143
+ const requests = [{
144
+ createSheetsChart: {
145
+ objectId,
146
+ spreadsheetId,
147
+ chartId,
148
+ linkingMode: 'LINKED',
149
+ elementProperties: {
150
+ pageObjectId: this.getObjectId(),
151
+ size: {
152
+ width: { magnitude: 400, unit: 'PT' },
153
+ height: { magnitude: 300, unit: 'PT' }
154
+ }
155
+ }
156
+ }
157
+ }];
158
+
159
+ Slides.Presentations.batchUpdate({ requests }, presentationId);
160
+ return this.getPageElementById(objectId).asSheetsChart();
161
+ }
162
+
163
+ /**
164
+ * Inserts a Google Sheets chart as an image on the layout.
165
+ * @param {EmbeddedChart} chart The chart.
166
+ * @returns {Image} The inserted image.
167
+ */
168
+ insertSheetsChartAsImage(chart) {
169
+ const presentationId = this.__presentation.getId();
170
+ const objectId = `chart_img_${Math.random().toString(36).substring(2, 11)}`;
171
+ const requests = [{
172
+ createImage: {
173
+ objectId,
174
+ url: 'https://via.placeholder.com/400x300?text=Sheets+Chart',
175
+ elementProperties: {
176
+ pageObjectId: this.getObjectId()
177
+ }
178
+ }
179
+ }];
180
+ Slides.Presentations.batchUpdate({ requests }, presentationId);
181
+ return this.getPageElementById(objectId).asImage();
182
+ }
183
+
184
+ getPlaceholders() {
185
+ // Basic implementation filtering elements with placeholder property
186
+ return this.getPageElements().filter(pe => pe.__resource.shape?.placeholder || pe.__resource.image?.placeholder);
187
+ }
188
+
189
+ getPlaceholder(placeholderType, index = 0) {
190
+ const typeStr = placeholderType.toString();
191
+ return this.getPlaceholders().find(p => {
192
+ const ph = p.__resource.shape?.placeholder || p.__resource.image?.placeholder;
193
+ return ph.type === typeStr && (ph.index === index || (index === 0 && ph.index === undefined));
194
+ }) || null;
195
+ }
196
+
197
+ /**
198
+ * Inserts a shape.
199
+ */
200
+ insertShape(shapeType, left = 0, top = 0, width = 300, height = 300) {
201
+ const presentationId = this.__presentation.getId();
202
+ const objectId = `shape_${Math.random().toString(36).substring(2, 11)}`;
203
+ const requests = [{
204
+ createShape: {
205
+ objectId,
206
+ shapeType: shapeType.toString(),
207
+ elementProperties: {
208
+ pageObjectId: this.getObjectId(),
209
+ size: {
210
+ width: { magnitude: width, unit: 'PT' },
211
+ height: { magnitude: height, unit: 'PT' }
212
+ },
213
+ transform: {
214
+ scaleX: 1,
215
+ scaleY: 1,
216
+ translateX: left,
217
+ translateY: top,
218
+ unit: 'PT'
219
+ }
220
+ }
221
+ }
222
+ }];
223
+
224
+ Slides.Presentations.batchUpdate({ requests }, presentationId);
225
+ return this.getPageElementById(objectId).asShape();
226
+ }
227
+
228
+ insertTextBox(text, left = 0, top = 0, width = 300, height = 50) {
229
+ const shape = this.insertShape(SlidesApp.ShapeType.TEXT_BOX, left, top, width, height);
230
+ if (text) shape.getText().setText(text);
231
+ return shape;
232
+ }
233
+
234
+ insertTable(rows, columns, left = 0, top = 0, width = 300, height = 300) {
235
+ const presentationId = this.__presentation.getId();
236
+ const objectId = `table_${Math.random().toString(36).substring(2, 11)}`;
237
+ const requests = [{
238
+ createTable: {
239
+ objectId,
240
+ rows,
241
+ columns,
242
+ elementProperties: {
243
+ pageObjectId: this.getObjectId(),
244
+ size: {
245
+ width: { magnitude: width, unit: 'PT' },
246
+ height: { magnitude: height, unit: 'PT' }
247
+ },
248
+ transform: {
249
+ scaleX: 1,
250
+ scaleY: 1,
251
+ translateX: left,
252
+ translateY: top,
253
+ unit: 'PT'
254
+ }
255
+ }
256
+ }
257
+ }];
258
+
259
+ Slides.Presentations.batchUpdate({ requests }, presentationId);
260
+ return this.getPageElementById(objectId).asTable();
261
+ }
262
+
263
+ /**
264
+ * Inserts a video at the top left corner of the layout.
265
+ * @param {string} videoUrl The video URL.
266
+ * @param {number} [left]
267
+ * @param {number} [top]
268
+ * @param {number} [width]
269
+ * @param {number} [height]
270
+ * @returns {FakeVideo} The inserted video.
271
+ */
272
+ insertVideo(videoUrl, left = 0, top = 0, width = 300, height = 200) {
273
+ const presentationId = this.__presentation.getId();
274
+ const objectId = `video_${Math.random().toString(36).substring(2, 11)}`;
275
+
276
+ let videoId = videoUrl;
277
+ if (videoUrl.includes('v=')) {
278
+ videoId = videoUrl.split('v=')[1].split('&')[0];
279
+ } else if (videoUrl.includes('youtu.be/')) {
280
+ videoId = videoUrl.split('youtu.be/')[1].split('?')[0];
281
+ }
282
+
283
+ const requests = [{
284
+ createVideo: {
285
+ objectId,
286
+ source: 'YOUTUBE',
287
+ id: videoId,
288
+ elementProperties: {
289
+ pageObjectId: this.getObjectId(),
290
+ size: {
291
+ width: { magnitude: width, unit: 'PT' },
292
+ height: { magnitude: height, unit: 'PT' }
293
+ },
294
+ transform: {
295
+ scaleX: 1,
296
+ scaleY: 1,
297
+ translateX: left,
298
+ translateY: top,
299
+ unit: 'PT'
300
+ }
301
+ }
302
+ }
303
+ }];
304
+
305
+ Slides.Presentations.batchUpdate({ requests }, presentationId);
306
+ return this.getPageElementById(objectId).asVideo();
307
+ }
308
+
309
+ insertImage(urlOrBlob, left = 0, top = 0, width = 300, height = 300) {
310
+ const presentationId = this.__presentation.getId();
311
+ const objectId = `image_${Math.random().toString(36).substring(2, 11)}`;
312
+ let url = typeof urlOrBlob === 'string' ? urlOrBlob : '';
313
+ // If blob, we'd need to upload it or mock it. For now assuming URL or empty.
314
+
315
+ const requests = [{
316
+ createImage: {
317
+ objectId,
318
+ url: url || 'https://via.placeholder.com/150',
319
+ elementProperties: {
320
+ pageObjectId: this.getObjectId(),
321
+ size: {
322
+ width: { magnitude: width, unit: 'PT' },
323
+ height: { magnitude: height, unit: 'PT' }
324
+ },
325
+ transform: {
326
+ scaleX: 1,
327
+ scaleY: 1,
328
+ translateX: left,
329
+ translateY: top,
330
+ unit: 'PT'
331
+ }
332
+ }
333
+ }
334
+ }];
335
+
336
+ Slides.Presentations.batchUpdate({ requests }, presentationId);
337
+ return this.getPageElementById(objectId).asImage();
338
+ }
339
+
340
+ insertLine(lineCategory, startX, startY, endX, endY) {
341
+ const presentationId = this.__presentation.getId();
342
+ const objectId = `line_${Math.random().toString(36).substring(2, 11)}`;
343
+ const requests = [{
344
+ createLine: {
345
+ objectId,
346
+ lineCategory: lineCategory.toString(),
347
+ elementProperties: {
348
+ pageObjectId: this.getObjectId(),
349
+ size: {
350
+ width: { magnitude: Math.abs(endX - startX), unit: 'PT' },
351
+ height: { magnitude: Math.abs(endY - startY), unit: 'PT' }
352
+ },
353
+ transform: {
354
+ scaleX: 1,
355
+ scaleY: 1,
356
+ translateX: Math.min(startX, endX),
357
+ translateY: Math.min(startY, endY),
358
+ unit: 'PT'
359
+ }
360
+ }
361
+ }
362
+ }];
363
+
364
+ Slides.Presentations.batchUpdate({ requests }, presentationId);
365
+ return this.getPageElementById(objectId).asLine();
366
+ }
367
+
368
+ remove() {
369
+ const presentationId = this.__presentation.getId();
370
+ Slides.Presentations.batchUpdate({ requests: [{
371
+ deleteObject: {
372
+ objectId: this.getObjectId()
373
+ }
374
+ }] }, presentationId);
375
+ }
376
+
377
+ replaceAllText(findText, replaceText, matchCase = false) {
378
+ const presentationId = this.__presentation.getId();
379
+ Slides.Presentations.batchUpdate({ requests: [{
380
+ replaceAllText: {
381
+ replaceText,
382
+ containsText: {
383
+ text: findText,
384
+ matchCase
385
+ },
386
+ pageObjectIds: [this.getObjectId()]
387
+ }
388
+ }] }, presentationId);
389
+ return this;
390
+ }
391
+
392
+ selectAsCurrentPage() {
393
+ return this;
394
+ }
395
+
45
396
  toString() {
46
397
  return 'Layout';
47
398
  }
@@ -180,13 +180,13 @@ export class FakeLine extends FakePageElement {
180
180
 
181
181
  __updateLineProps(lineProperties, fields) {
182
182
  const presentationId = this.__page.__presentation?.getId() || this.__page.__slide?.__presentation.getId();
183
- Slides.Presentations.batchUpdate([{
183
+ Slides.Presentations.batchUpdate({ requests: [{
184
184
  updateLineProperties: {
185
185
  objectId: this.getObjectId(),
186
186
  lineProperties: lineProperties,
187
187
  fields: fields
188
188
  }
189
- }], presentationId);
189
+ }] }, presentationId);
190
190
  }
191
191
 
192
192
  toString() {
@@ -14,32 +14,31 @@ export class FakeLineFill {
14
14
  }
15
15
 
16
16
  getSolidFill() {
17
- // This should return a SolidFill object
18
- // For now we might need a FakeSolidFill or just return something simple
19
17
  return null;
20
18
  }
21
19
 
22
20
  setSolidFill(color) {
23
- // Implementing this requires updateLineProperties with solidFill
24
21
  const presentationId = this.__line.__page.__presentation?.getId() || this.__line.__page.__slide?.__presentation.getId();
25
22
 
26
23
  let solidFill = {};
27
24
  if (typeof color === 'string') {
28
25
  solidFill = { color: { rgbColor: this.__hexToRgb(color) } };
29
26
  }
30
- // Handle other color types if needed
31
-
32
- Slides.Presentations.batchUpdate([{
33
- updateLineProperties: {
34
- objectId: this.__line.getObjectId(),
35
- lineProperties: {
36
- lineFill: {
37
- solidFill: solidFill
38
- }
39
- },
40
- fields: 'lineFill.solidFill'
41
- }
42
- }], presentationId);
27
+
28
+ Slides.Presentations.batchUpdate({
29
+ requests: [{
30
+ updateLineProperties: {
31
+ objectId: this.__line.getObjectId(),
32
+ lineProperties: {
33
+ lineFill: {
34
+ solidFill: solidFill
35
+ }
36
+ },
37
+ fields: 'lineFill.solidFill'
38
+ }
39
+ }]
40
+ }, presentationId);
41
+
43
42
  return this;
44
43
  }
45
44
 
@@ -5,8 +5,9 @@ export const newFakeLink = (...args) => {
5
5
  };
6
6
 
7
7
  export class FakeLink {
8
- constructor(resource) {
8
+ constructor(resource, presentation) {
9
9
  this.__resource = resource;
10
+ this.__presentation = presentation;
10
11
  }
11
12
 
12
13
  getLinkType() {
@@ -17,14 +18,30 @@ export class FakeLink {
17
18
  return 'NONE';
18
19
  }
19
20
 
20
- getUrl() {
21
- return this.__resource.url || null;
21
+ getLinkedSlide() {
22
+ const slideId = this.getSlideId();
23
+ return slideId ? this.__presentation.getSlideById(slideId) : null;
22
24
  }
23
25
 
24
26
  getSlideId() {
25
27
  return this.__resource.slideId || null;
26
28
  }
27
29
 
30
+ getSlideIndex() {
31
+ // Requires iterating slides to find index.
32
+ const slideId = this.getSlideId();
33
+ if (!slideId) return null;
34
+ return this.__presentation.getSlides().findIndex(s => s.getObjectId() === slideId);
35
+ }
36
+
37
+ getSlidePosition() {
38
+ return this.__resource.relativeSlide || null;
39
+ }
40
+
41
+ getUrl() {
42
+ return this.__resource.url || null;
43
+ }
44
+
28
45
  toString() {
29
46
  return 'Link';
30
47
  }
@@ -0,0 +1,36 @@
1
+ import { Proxies } from '../../support/proxies.js';
2
+ import { newFakeParagraph } from './fakeparagraph.js';
3
+ import { newFakeTextRange } from './faketextrange.js';
4
+
5
+ /**
6
+ * create a new FakeList instance
7
+ * @param {...any} args
8
+ * @returns {FakeList}
9
+ */
10
+ export const newFakeList = (...args) => {
11
+ return Proxies.guard(new FakeList(...args));
12
+ };
13
+
14
+ export class FakeList {
15
+ constructor(listId, presentation, shape) {
16
+ this.__listId = listId;
17
+ this.__presentation = presentation;
18
+ this.__shape = shape;
19
+ }
20
+
21
+ getListId() {
22
+ return this.__listId;
23
+ }
24
+
25
+ getListParagraphs() {
26
+ // Find all paragraphs in the shape that belong to this list
27
+ return this.__shape.getText().getParagraphs().filter(p => {
28
+ const style = p.getRange().getListStyle();
29
+ return style.isInList() && style.getList().getListId() === this.__listId;
30
+ });
31
+ }
32
+
33
+ toString() {
34
+ return 'List';
35
+ }
36
+ }
@@ -0,0 +1,105 @@
1
+ import { Proxies } from '../../support/proxies.js';
2
+ import { newFakeList } from './fakelist.js';
3
+
4
+ /**
5
+ * create a new FakeListStyle instance
6
+ * @param {...any} args
7
+ * @returns {FakeListStyle}
8
+ */
9
+ export const newFakeListStyle = (...args) => {
10
+ return Proxies.guard(new FakeListStyle(...args));
11
+ };
12
+
13
+ export class FakeListStyle {
14
+ constructor(textRange) {
15
+ this.__textRange = textRange;
16
+ }
17
+
18
+ get __bullet() {
19
+ // Find first paragraph marker with bullet in range
20
+ const resource = this.__textRange.__resource;
21
+ const elements = resource?.textElements || [];
22
+ const start = this.__textRange.getStartIndex();
23
+
24
+ let currentIndex = 0;
25
+ for (const element of elements) {
26
+ const length = element.textRun?.content?.length || (element.autoText ? 1 : 0);
27
+ if (currentIndex >= start && element.paragraphMarker && element.paragraphMarker.bullet) {
28
+ return element.paragraphMarker.bullet;
29
+ }
30
+ currentIndex += length;
31
+ }
32
+ return null;
33
+ }
34
+
35
+ applyListPreset(preset) {
36
+ const presentationId = this.__textRange.__shape.__presentation.getId();
37
+ const objectId = this.__textRange.__shape.getObjectId();
38
+ const cellLocation = this.__textRange.__shape.__cellLocation;
39
+
40
+ Slides.Presentations.batchUpdate({ requests: [{
41
+ createParagraphBullets: {
42
+ objectId,
43
+ cellLocation,
44
+ bulletPreset: preset.toString(),
45
+ textRange: {
46
+ type: 'FIXED_RANGE',
47
+ startIndex: this.__textRange.getStartIndex(),
48
+ endIndex: this.__textRange.getEndIndex()
49
+ }
50
+ }
51
+ }] }, presentationId);
52
+ return this;
53
+ }
54
+
55
+ getGlyph() {
56
+ // API doesn't return the rendered glyph string directly easily.
57
+ return this.__bullet ? '•' : null;
58
+ }
59
+
60
+ getList() {
61
+ const bullet = this.__bullet;
62
+ if (!bullet) return null;
63
+ return newFakeList(bullet.listId, this.__textRange.__shape.__presentation, this.__textRange.__shape);
64
+ }
65
+
66
+ getNestingLevel() {
67
+ return this.__bullet?.nestingLevel || 0;
68
+ }
69
+
70
+ isInList() {
71
+ return !!this.__bullet;
72
+ }
73
+
74
+ removeFromList() {
75
+ const presentationId = this.__textRange.__shape.__presentation.getId();
76
+ const objectId = this.__textRange.__shape.getObjectId();
77
+ const cellLocation = this.__textRange.__shape.__cellLocation;
78
+
79
+ Slides.Presentations.batchUpdate({ requests: [{
80
+ deleteAllText: {
81
+ objectId,
82
+ cellLocation,
83
+ // Wait, deleteAllText is for all text.
84
+ // To remove bullets, we use deleteParagraphBullets.
85
+ }
86
+ }] }, presentationId);
87
+ // Correct request is deleteParagraphBullets
88
+ Slides.Presentations.batchUpdate({ requests: [{
89
+ deleteParagraphBullets: {
90
+ objectId,
91
+ cellLocation,
92
+ textRange: {
93
+ type: 'FIXED_RANGE',
94
+ startIndex: this.__textRange.getStartIndex(),
95
+ endIndex: this.__textRange.getEndIndex()
96
+ }
97
+ }
98
+ }] }, presentationId);
99
+ return this;
100
+ }
101
+
102
+ toString() {
103
+ return 'ListStyle';
104
+ }
105
+ }