@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.
- package/README.md +17 -3
- package/package.json +1 -1
- package/pngs/srv.jpg +0 -0
- package/src/cli/app.js +1 -0
- package/src/cli/togas.js +23 -14
- package/src/index.js +1 -0
- package/src/services/advslides/fakeadvslides.js +11 -5
- package/src/services/base/app.js +9 -0
- package/src/services/base/fakebase.js +28 -0
- package/src/services/common/fakeadvresource.js +3 -2
- package/src/services/content/contentservice.js +3 -2
- package/src/services/enums/baseenums.js +47 -0
- package/src/services/enums/contentenums.js +1 -3
- package/src/services/enums/scriptenums.js +31 -4
- package/src/services/enums/slidesenums.js +3 -1
- package/src/services/enums/xmlenums.js +14 -0
- package/src/services/html/serverworker.js +1 -1
- package/src/services/scriptapp/app.js +14 -7
- package/src/services/scriptapp/fakeauthorizationinfo.js +4 -4
- package/src/services/slidesapp/app.js +5 -0
- package/src/services/slidesapp/fakeautofit.js +1 -1
- package/src/services/slidesapp/fakeborder.js +106 -0
- package/src/services/slidesapp/fakecolorscheme.js +1 -1
- package/src/services/slidesapp/fakefill.js +216 -0
- package/src/services/slidesapp/fakegroup.js +35 -0
- package/src/services/slidesapp/fakeimage.js +118 -0
- package/src/services/slidesapp/fakelayout.js +351 -0
- package/src/services/slidesapp/fakeline.js +2 -2
- package/src/services/slidesapp/fakelinefill.js +15 -16
- package/src/services/slidesapp/fakelink.js +20 -3
- package/src/services/slidesapp/fakelist.js +36 -0
- package/src/services/slidesapp/fakeliststyle.js +105 -0
- package/src/services/slidesapp/fakemaster.js +358 -0
- package/src/services/slidesapp/fakenotesmaster.js +125 -0
- package/src/services/slidesapp/fakenotespage.js +102 -2
- package/src/services/slidesapp/fakepagebackground.js +109 -1
- package/src/services/slidesapp/fakepageelement.js +157 -18
- package/src/services/slidesapp/fakepageelementrange.js +28 -0
- package/src/services/slidesapp/fakepagerange.js +28 -0
- package/src/services/slidesapp/fakeparagraphstyle.js +139 -0
- package/src/services/slidesapp/fakepicturefill.js +32 -0
- package/src/services/slidesapp/fakepresentation.js +126 -2
- package/src/services/slidesapp/fakeshape.js +9 -0
- package/src/services/slidesapp/fakeslide.js +216 -24
- package/src/services/slidesapp/fakesolidfill.js +45 -0
- package/src/services/slidesapp/fakespeakerspotlight.js +18 -0
- package/src/services/slidesapp/faketable.js +55 -9
- package/src/services/slidesapp/faketablecell.js +141 -12
- package/src/services/slidesapp/faketablecellrange.js +28 -0
- package/src/services/slidesapp/faketablecolumn.js +72 -0
- package/src/services/slidesapp/faketablerow.js +31 -0
- package/src/services/slidesapp/faketextrange.js +179 -135
- package/src/services/slidesapp/faketextstyle.js +158 -0
- package/src/services/slidesapp/fakevideo.js +35 -0
- package/src/services/slidesapp/fakewordart.js +22 -0
- package/src/services/slidesapp/pageelementfactory.js +24 -1
- package/src/services/spreadsheetapp/fakeembeddedchartbuilder.js +92 -12
- package/src/services/spreadsheetapp/fakespreadsheet.js +360 -62
- package/src/services/spreadsheetapp/fakespreadsheettheme.js +53 -0
- package/src/services/urlfetchapp/app.js +216 -175
- package/src/services/xmlservice/app.js +3 -78
- package/src/services/xmlservice/fakeattribute.js +15 -0
- package/src/services/xmlservice/fakecdata.js +40 -0
- package/src/services/xmlservice/fakecomment.js +34 -0
- package/src/services/xmlservice/fakecontent.js +51 -0
- package/src/services/xmlservice/fakedoctype.js +68 -0
- package/src/services/xmlservice/fakedocument.js +110 -13
- package/src/services/xmlservice/fakeelement.js +297 -82
- package/src/services/xmlservice/fakeentityref.js +54 -0
- package/src/services/xmlservice/fakeformat.js +67 -22
- package/src/services/xmlservice/fakeprocessinginstruction.js +44 -0
- package/src/services/xmlservice/faketext.js +39 -0
- package/src/services/xmlservice/fakexmlservice.js +118 -0
- package/src/support/sxfetch.js +60 -0
- package/tools/omlx.env.example +6 -0
- 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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
21
|
-
|
|
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
|
+
}
|