├── .codeclimate.yml
├── DocumentAppp.js
├── ExcelApp.js
├── LICENCE
├── README.md
├── SlidesAppp.js
├── SpreadsheetAppp.js
├── WordApp.js
├── appsscript.json
├── images
├── demo1.png
├── fig1.png
├── fig2.png
├── fig3.png
├── fig4.png
└── fig5.png
└── mainMethods.js
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | ---
2 | engines:
3 | duplication:
4 | enabled: true
5 | config:
6 | languages:
7 | - ruby
8 | - javascript
9 | - python
10 | - php
11 | eslint:
12 | enabled: true
13 | fixme:
14 | enabled: true
15 | ratings:
16 | paths:
17 | - "**.inc"
18 | - "**.js"
19 | - "**.jsx"
20 | - "**.module"
21 | - "**.php"
22 | - "**.py"
23 | - "**.rb"
24 | exclude_paths:
25 | - "tests/"
26 | - "spec/"
27 | - "**/vendor/"
28 |
--------------------------------------------------------------------------------
/DocumentAppp.js:
--------------------------------------------------------------------------------
1 | // --- DocumentAppp (DocumentApp plus) ---
2 | (function(r) {
3 | var DocumentAppp;
4 | DocumentAppp = (function() {
5 | var gToM, putError, putInternalError;
6 |
7 | class DocumentAppp {
8 | constructor(id_) {
9 | this.name = "DocumentAppp";
10 | if (id_ !== "create") {
11 | if (id_ === "" || DriveApp.getFileById(id_).getMimeType() !== MimeType.GOOGLE_DOCS) {
12 | putError.call(this, "This file ID is not the file ID of Document.");
13 | }
14 | this.obj = {
15 | documentId: id_
16 | };
17 | }
18 | this.headers = {
19 | Authorization: `Bearer ${ScriptApp.getOAuthToken()}`
20 | };
21 | this.mainObj = {};
22 | }
23 |
24 | // --- begin methods
25 | getTableColumnWidth() {
26 | gToM.call(this);
27 | return new WordApp(this.mainObj.blob).getTableColumnWidth();
28 | }
29 |
30 | };
31 |
32 | DocumentAppp.name = "DocumentAppp";
33 |
34 | // --- end methods
35 | gToM = function() {
36 | var obj, url;
37 | url = `https://www.googleapis.com/drive/v3/files/${this.obj.documentId}/export?mimeType=${MimeType.MICROSOFT_WORD}`;
38 | obj = UrlFetchApp.fetch(url, {
39 | headers: this.headers
40 | });
41 | if (obj.getResponseCode() !== 200) {
42 | putError.call(this, "Document ID might be not correct. Please check it again.");
43 | }
44 | this.mainObj.blob = obj.getBlob();
45 | };
46 |
47 | putError = function(m) {
48 | throw new Error(`${m}`);
49 | };
50 |
51 | putInternalError = function(m) {
52 | throw new Error(`Internal error: ${m}`);
53 | };
54 |
55 | return DocumentAppp;
56 |
57 | }).call(this);
58 | return r.DocumentAppp = DocumentAppp;
59 | })(this);
60 |
--------------------------------------------------------------------------------
/ExcelApp.js:
--------------------------------------------------------------------------------
1 | // --- ExcelApp ---
2 | (function(r) {
3 | var ExcelApp;
4 | ExcelApp = (function() {
5 | var a1NotationToRowCol, columnToLetter, disassembleExcel, getCommentsAsObject, getImagesAsObject, getNamedFunctionsAsObject, getQuotePrefixCellsAsObject, getSharedStrings, getStyleAsObject, getValuesAsObject, getValuesFromObj, getXmlObj, letterToColumn, parsXLSX, putError, putInternalError, sheetNameToFileName;
6 |
7 | class ExcelApp {
8 | constructor(blob_) {
9 | this.name = "ExcelApp";
10 | if (!blob_ || blob_.getContentType() !== MimeType.MICROSOFT_EXCEL) {
11 | throw new Error("Please set the blob of data of XLSX format.");
12 | }
13 | this.obj = {
14 | excel: blob_
15 | };
16 | this.contentTypes = "[Content_Types].xml";
17 | this.sharedStrings = "xl/sharedStrings.xml";
18 | this.workbook = "xl/workbook.xml";
19 | this.styles = "xl/styles.xml";
20 | this.mainObj = {};
21 | parsXLSX.call(this);
22 | }
23 |
24 | // --- begin methods
25 | getSheetByName(sheetName_) {
26 | if (!sheetName_ || sheetName_.toString() === "") {
27 | putError.call(this, "No sheet name.");
28 | }
29 | this.obj.sheetName = sheetName_;
30 | return this;
31 | }
32 |
33 | getAll() {
34 | return this.mainObj.sheetsObj.sheetAr.map(({sheetName}, i) => {
35 | this.obj.sheetName = sheetName;
36 | return {
37 | sheetName: sheetName,
38 | values: getValuesAsObject.call(this),
39 | images: getImagesAsObject.call(this),
40 | comments: getCommentsAsObject.call(this)
41 | };
42 | });
43 | }
44 |
45 | getSheets() {
46 | return this.mainObj.sheetsObj.sheetAr.map(({sheetName}, i) => {
47 | return {
48 | index: i,
49 | sheetName: sheetName
50 | };
51 | });
52 | }
53 |
54 | getValues() {
55 | return getValuesFromObj.call(this, "value");
56 | }
57 |
58 | getFormulas() {
59 | return getValuesFromObj.call(this, "formula");
60 | }
61 |
62 | getImages() {
63 | return getImagesAsObject.call(this);
64 | }
65 |
66 | getComments() {
67 | return getCommentsAsObject.call(this);
68 | }
69 |
70 | getQuotePrefixCells() {
71 | return getQuotePrefixCellsAsObject.call(this);
72 | }
73 |
74 | getNamedFunctions() {
75 | return getNamedFunctionsAsObject.call(this);
76 | }
77 |
78 | };
79 |
80 | ExcelApp.name = "ExcelApp";
81 |
82 | // --- end methods
83 | getNamedFunctionsAsObject = function() {
84 | var definedNames, root, xmlObj1;
85 | xmlObj1 = getXmlObj.call(this, "xl/workbook.xml");
86 | root = xmlObj1.getRootElement();
87 | definedNames = root.getChild("definedNames", root.getNamespace()).getChildren();
88 | return definedNames.map((e) => {
89 | return {
90 | definedName: e.getAttribute("name").getValue(),
91 | definedFunction: e.getValue()
92 | };
93 | });
94 | };
95 |
96 | getQuotePrefixCellsAsObject = function() {
97 | var checkFilename, quotePrefix, sr, styler, xmlObj1, xmlObj2;
98 | if (this.mainObj.sheetsObj.sheetsObj.hasOwnProperty(this.obj.sheetName)) {
99 | checkFilename = this.mainObj.sheetsObj.sheetsObj[this.obj.sheetName].sheet;
100 | if (this.mainObj.fileObj.hasOwnProperty(checkFilename)) {
101 | xmlObj1 = getXmlObj.call(this, "xl/styles.xml");
102 | styler = xmlObj1.getRootElement();
103 | quotePrefix = styler.getChild("cellXfs", styler.getNamespace()).getChildren().map((e) => {
104 | if (e.getAttribute("quotePrefix")) {
105 | return true;
106 | } else {
107 | return false;
108 | }
109 | });
110 | xmlObj2 = getXmlObj.call(this, checkFilename);
111 | sr = xmlObj2.getRootElement();
112 | return sr.getChild("sheetData", sr.getNamespace()).getChildren().reduce((ar, r, i) => {
113 | r.getChildren().forEach((c, j) => {
114 | var v;
115 | r = c.getAttribute("r").getValue();
116 | v = Number(c.getAttribute("s").getValue());
117 | if (quotePrefix[v]) {
118 | return ar.push(r);
119 | }
120 | });
121 | return ar;
122 | }, []);
123 | }
124 | }
125 | };
126 |
127 | parsXLSX = function() {
128 | disassembleExcel.call(this);
129 | getSharedStrings.call(this);
130 | getStyleAsObject.call(this);
131 | sheetNameToFileName.call(this);
132 | };
133 |
134 | disassembleExcel = function() {
135 | var blobs;
136 | blobs = Utilities.unzip(this.obj.excel.setContentType(MimeType.ZIP));
137 | this.mainObj.fileObj = blobs.reduce((o, b) => {
138 | return Object.assign(o, {
139 | [b.getName()]: b
140 | });
141 | }, {});
142 | };
143 |
144 | getSharedStrings = function() {
145 | var rootChildren, xmlObj;
146 | if (this.mainObj.fileObj.hasOwnProperty(this.sharedStrings)) {
147 | xmlObj = getXmlObj.call(this, this.sharedStrings);
148 | rootChildren = xmlObj.getRootElement().getChildren();
149 | this.mainObj.valueSharedStrings = rootChildren.map((e) => {
150 | var temp;
151 | temp = e.getChild("t", e.getNamespace());
152 | if (temp) {
153 | return temp.getValue();
154 | } else {
155 | return "";
156 | }
157 | });
158 | } else {
159 | putInternalError.call(this, "This Excel data cannot be analyzed.");
160 | }
161 | };
162 |
163 | sheetNameToFileName = function() {
164 | var rootChildren, sheets, xmlObj;
165 | if (this.mainObj.fileObj.hasOwnProperty(this.workbook)) {
166 | xmlObj = getXmlObj.call(this, this.workbook);
167 | rootChildren = xmlObj.getRootElement();
168 | sheets = rootChildren.getChild("sheets", rootChildren.getNamespace()).getChildren();
169 | return this.mainObj.sheetsObj = sheets.reduce((o, e) => {
170 | var sheetId, sheetName;
171 | sheetId = e.getAttribute("sheetId").getValue();
172 | sheetName = e.getAttribute("name").getValue();
173 | Object.assign(o.sheetsObj, {
174 | [sheetName]: {
175 | sheet: `xl/worksheets/sheet${sheetId}.xml`,
176 | rels: `xl/worksheets/_rels/sheet${sheetId}.xml.rels`
177 | }
178 | });
179 | o.sheetAr.push({
180 | sheetIndex: sheetId,
181 | sheetName: sheetName
182 | });
183 | return o;
184 | }, {
185 | sheetsObj: {},
186 | sheetAr: []
187 | });
188 | } else {
189 | return putInternalError.call(this, "This Excel data cannot be analyzed.");
190 | }
191 | };
192 |
193 | getStyleAsObject = function() {
194 | var cellXfs, cellXfsC, fills, fillsC, fillsObj, fonts, fontsC, fontsObj, numFmts, numFmtsC, numFmtsObj, root, styleObj, xmlObj;
195 | if (this.mainObj.fileObj.hasOwnProperty(this.styles)) {
196 | xmlObj = getXmlObj.call(this, this.styles);
197 | root = xmlObj.getRootElement();
198 | numFmtsC = root.getChild("numFmts", root.getNamespace());
199 | if (numFmtsC) {
200 | numFmts = numFmtsC.getChildren();
201 | numFmtsObj = numFmts.reduce((o, e) => {
202 | return Object.assign(o, {
203 | [e.getAttribute("numFmtId").getValue()]: e.getAttribute("formatCode").getValue()
204 | });
205 | }, {});
206 | }
207 | fontsC = root.getChild("fonts", root.getNamespace());
208 | if (fontsC) {
209 | fonts = fontsC.getChildren();
210 | fontsObj = fonts.map((e) => {
211 | return e.getChildren().reduce((o, f) => {
212 | return Object.assign(o, {
213 | [f.getName()]: f.getAttributes().reduce((o2, g) => {
214 | return Object.assign(o2, {
215 | [g.getName()]: g.getValue() || true
216 | });
217 | }, {})
218 | });
219 | }, {});
220 | });
221 | }
222 | fillsC = root.getChild("fills", root.getNamespace());
223 | if (fillsC) {
224 | fills = fillsC.getChildren();
225 | fillsObj = fills.map((e) => {
226 | var c, children, temp;
227 | c = e.getChild("patternFill", e.getNamespace());
228 | temp = {
229 | patternType: c.getAttribute("patternType").getValue()
230 | };
231 | children = c.getChildren();
232 | if (children.length > 0) {
233 | children.forEach((f) => {
234 | return temp[f.getName()] = f.getAttributes().reduce((o, g) => {
235 | return Object.assign(o, {
236 | [g.getName()]: g.getValue() || true
237 | });
238 | }, {});
239 | });
240 | }
241 | return temp;
242 | });
243 | }
244 | cellXfsC = root.getChild("cellXfs", root.getNamespace());
245 | if (cellXfsC) {
246 | cellXfs = cellXfsC.getChildren();
247 | styleObj = cellXfs.map((e) => {
248 | return e.getAttributes().reduce((o, f) => {
249 | var c, n, v;
250 | n = f.getName();
251 | v = f.getValue();
252 | switch (n) {
253 | case "numFmtId":
254 | o.numFmt = numFmtsObj ? numFmtsObj[v] || null : null;
255 | break;
256 | case "fontId":
257 | o.font = fontsObj ? fontsObj[v] || null : null;
258 | break;
259 | case "fillId":
260 | o.fill = fillsObj ? fillsObj[v] || null : null;
261 | }
262 | c = e.getChild("alignment", e.getNamespace());
263 | if (c) {
264 | o.alignment = c.getAttributes().reduce((o2, g) => {
265 | return Object.assign(o2, {
266 | [g.getName()]: g.getValue() || true
267 | });
268 | }, {});
269 | }
270 | return o;
271 | }, {});
272 | });
273 | return this.mainObj.styleObj = styleObj;
274 | }
275 | } else {
276 | return putInternalError.call(this, "Style file cannot be used.");
277 | }
278 | };
279 |
280 | getValuesAsObject = function() {
281 | var checkFilename, root, rows, sheetData, xmlObj;
282 | if (this.mainObj.sheetsObj.sheetsObj.hasOwnProperty(this.obj.sheetName)) {
283 | checkFilename = this.mainObj.sheetsObj.sheetsObj[this.obj.sheetName].sheet;
284 | if (this.mainObj.fileObj.hasOwnProperty(checkFilename)) {
285 | xmlObj = getXmlObj.call(this, checkFilename);
286 | root = xmlObj.getRootElement();
287 | sheetData = root.getChild("sheetData", root.getNamespace()).getChildren();
288 | rows = [];
289 | sheetData.forEach((s) => {
290 | var cols, rowNum;
291 | cols = [];
292 | rowNum = 0;
293 | s.getChildren().forEach((c) => {
294 | var cObj, fv, fval, ra, sa, ta, tav, temp, tobj, vv, vval;
295 | vval = c.getChild("v", c.getNamespace());
296 | fval = c.getChild("f", c.getNamespace());
297 | ra = c.getAttribute("r");
298 | ta = c.getAttribute("t");
299 | sa = c.getAttribute("s");
300 | vv = "";
301 | fv = "";
302 | if (ta) {
303 | tav = ta.getValue();
304 | if (tav === "s") {
305 | if (vval) {
306 | vv = this.mainObj.valueSharedStrings[vval.getValue()];
307 | }
308 | if (fval) {
309 | fv = fval.getValue();
310 | }
311 | } else if (tav === "str") {
312 | if (vval) {
313 | vv = vval.getValue();
314 | }
315 | if (fval) {
316 | fv = fval.getValue();
317 | }
318 | } else if (tav === "b") {
319 | if (vval) {
320 | vv = vval.getValue() === "1" ? true : false;
321 | }
322 | if (fval) {
323 | fv = fval.getValue();
324 | }
325 | } else {
326 | if (vval) {
327 | vv = vval.getValue();
328 | }
329 | if (fval) {
330 | fv = fval.getValue();
331 | }
332 | }
333 | } else {
334 | if (vval) {
335 | vv = Number(vval.getValue());
336 | }
337 | if (fval) {
338 | fv = fval.getValue();
339 | }
340 | }
341 | if (ra) {
342 | temp = ra.getValue();
343 | cObj = a1NotationToRowCol.call(this, temp);
344 | rowNum = cObj.row;
345 | tobj = {};
346 | tobj.value = {};
347 | tobj.range = {};
348 | tobj.value.value = vv.toString() !== "" ? vv : null;
349 | tobj.value.formula = fv.toString() !== "" ? `=${fv}` : null;
350 | tobj.range.col = cObj.col;
351 | tobj.range.row = cObj.row;
352 | tobj.range.a1Notation = temp;
353 | if (sa) {
354 | tobj.style = this.mainObj.styleObj[sa.getValue()];
355 | }
356 | return cols[cObj.col - 1] = tobj;
357 | }
358 | });
359 | return rows[rowNum - 1] = cols;
360 | });
361 | return rows;
362 | } else {
363 | putInternalError.call(this, "No sheet file.");
364 | }
365 | } else {
366 | putInternalError.call(this, "No sheet name.");
367 | }
368 | };
369 |
370 | getImagesAsObject = function() {
371 | var drawingFilename, imageObj, rootChildren, xmlObj;
372 | if (!this.mainObj.sheetsObj.sheetsObj.hasOwnProperty(this.obj.sheetName)) {
373 | putError.call(this, "No sheet name.");
374 | }
375 | drawingFilename = this.mainObj.sheetsObj.sheetsObj[this.obj.sheetName].sheet.replace("worksheets", "drawings").replace("sheet", "drawing");
376 | if (this.mainObj.fileObj.hasOwnProperty(drawingFilename)) {
377 | xmlObj = getXmlObj.call(this, drawingFilename);
378 | rootChildren = xmlObj.getRootElement().getChildren();
379 | imageObj = rootChildren.map((e) => {
380 | var cNvPr, description, filename, form, formn, n, nvPicPr, nvPicPrn, pic, sp, temp, title;
381 | temp = {};
382 | n = e.getNamespace();
383 | form = e.getChild("from", n);
384 | formn = form.getNamespace();
385 | temp.range = {
386 | col: Number(form.getChild("col", formn).getValue()) + 1,
387 | colOff: Number(form.getChild("colOff", formn).getValue()),
388 | row: Number(form.getChild("row", formn).getValue()) + 1,
389 | rowOff: Number(form.getChild("rowOff", formn).getValue())
390 | };
391 | temp.range.a1Notation = (columnToLetter.call(this, temp.range.col)) + temp.range.row;
392 | pic = e.getChild("pic", n);
393 | sp = e.getChild("sp", n); // Drawing
394 | if (pic) {
395 | nvPicPr = pic.getChild("nvPicPr", pic.getNamespace());
396 | nvPicPrn = nvPicPr.getNamespace();
397 | cNvPr = nvPicPr.getChild("cNvPr", nvPicPrn);
398 | filename = "xl/media/" + cNvPr.getAttribute("name").getValue();
399 | temp.image = {};
400 | description = cNvPr.getAttribute("descr");
401 | if (description) {
402 | temp.image.description = description.getValue();
403 | }
404 | title = cNvPr.getAttribute("title");
405 | if (title) {
406 | temp.image.title = title.getValue();
407 | }
408 | temp.image.blob = (this.mainObj.fileObj[filename] && this.mainObj.fileObj[filename].setName(filename.split("/").pop())) || null;
409 | temp.image.innerCell = temp.range.colOff === 0 && temp.range.rowOff === 0 ? true : false;
410 | } else if (sp) {
411 | temp.drawing = {
412 | message: "In the current stage, the object of drawing cannot be directly retrieved as the blob."
413 | };
414 | }
415 | delete temp.range.colOff;
416 | delete temp.range.rowOff;
417 | return temp;
418 | });
419 | return imageObj;
420 | } else {
421 | return putInternalError.call(this, "Internal error: Image files cannot be retrieved.");
422 | }
423 | };
424 |
425 | getCommentsAsObject = function() {
426 | var checkFilename, commentFilename, commentList, comments, f, i, p, ref1, root, rootChildren, t, target, temp, xmlObj;
427 | commentFilename = "";
428 | if (this.mainObj.sheetsObj.sheetsObj.hasOwnProperty(this.obj.sheetName)) {
429 | checkFilename = this.mainObj.sheetsObj.sheetsObj[this.obj.sheetName].rels;
430 | if (this.mainObj.fileObj.hasOwnProperty(checkFilename)) {
431 | xmlObj = getXmlObj.call(this, checkFilename);
432 | rootChildren = xmlObj.getRootElement().getChildren();
433 | for (i = p = 0, ref1 = rootChildren.length; (0 <= ref1 ? p < ref1 : p > ref1); i = 0 <= ref1 ? ++p : --p) {
434 | target = rootChildren[i].getAttribute("Target");
435 | if (target) {
436 | t = target.getValue();
437 | if (t.includes("comments")) {
438 | commentFilename = t;
439 | break;
440 | }
441 | }
442 | }
443 | } else {
444 | putInternalError.call(this, "No sheet file.");
445 | }
446 | } else {
447 | putError.call(this, "No sheet name.");
448 | }
449 | temp = commentFilename.split("\/")[1];
450 | f = Object.entries(this.mainObj.fileObj).filter(([k, v]) => {
451 | return k.includes(temp);
452 | });
453 | comments = [];
454 | if (f.length > 0) {
455 | xmlObj = XmlService.parse(f[0][1].getDataAsString());
456 | root = xmlObj.getRootElement();
457 | commentList = root.getChild("commentList", root.getNamespace()).getChildren();
458 | comments = commentList.reduce((ar, e) => {
459 | var cObj, commentObj, ref, tempComment, text, tmp;
460 | temp = {};
461 | ref = e.getAttribute("ref");
462 | if (ref) {
463 | tmp = ref.getValue();
464 | cObj = a1NotationToRowCol.call(this, tmp);
465 | temp.range = {};
466 | temp.range.col = cObj.col;
467 | temp.range.row = cObj.row;
468 | temp.range.a1Notation = tmp;
469 | text = e.getChild("text", e.getNamespace());
470 | t = text.getChild("t", text.getNamespace());
471 | if (t) {
472 | tempComment = t.getValue();
473 | comments = tempComment.split(/\t\-\w.+/);
474 | commentObj = [...tempComment.matchAll(/\t\-\w.+/g)].map(([h]) => {
475 | return h.replace(/\t-/, "");
476 | }).map((h, l) => {
477 | return {
478 | user: h,
479 | comment: comments[l]
480 | };
481 | });
482 | temp.comment = commentObj;
483 | }
484 | ar.push(temp);
485 | }
486 | return ar;
487 | }, []);
488 | }
489 | return comments;
490 | };
491 |
492 | getValuesFromObj = function(v_) {
493 | var maxColumnLength, obj, values;
494 | obj = getValuesAsObject.call(this);
495 | maxColumnLength = obj.reduce((c, e) => {
496 | if (c < e.length) {
497 | return e.length;
498 | } else {
499 | return c;
500 | }
501 | }, 0);
502 | values = obj.reduce((ar, e) => {
503 | var temp;
504 | temp = new Array(maxColumnLength).fill("");
505 | e.forEach(({value, range}) => {
506 | return temp[range.col - 1] = value[v_] === null ? "" : value[v_];
507 | });
508 | ar.push(temp);
509 | return ar;
510 | }, []);
511 | return values;
512 | };
513 |
514 | getXmlObj = function(k_) {
515 | return XmlService.parse(this.mainObj.fileObj[k_].getDataAsString());
516 | };
517 |
518 | putError = function(m) {
519 | throw new Error(`${m}`);
520 | };
521 |
522 | putInternalError = function(m) {
523 | throw new Error(`Internal error: ${m}`);
524 | };
525 |
526 | a1NotationToRowCol = function(a1Notation_) {
527 | var num, str;
528 | str = a1Notation_.match(/[a-zA-Z]+/)[0];
529 | num = Number(a1Notation_.match(/\d+/)[0]);
530 | return {
531 | row: num,
532 | col: letterToColumn.call(this, str)
533 | };
534 | };
535 |
536 | columnToLetter = function(column) {
537 | var letter, temp;
538 | temp = 0;
539 | letter = "";
540 | while (column > 0) {
541 | temp = (column - 1) % 26;
542 | letter = String.fromCharCode(temp + 65) + letter;
543 | column = (column - temp - 1) / 26;
544 | }
545 | return letter;
546 | };
547 |
548 | letterToColumn = function(letter) {
549 | var column, i, length, p, ref1;
550 | column = 0;
551 | length = letter.length;
552 | for (i = p = 0, ref1 = length; (0 <= ref1 ? p < ref1 : p > ref1); i = 0 <= ref1 ? ++p : --p) {
553 | column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);
554 | }
555 | return column;
556 | };
557 |
558 | return ExcelApp;
559 |
560 | }).call(this);
561 | return r.ExcelApp = ExcelApp;
562 | })(this);
563 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2020 Kanshi TANAIKE
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DocsServiceApp
2 |
3 |
4 |
5 | [](LICENCE)
6 |
7 |
8 |
9 | # Overview
10 |
11 | **This is a Google Apps Script library for supporting Document service, Docs API, Spreadsheet service, Sheets API, Slides service and Slides API.** The aim of this library is to compensate the processes that they services cannot achieve.
12 |
13 | 
14 |
15 |
16 |
17 | # Description
18 |
19 | The Google services, which are Document service, Docs API, Spreadsheet service, Sheets API, Slides service and Slides API, are growing now. But, unfortunately, there are still the processes that they cannot done. I created this GAS library for supporting the Google services.
20 |
21 | The basic method of DocsServiceApp is to directly create and edit the data of Microsoft Docs (Word, Excel and Powerpoint). The created data of Microsoft Docs can be reflected to Google Docs (Document, Spreadsheet and Slides) by converting and copying the values. By this, the processes which cannot be achieved by Google services are achieved. So it can be considered that this DocsServiceApp is used as the wrapper for supporting Google service. I believe that this method will be able to be also applied for various scenes as the methodology. So I would like to grow this library.
22 |
23 | # Feature
24 |
25 | ## For Google Docs
26 |
27 | ### [Google Document](#googledocument)
28 |
29 | - Retrieve table width and column width from the table. The tables inserted with the default width are included.
30 |
31 | ### [Google Spreadsheet](#googlespreadsheet)
32 |
33 | - Retrieve all images in Google Spreadsheet as an object including the cell range and image blob.
34 | - Retrieve all comments in Google Spreadsheet as an object including the cell range and comments.
35 | - Insert images in cells of Google Spreadsheet using the image blob.
36 | - Create new Google Spreadsheet by setting the custom header and footer.
37 | - Retrieve cell coordinates of cells with the quote prefix.
38 | - Retrieve named functions.
39 |
40 | ### [Google Slides](#googleslides)
41 |
42 | - Create new Google Slides by setting the page size.
43 |
44 | ## For Microsoft Docs
45 |
46 | In the current stage, there are not methods for directly parsing Microsoft Docs files. This library can achieve this.
47 |
48 | ### [Microsoft Word](#microsoftword)
49 |
50 | - Retrieve table width and column width.
51 |
52 | ### [Microsoft Excel](#microsoftexcel)
53 |
54 | - Retrieve all values and formulas of the cells.
55 | - Retrieve all sheet names.
56 | - Retrieve all images as an object including the cell range and image blob.
57 | - Retrieve all comments as an object including the cell range and comments.
58 |
59 | ### [Microsoft Powerpoint](#microsoftpowerpoint)
60 |
61 | There are no methods yet.
62 |
63 | # Library's project key
64 |
65 | ```
66 | 108j6x_ZX544wEhGkgddFYM6Ie09edDqXaFwnW3RVFQCLHw_mEueqUHTW
67 | ```
68 |
69 | # How to install
70 |
71 | ## Install this library
72 |
73 | - Open Script Editor. Click as follows:
74 | - -> Resource
75 | - -> Library
76 | - -> Input the Script ID in the text box. The Script ID is **`108j6x_ZX544wEhGkgddFYM6Ie09edDqXaFwnW3RVFQCLHw_mEueqUHTW`**.
77 | - -> Add library
78 | - -> Please select the latest version
79 | - -> Developer mode ON (Or select others if you don't want to use the latest version)
80 | - -> The identifier is "**`DocsServiceApp`**". This is set under the default.
81 |
82 | [You can read more about libraries in Apps Script here](https://developers.google.com/apps-script/guide_libraries).
83 |
84 | Please use this library with enabling V8 runtime.
85 |
86 | ## About Google APIs
87 |
88 | This library uses the following Google APIs. So when you want to use the library, please enable the following APIs at Advanced Google services. [Ref](https://developers.google.com/apps-script/guides/services/advanced#enabling_advanced_services)
89 |
90 | - Drive API: This is used for all methods.
91 | - Sheets API: This is used for Google Spreadsheet.
92 |
93 | ## About scopes
94 |
95 | This library uses the following scope. This is installed in the library, and nothing further is required from the user. But if you want to manually control the scopes, please set the required scopes to the manifest file (`appsscript.json`) in your client Google Apps Script project.
96 |
97 | - `https://www.googleapis.com/auth/drive`
98 | - This is used for all methods.
99 | - `https://www.googleapis.com/auth/script.external_request`
100 | - This is used for all methods.
101 | - `https://www.googleapis.com/auth/documents`
102 | - This is used for Google Document.
103 | - `https://www.googleapis.com/auth/spreadsheets`
104 | - This is used for Google Spreadsheet.
105 | - `https://www.googleapis.com/auth/presentations`
106 | - This is used for Google Slides.
107 |
108 | ## About including GAS libraries
109 |
110 | This library uses the following Google Apps Script library.
111 |
112 | - [ImgApp](https://github.com/tanaikech/ImgApp)
113 |
114 |
115 |
116 | # Methods
117 |
118 | In the current stage, there are the following methods in this library.
119 |
120 |
121 |
122 | ## For Google Document
123 |
124 | ### 1. `getTableColumnWidth()`
125 |
126 | Retrieve the column width of the table in the Google Document. For example, when a new table, which has 1 row and 2 columns, is manually inserted to the Document body as the default format, the table width and column width retrieved by `getColumnWidth()` return `null`. By this, in the current stage, the table width and column width cannot be retrieved. This method achieves this.
127 |
128 | #### Sample script
129 |
130 | ```javascript
131 | const documentId = "###"; // Google Document ID
132 | const res = DocsServiceApp.openByDocumentId(documentId).getTableColumnWidth();
133 | console.log(res);
134 | ```
135 |
136 | #### Result
137 |
138 | ```json
139 | [
140 | {
141 | "tableIndex": 0, // 0 means the 1st table in Google Document.
142 | "unit": "pt",
143 | "tableWidth": 451.3, // Table width
144 | "tebleColumnWidth": [225.65, 225.65] // Column width of each column. Array index is the column index.
145 | },
146 | ,
147 | ,
148 | ,
149 | ]
150 | ```
151 |
152 | - For example, when the table which has the columns "A" and "B" of 100 pt and 200 pt are checked by above script, the same values of 100 and 200 for the columns "A" and "B" could be confirmed. So from this result, it is found that the column width of DOCX data and Google Document is the same.
153 |
154 |
155 |
156 | ## For Google Spreadsheet
157 |
158 | ### 1. `getImages()`
159 |
160 | Retrieve images in and over the cell from Google Spreadsheet as blob. In the current stage, there are no methods for retrieving the images over the cells and inner the cells in the existing Google Spreadsheet service and Sheets API. This method achieves this.
161 |
162 | #### Sample script
163 |
164 | ```javascript
165 | const spreadsheetId = "###"; // Google Spreadsheet ID
166 | const res = DocsServiceApp.openBySpreadsheetId(spreadsheetId)
167 | .getSheetByName("Sheet1")
168 | .getImages();
169 | console.log(res);
170 | ```
171 |
172 | In this script, the images are retrieved from "Sheet1" of `spreadsheetId`.
173 |
174 | And
175 |
176 | ```javascript
177 | const spreadsheetId = "###"; // Google Spreadsheet ID
178 | const res = DocsServiceApp.openBySpreadsheetId(spreadsheetId).getImages();
179 | console.log(res);
180 | ```
181 |
182 | In this script, the images are retrieved from all sheets of `spreadsheetId`.
183 |
184 | When you want to save all images in the Spreadsheet as the files, you can use the following script.
185 |
186 | ```javascript
187 | const spreadsheetId = "###"; // Google Spreadsheet ID
188 | const res = DocsServiceApp.openBySpreadsheetId(spreadsheetId).getImages();
189 | const folder = DriveApp.getFolderById("### folderId ###");
190 | res.forEach(({ images }) =>
191 | images.forEach((e) => {
192 | if (e.image) folder.createFile(e.image.blob);
193 | })
194 | );
195 | ```
196 |
197 | #### Result
198 |
199 | ```json
200 | [
201 | {
202 | "range": { "col": 3, "row": 8, "a1Notation": "C8" },
203 | "image": {
204 | "description": "sample description",
205 | "title": "sample title",
206 | "blob": BLOB,
207 | "innerCell": false // "false" means that the image is over a cell.
208 | }
209 | },
210 | {
211 | "range": { "col": 2, "row": 2, "a1Notation": "B2" },
212 | "image": {
213 | "description": "sample description",
214 | "title": "sample title",
215 | "blob": BLOB,
216 | "innerCell": true // "true" means that the image is in a cell.
217 | }
218 | },
219 | ,
220 | ,
221 | ,
222 | ]
223 | ```
224 |
225 | - You can create the image file from `BLOB`.
226 |
227 | - When `getSheetByName()` is not used, above array is put in each sheet as follows.
228 |
229 | ```json
230 | [
231 | { "sheetName": "Sheet1", "images": [[Object], [Object], [Object]] },
232 | { "sheetName": "Sheet2", "images": [] },
233 | { "sheetName": "Sheet3", "images": [[Object], [Object]] }
234 | ]
235 | ```
236 |
237 | #### Limitation
238 |
239 | - When the images are retrieved from XLSX data, it seems that the image is a bit different from the original one. The image format is the same. But the data size is smaller than that of the original. When the image size is more than 2048 pixels and 72 dpi, the image is modified to 2048 pixels and 72 dpi. Even when the image size is less than 2048 pixels and 72 dpi, the file size becomes smaller than that of original one. So I think that the image might be compressed. Please be careful this.
240 | - In the current stage, the drawings cannot be retrieved yet. I apologize for this.
241 |
242 | ### 2. `getComments()`
243 |
244 | Retrieve comments in Google Spreadsheet. In the current stage, there are no methods for retrieving the comments with the cell coordinate in the existing Google Spreadsheet service and Sheets API. This method achieves this.
245 |
246 | #### Sample script
247 |
248 | ```javascript
249 | const spreadsheetId = "###"; // Google Spreadsheet ID
250 | const res = DocsServiceApp.openBySpreadsheetId(spreadsheetId)
251 | .getSheetByName("Sheet1")
252 | .getComments();
253 | console.log(res);
254 | ```
255 |
256 | In this script, the images are retrieved from "Sheet1" of `spreadsheetId`.
257 |
258 | And
259 |
260 | ```javascript
261 | const spreadsheetId = "###"; // Google Spreadsheet ID
262 | const res = DocsServiceApp.openBySpreadsheetId(spreadsheetId).getComments();
263 | console.log(res);
264 | ```
265 |
266 | In this script, the images are retrieved from all sheets of `spreadsheetId`.
267 |
268 | #### Result
269 |
270 | ```json
271 | [
272 | {
273 | "range": {
274 | "col": 2,
275 | "row": 11,
276 | "a1Notation": "B11"
277 | },
278 | "comment": [
279 | {
280 | "user": "user name",
281 | "comment": "comment"
282 | },
283 | ,
284 | ,
285 | ,
286 | ]
287 | },
288 | ,
289 | ,
290 | ,
291 | ]
292 | ```
293 |
294 | - When `getSheetByName()` is not used, above array is put in each sheet as follows.
295 |
296 | ```json
297 | [
298 | { "sheetName": "Sheet1", "images": [[Object], [Object], [Object]] },
299 | { "sheetName": "Sheet2", "images": [] },
300 | { "sheetName": "Sheet3", "images": [[Object], [Object]] }
301 | ]
302 | ```
303 |
304 | ### 3. `insertImage()`
305 |
306 | Insert images in and over the cell from Google Spreadsheet from the image blob. In the current stage, there are no methods for directly inserting an image in a cell in the existing Google Spreadsheet service and Sheets API. For example, when the user wants to insert an image on own Google Drive in a cell, the image is required to be publicly shared for using `=IMAGE(URL)`. In this method, the image can be put without publicly sharing the image and using `=IMAGE(URL)`.
307 |
308 | #### Sample script
309 |
310 | ```javascript
311 | const spreadsheetId = "###"; // Google Spreadsheet ID
312 | const blob1 = DriveApp.getFileById("###fileId###").getBlob();
313 | const blob2 = UrlFetchApp.fetch("###URL###").getBlob();
314 | const object = [
315 | { blob: blob1, range: { row: 1, column: 1 } }, // Image is inserted in a cell "A1".
316 | { blob: blob2, range: { row: 5, column: 2 } }, // Image is inserted in a cell "B5".
317 | ];
318 | DocsServiceApp.openBySpreadsheetId(spreadsheetId)
319 | .getSheetByName("Sheet1")
320 | .insertImage(object);
321 | ```
322 |
323 | - **In this method, no values are returned.**
324 | - In above sample script, 2 images are inserted into the cells "A1" and "B5" in "Sheet1", respectively.
325 |
326 | #### Result
327 |
328 | 
329 |
330 | - The sample image of cell "A1" is from [https://www.deviantart.com/k3-studio/art/Rainbow-painting-281090729](https://www.deviantart.com/k3-studio/art/Rainbow-painting-281090729)
331 | - The sample image of cell "B5" is from [https://www.deviantart.com/k3-studio/art/Chromatic-lituus-415318548](https://www.deviantart.com/k3-studio/art/Chromatic-lituus-415318548)
332 |
333 | #### Limitation
334 |
335 | - When the images are retrieved from XLSX data, it seems that the image is a bit different from the original one. The image format is the same. But the data size is smaller than that of the original. When the image size is more than 2048 pixels and 72 dpi, the image is modified to 2048 pixels and 72 dpi. Even when the image size is less than 2048 pixels and 72 dpi, the file size becomes smaller than that of original one. So I think that the image might be compressed. Please be careful this.
336 | - In the current stage, the drawings cannot be retrieved yet. I apologize for this.
337 |
338 | ### 4. `createNewSpreadsheetWithCustomHeaderFooter()`
339 |
340 | Create new Google Spreadsheet by setting the header and footer. In the current stage, there are no methods for setting the header and footer for Google Spreadsheet in the existing Google Spreadsheet service and Sheets API. This method achieves this.
341 |
342 | #### Sample script
343 |
344 | ```javascript
345 | const object = {
346 | title: "sample title", // Title of created Spreadsheet.
347 | parent: "###", // folder ID
348 | header: { l: "left header", c: "center header", r: "right header" },
349 | footer: { l: "left footer", c: "center footer", r: "right footer" },
350 | };
351 | const res = DocsServiceApp.createNewSpreadsheetWithCustomHeaderFooter(object);
352 | console.log(res);
353 | ```
354 |
355 | - In this method, the spreadsheet ID of created Spreadsheet is returned.
356 |
357 | #### Result
358 |
359 | 
360 |
361 |
362 |
363 | ### 5. `getQuotePrefixCells()`
364 |
365 | 
366 |
367 | Retrieve cell coordinates of cells with the quote prefix. In Google Spreadsheet, when a single quote is add to the top letter of the cell value, the cell is used as the text value. When we want to search the cells with the quote prefix in Spreadsheet, unfortunately, in the current stage, this cannot be achieved using Spreadsheet service (SpreadsheetApp) and Sheets API. In this method, such cells can be retrieved. The output values are the cell coordinates of the cells with the quote prefix.
368 |
369 | #### Sample script
370 |
371 | ```javascript
372 | const spreadsheetId = "###"; // Google Spreadsheet ID
373 | const res = DocsServiceApp.openBySpreadsheetId(spreadsheetId)
374 | .getSheetByName("Sheet1") // Please set sheet name.
375 | .getQuotePrefixCells();
376 | console.log(res);
377 | ```
378 |
379 | #### Result
380 |
381 | ```json
382 | ["A1", "C3", "E1", , ,]
383 | ```
384 |
385 | - I answered this method to [this thread at Stackoverflow](https://stackoverflow.com/a/73616511).
386 |
387 |
388 |
389 | ### 6. `getNamedFunctions()`
390 |
391 | 
392 |
393 | This method is for retrieving the named functions from Google Spreadsheet using Google Apps Script.
394 |
395 | Recently, the named functions got to be able to be used in Google Spreadsheet. [Ref](https://workspaceupdates.googleblog.com/2022/08/named-functions-google-sheets.html) When several named functions are added, I thought that I wanted to retrieve these functions using a script. But, unfortunately, in the current stage, it seems that there are no built-in methods (SpreadsheetApp and Sheets API) for directly retrieving the named functions. So, I created this method.
396 |
397 | #### Sample script
398 |
399 | ```javascript
400 | const spreadsheetId = "###"; // Google Spreadsheet ID
401 | const res =
402 | DocsServiceApp.openBySpreadsheetId(spreadsheetId).getNamedFunctions();
403 | console.log(res);
404 | ```
405 |
406 | #### Result
407 |
408 | When this script is run to the top sample situation in this section, the following result is obtained.
409 |
410 | ```json
411 | [
412 | {
413 | "definedName": "CONTAINS",
414 | "definedFunction": "LAMBDA(cell, range, NOT(ISERROR(MATCH(cell,range,0))))"
415 | },
416 | { "definedName": "SAMPLE1", "definedFunction": "LAMBDA(range, SUM(range))" }
417 | ]
418 | ```
419 |
420 | - Unfortunately, in the current stage, the description of the named function cannot be obtained.
421 |
422 | - At XLSX format, the named functions are used as LAMBDA function. If you want to directly use this LAMBDA function, for example, please put a function like =LAMBDA(range, SUM(range))(A1:A5) into a cell. By this, the LAMBDA function can be run. Of course, you can retrieve the function from this result and put it as the named function again.
423 |
424 | - I posted this method in my [blog](https://tanaikech.github.io/2022/09/28/retrieving-named-functions-from-google-spreadsheet-using-google-apps-script/).
425 |
426 |
427 |
428 | ## For Google Slides
429 |
430 | ### 1. `createNewSlidesWithPageSize()`
431 |
432 | Create new Google Slides by setting the page size. In the current stage, there are no methods for setting the page size for Google Slides in the existing Google Slides service and Slides API, although Slides API has the method of "presentations.create". This method achieves this.
433 |
434 | #### Sample script
435 |
436 | ```javascript
437 | const object = {
438 | title: "sample title", // Title of created Slides.
439 | parent: "###", // folder ID
440 | width: { unit: "pixel", size: 200 },
441 | height: { unit: "pixel", size: 300 },
442 | };
443 | const res = DocsServiceApp.createNewSlidesWithPageSize(object);
444 | console.log(res);
445 | ```
446 |
447 | - In this method, the presentation ID of created Slides is returned.
448 | - "pixel" and "point" can be used for `unit` in above object.
449 |
450 | #### Sample situations
451 |
452 | When this method is used, the following application can be created.
453 |
454 | 1. [Inserting Text on Image using Google Apps Script](https://gist.github.com/tanaikech/835642df109731a559e52d831bd3342d) : This is a sample script for inserting a text on an image using Google Apps Script.
455 |
456 |
457 |
458 | ## For Microsoft Word
459 |
460 | ### 1. `getTableColumnWidth()`
461 |
462 | Retrieve the column width of the table in the Microsoft Word. In this case, the column width of the table are directly retrieved from Microsoft Word.
463 |
464 | #### Sample script
465 |
466 | ```javascript
467 | const blob = "BLOB"; // Blob of Microsoft Word file.
468 | const res = DocsServiceApp.openByWordFileBlob(blob).getTableColumnWidth();
469 | console.log(res);
470 | ```
471 |
472 | #### Result
473 |
474 | ```json
475 | [
476 | {
477 | "tableIndex": 0, // 0 means the 1st table in Google Document.
478 | "unit": "pt",
479 | "tableWidth": 451.3, // Table width
480 | "tebleColumnWidth": [225.65, 225.65] // Column width of each column. Array index is the column index.
481 | },
482 | ,
483 | ,
484 | ,
485 | ]
486 | ```
487 |
488 |
489 |
490 | ## For Microsoft Excel
491 |
492 | 
493 |
494 | > IMPORTANT: About `getValues()` and `getFormulas()` methods, in the current stage, the process costs of them is much higher than those of Google Spreadsheet service. So when you want to retrieve the values and formulas from XLSX data, I would like to recommend to use Google Spreadsheet service by converting XSLX data to Google Spreadsheet.
495 |
496 | ### 1. `getImages()`
497 |
498 | Retrieve images in and over the cell from Microsoft Excel as blob. In this case, the images are directly retrieved from Microsoft Excel.
499 |
500 | #### Sample script
501 |
502 | ```javascript
503 | const blob = "BLOB"; // Blob of Microsoft Excel file.
504 | const res = DocsServiceApp.openByExcelFileBlob(blob)
505 | .getSheetByName("Sheet1")
506 | .getImages();
507 | console.log(res);
508 | ```
509 |
510 | In this script, the images are retrieved from "Sheet1" of `spreadsheetId`.
511 |
512 | And
513 |
514 | ```javascript
515 | const blob = "BLOB"; // Blob of Microsoft Excel file.
516 | const res = DocsServiceApp.openByExcelFileBlob(blob).getImages();
517 | console.log(res);
518 | ```
519 |
520 | In this script, the images are retrieved from all sheets of `spreadsheetId`.
521 |
522 | - **`blob`** : Blob of XLSX file.
523 | - **`sheetName`** : Sheet name in XLSX file. The formulas are retrieved from the sheet.
524 |
525 | #### Result
526 |
527 | ```json
528 | [
529 | {
530 | "range": { "col": 3, "row": 8, "a1Notation": "C8" },
531 | "image": {
532 | "description": "sample description",
533 | "title": "sample title",
534 | "blob": BLOB,
535 | "innerCell": false // "false" means that the image is over a cell.
536 | }
537 | },
538 | {
539 | "range": { "col": 2, "row": 2, "a1Notation": "B2" },
540 | "image": {
541 | "description": "sample description",
542 | "title": "sample title",
543 | "blob": BLOB,
544 | "innerCell": true // "true" means that the image is in a cell.
545 | }
546 | },
547 | ,
548 | ,
549 | ,
550 | ]
551 | ```
552 |
553 | - When `getSheetByName()` is not used, above array is put in each sheet as follows.
554 |
555 | ```json
556 | [
557 | { "sheetName": "Sheet1", "images": [[Object], [Object], [Object]] },
558 | { "sheetName": "Sheet2", "images": [] },
559 | { "sheetName": "Sheet3", "images": [[Object], [Object]] }
560 | ]
561 | ```
562 |
563 | #### Limitation
564 |
565 | - When the images are retrieved from XLSX data, it seems that the image is a bit different from the original one. The image format is the same. But the data size is smaller than that of the original. When the image size is more than 2048 pixels and 72 dpi, the image is modified to 2048 pixels and 72 dpi. Even when the image size is less than 2048 pixels and 72 dpi, the file size becomes smaller than that of original one. So I think that the image might be compressed. Please be careful this.
566 | - In the current stage, the drawings cannot be retrieved yet. I apologize for this.
567 |
568 | ### 2. `getComments()`
569 |
570 | Retrieve comments in Microsoft Excel. In this case, the comments are directly retrieved from Microsoft Excel.
571 |
572 | #### Sample script
573 |
574 | ```javascript
575 | const blob = "BLOB"; // Blob of Microsoft Excel file.
576 | const res = DocsServiceApp.openByExcelFileBlob(blob)
577 | .getSheetByName("Sheet1")
578 | .getComments();
579 | console.log(res);
580 | ```
581 |
582 | In this script, the comments are retrieved from "Sheet1" of Blob of Microsoft Excel file.
583 |
584 | - **`blob`** : Blob of XLSX file.
585 | - **`sheetName`** : Sheet name in XLSX file. The formulas are retrieved from the sheet.
586 |
587 | #### Result
588 |
589 | ```json
590 | [
591 | {
592 | "range": {
593 | "col": 2,
594 | "row": 11,
595 | "a1Notation": "B11"
596 | },
597 | "comment": [
598 | {
599 | "user": "user name",
600 | "comment": "comment"
601 | },
602 | ,
603 | ,
604 | ,
605 | ]
606 | },
607 | ,
608 | ,
609 | ,
610 | ]
611 | ```
612 |
613 | ### 3. `getAll()`
614 |
615 | This method is used for retrieving all values (in the current stage, those are values, formulas, images and comments.) from all sheets of XLSX data. The returned value is JSON object.
616 |
617 | #### Sample script
618 |
619 | ```javascript
620 | function myFunction() {
621 | const fileId = "###"; // Please set the file ID of XLSX file.
622 | const blob = DriveApp.getFileById(fileId).getBlob();
623 |
624 | const res = DocsServiceApp.openByExcelFileBlob(blob).getAll();
625 | console.log(res);
626 | }
627 | ```
628 |
629 | - **`blob`** : Blob of XLSX file.
630 | - The values are returned as JSON object. The returned values include the values, formulas, images and comments of all sheets in the XLSX data.
631 |
632 | ### 4. `getSheets()`
633 |
634 | This method is used for retrieving the sheet list from XLSX data.
635 |
636 | #### Sample script
637 |
638 | ```javascript
639 | function myFunction() {
640 | const fileId = "###"; // Please set the file ID of XLSX file.
641 | const blob = DriveApp.getFileById(fileId).getBlob();
642 |
643 | const res = DocsServiceApp.openByExcelFileBlob(blob).getSheets();
644 | console.log(res);
645 | }
646 | ```
647 |
648 | - **`blob`** : Blob of XLSX file.
649 |
650 | ### 5. `getValues()`
651 |
652 | This method is used for updating the values from a sheet of XLSX data.
653 |
654 | #### Sample script
655 |
656 | ```javascript
657 | function myFunction() {
658 | const fileId = "###"; // Please set the file ID of XLSX file.
659 | const sheetName = "###"; // Please set the sheet name.
660 | const blob = DriveApp.getFileById(fileId).getBlob();
661 |
662 | const res = DocsServiceApp.openByExcelFileBlob(blob)
663 | .getSheetByName(sheetName)
664 | .getValues();
665 | console.log(res);
666 | }
667 | ```
668 |
669 | - **`blob`** : Blob of XLSX file.
670 | - **`sheetName`** : Sheet name in XLSX file. The values are retrieved from the sheet.
671 |
672 | Sample result value is as follows. The values are returned as 2 dimensional array.
673 |
674 | ```json
675 | [
676 | ["a1", "b1", "c1"],
677 | ["", "b2", "c2"],
678 | ["a3", "b3", "c3"],
679 | ["a4", "b4", "c4"],
680 | ["a5", "b5", "c5"]
681 | ]
682 | ```
683 |
684 |
685 |
686 | ### 6. `getFormulas()`
687 |
688 | This method is used for updating the formulas from a sheet of XLSX data.
689 |
690 | ### Sample script
691 |
692 | ```javascript
693 | function myFunction() {
694 | const fileId = "###"; // Please set the file ID of XLSX file.
695 | const sheetName = "###"; // Please set the sheet name.
696 | const blob = DriveApp.getFileById(fileId).getBlob();
697 |
698 | const res = DocsServiceApp.openByExcelFileBlob(blob)
699 | .getSheetByName(sheetName)
700 | .getFormulas();
701 | console.log(res);
702 | }
703 | ```
704 |
705 | - **`blob`** : Blob of XLSX file.
706 | - **`sheetName`** : Sheet name in XLSX file. The formulas are retrieved from the sheet.
707 | - The values are returned as 2 dimensional array.
708 |
709 |
710 |
711 | ## For Microsoft Powerpoint
712 |
713 | There are no methods yet.
714 |
715 | ---
716 |
717 |
718 |
719 | # Licence
720 |
721 | [MIT](LICENCE)
722 |
723 |
724 |
725 | # Author
726 |
727 | [Tanaike](https://tanaikech.github.io/about/)
728 |
729 |
730 |
731 | # Update History
732 |
733 | - v1.0.0 (September 24, 2020)
734 |
735 | 1. Initial release.
736 |
737 | - v1.1.0 (September 28, 2022)
738 |
739 | 1. Added a new method of [`getQuotePrefixCells()`](#getQuotePrefixCells). This method can detect the cells with the quote prefix cells.
740 |
741 | - v1.2.0 (September 29, 2022)
742 |
743 | 1. Added a new method of [`getNamedFunctions()`](#getnamedfunctions). This method can retrieve the named functions from Google Spreadsheet.
744 |
745 | - v1.2.1 (December 28, 2022)
746 |
747 | 1. Remove a bug in `ExcelApp`.
748 |
749 | - v1.2.2 (January 30, 2024)
750 |
751 | 1. Remove a bug in `ExcelApp`. When the inserted image had no data, an error occurred. This issue was removed.
752 |
753 | [TOP](#top)
754 |
--------------------------------------------------------------------------------
/SlidesAppp.js:
--------------------------------------------------------------------------------
1 | // --- SlidesAppp (SlidesApp plus) ---
2 | (function(r) {
3 | var SlidesAppp;
4 | SlidesAppp = (function() {
5 | var newPPTXdata, pptxObjToBlob, putError, putInternalError, setPageSize;
6 |
7 | class SlidesAppp {
8 | constructor(id_) {
9 | this.name = "SlidesAppp";
10 | if (id_ !== "create") {
11 | if (id_ === "" || DriveApp.getFileById(id_).getMimeType() !== MimeType.GOOGLE_SLIDES) {
12 | putError.call(this, "This file ID is not the file ID of Google Slides.");
13 | }
14 | this.obj = {
15 | presentationId: id_
16 | };
17 | }
18 | this.headers = {
19 | Authorization: `Bearer ${ScriptApp.getOAuthToken()}`
20 | };
21 | this.mainObj = {};
22 | }
23 |
24 | // --- begin methods
25 | createNewSlidesWithPageSize(obj_) {
26 | var blob, createObj, e, pptxObj, tmpId;
27 | if (!obj_ || Object.keys(obj_).length === 0) {
28 | putError.call(this, "Object was not found. Please confirm it again.");
29 | }
30 | pptxObj = newPPTXdata.call(this);
31 | setPageSize.call(this, obj_, pptxObj);
32 | blob = pptxObjToBlob.call(this, pptxObj);
33 | createObj = {
34 | title: "SlidesSample",
35 | mimeType: MimeType.GOOGLE_SLIDES
36 | };
37 | if (obj_.hasOwnProperty("title")) {
38 | createObj.title = obj_.title;
39 | }
40 | if (obj_.hasOwnProperty("parent")) {
41 | createObj.parents = [
42 | {
43 | id: obj_.parent
44 | }
45 | ];
46 | }
47 | try {
48 | tmpId = Drive.Files.insert(createObj, blob).id;
49 | } catch (error) {
50 | e = error;
51 | if (e.message === "Drive is not defined") {
52 | putError.call(this, "Please enable Drive API at Advanced Google services, and try again.");
53 | } else {
54 | putError.call(this, e.message);
55 | }
56 | }
57 | return tmpId;
58 | }
59 |
60 | };
61 |
62 | SlidesAppp.name = "SlidesAppp";
63 |
64 | // --- end methods
65 | newPPTXdata = function() {
66 | var data;
67 | data = "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";
68 | return JSON.parse(Utilities.unzip(Utilities.newBlob(Utilities.base64Decode(data), MimeType.ZIP))[0].getDataAsString());
69 | };
70 |
71 | setPageSize = function(obj_, obj) {
72 | var filename, h, root, unitX, unitY, w, xmlObj;
73 | if (obj_.hasOwnProperty("width") || obj_.hasOwnProperty("height")) {
74 | unitX = "pixel";
75 | unitY = "pixel";
76 | if (obj_.width.hasOwnProperty("unit")) {
77 | unitX = obj_.width.unit;
78 | }
79 | if (obj_.height.hasOwnProperty("unit")) {
80 | unitY = obj_.height.unit;
81 | }
82 | if ((unitX !== "pixel" && unitX !== "point") || (unitY !== "pixel" && unitY !== "point")) {
83 | putError.call(this, "Unit is wrong.");
84 | }
85 | if (!obj_.width.hasOwnProperty("size") || !obj_.height.hasOwnProperty("size")) {
86 | putError.call(this, "Size was not found.");
87 | }
88 | w = (unitX === "pixel" ? obj_.width.size * 0.75 : obj_.width.size) * 12700;
89 | h = (unitX === "pixel" ? obj_.height.size * 0.75 : obj_.height.size) * 12700;
90 | filename = "ppt/presentation.xml";
91 | xmlObj = XmlService.parse(obj[filename]);
92 | root = xmlObj.getRootElement();
93 | root.getChild("sldSz", root.getNamespace("p")).setAttribute("cx", w).setAttribute("cy", h);
94 | obj[filename] = XmlService.getRawFormat().format(root);
95 | }
96 | };
97 |
98 | pptxObjToBlob = function(pptxObj) {
99 | var blobs;
100 | blobs = Object.entries(pptxObj).reduce((ar, [k, v]) => {
101 | ar.push(v.toString() === "Blob" ? v : Utilities.newBlob(v, MimeType.PLAIN_TEXT, k));
102 | return ar;
103 | }, []);
104 | return Utilities.zip(blobs, "temp.pptx").setContentType(MimeType.MICROSOFT_POWERPOINT);
105 | };
106 |
107 | putError = function(m) {
108 | throw new Error(`${m}`);
109 | };
110 |
111 | putInternalError = function(m) {
112 | throw new Error(`Internal error: ${m}`);
113 | };
114 |
115 | return SlidesAppp;
116 |
117 | }).call(this);
118 | return r.SlidesAppp = SlidesAppp;
119 | })(this);
120 |
--------------------------------------------------------------------------------
/SpreadsheetAppp.js:
--------------------------------------------------------------------------------
1 | // --- SpreadsheetAppp (SpreadsheetApp plus) ---
2 | (function (r) {
3 | var SpreadsheetAppp;
4 | SpreadsheetAppp = function () {
5 | var ContentTypesXml_,
6 | createDrawing1Xml_,
7 | createSheet1Xml_,
8 | drawing1XmlRels_,
9 | gToM,
10 | imagesToObj,
11 | newXLSXdata,
12 | putError,
13 | putInternalError,
14 | setheaderFooter,
15 | xlsxObjToBlob;
16 |
17 | class SpreadsheetAppp {
18 | constructor(id_) {
19 | this.name = "SpreadsheetAppp";
20 | if (id_ !== "create") {
21 | if (
22 | id_ === "" ||
23 | DriveApp.getFileById(id_).getMimeType() !== MimeType.GOOGLE_SHEETS
24 | ) {
25 | putError.call(
26 | this,
27 | "This file ID is not the file ID of Spreadsheet."
28 | );
29 | }
30 | this.obj = {
31 | spreadsheetId: id_,
32 | };
33 | }
34 | this.headers = {
35 | Authorization: `Bearer ${ScriptApp.getOAuthToken()}`,
36 | };
37 | this.mainObj = {};
38 | }
39 |
40 | // --- begin methods
41 | getSheetByName(sheetName_) {
42 | if (!sheetName_ || sheetName_.toString() === "") {
43 | putError.call(this, "No sheet name.");
44 | }
45 | this.obj.sheetName = sheetName_;
46 | return this;
47 | }
48 |
49 | getImages() {
50 | gToM.call(this);
51 | if (this.obj.hasOwnProperty("sheetName")) {
52 | return new ExcelApp(this.mainObj.blob)
53 | .getSheetByName(this.obj.sheetName)
54 | .getImages();
55 | } else {
56 | return new ExcelApp(this.mainObj.blob)
57 | .getAll()
58 | .map(({ sheetName, images }) => {
59 | return { sheetName, images };
60 | });
61 | }
62 | }
63 |
64 | getComments() {
65 | gToM.call(this);
66 | if (this.obj.hasOwnProperty("sheetName")) {
67 | return new ExcelApp(this.mainObj.blob)
68 | .getSheetByName(this.obj.sheetName)
69 | .getComments();
70 | } else {
71 | return new ExcelApp(this.mainObj.blob)
72 | .getAll()
73 | .map(({ sheetName, comments }) => {
74 | return { sheetName, comments };
75 | });
76 | }
77 | }
78 |
79 | insertImage(objAr_) {
80 | var ar,
81 | blob,
82 | dstSS,
83 | dstSheet,
84 | dstSheetId,
85 | e,
86 | requests,
87 | tmpId,
88 | tmpSheet,
89 | tmpSheetId,
90 | xlsxObj;
91 | if (
92 | !Array.isArray(objAr_) ||
93 | objAr_.some(({ blob, range }) => {
94 | var height, identification, width;
95 | if (
96 | blob.toString() !== "Blob" ||
97 | !range.row ||
98 | !range.column ||
99 | isNaN(range.row) ||
100 | isNaN(range.column)
101 | ) {
102 | return true;
103 | }
104 | ({ width, height, identification } = ImgApp.getSize(blob));
105 | if (width * height > 1048576) {
106 | return true;
107 | }
108 | if (
109 | !["GIF", "PNG", "JPG"].some((e) => {
110 | return e === identification;
111 | })
112 | ) {
113 | return true;
114 | }
115 | return false;
116 | })
117 | ) {
118 | putError.call(
119 | this,
120 | "Wrong object. Please confirm it again. By the way, the maximum image size is 'width x height < 1048576'. And the mimeTypes are PNG, JPG and GIF."
121 | );
122 | }
123 | xlsxObj = newXLSXdata.call(this);
124 | ar = imagesToObj.call(this, xlsxObj, objAr_);
125 | ContentTypesXml_.call(this, xlsxObj, ar);
126 | createSheet1Xml_.call(this, xlsxObj, ar);
127 | createDrawing1Xml_.call(this, xlsxObj, ar);
128 | drawing1XmlRels_.call(this, xlsxObj, ar);
129 | blob = xlsxObjToBlob.call(this, xlsxObj);
130 | try {
131 | tmpId = Drive.Files.insert(
132 | {
133 | title: "SpreadsheetAppp_temp",
134 | mimeType: MimeType.GOOGLE_SHEETS,
135 | },
136 | blob
137 | ).id;
138 | } catch (error) {
139 | e = error;
140 | if (e.message === "Drive is not defined") {
141 | putError.call(
142 | this,
143 | "Please enable Drive API at Advanced Google services, and try again."
144 | );
145 | } else {
146 | putError.call(this, e.message);
147 | }
148 | }
149 | dstSS = SpreadsheetApp.openById(this.obj.spreadsheetId);
150 | dstSheet = dstSS.getSheetByName(this.obj.sheetName);
151 | dstSheetId = dstSheet.getSheetId();
152 | tmpSheet = SpreadsheetApp.openById(tmpId)
153 | .getSheets()[0]
154 | .setName(`SpreadsheetAppp_${Utilities.getUuid()}`)
155 | .copyTo(dstSS);
156 | DriveApp.getFileById(tmpId).setTrashed(true);
157 | tmpSheetId = tmpSheet.getSheetId();
158 | requests = ar.map((e) => {
159 | e.from.sheetId = tmpSheetId;
160 | e.to.sheetId = dstSheetId;
161 | return {
162 | copyPaste: {
163 | source: e.from,
164 | destination: e.to,
165 | pasteType: "PASTE_VALUES",
166 | },
167 | };
168 | });
169 | try {
170 | Sheets.Spreadsheets.batchUpdate(
171 | {
172 | requests: requests,
173 | },
174 | this.obj.spreadsheetId
175 | );
176 | } catch (error) {
177 | e = error;
178 | if (e.message === "Sheets is not defined") {
179 | putError.call(
180 | this,
181 | "Please enable Sheets API at Advanced Google services, and try again."
182 | );
183 | } else {
184 | putError.call(this, e.message);
185 | }
186 | }
187 | dstSS.deleteSheet(tmpSheet);
188 | return null;
189 | }
190 |
191 | createNewSpreadsheetWithCustomHeaderFooter(obj_) {
192 | var blob, createObj, e, tmpId, xlsxObj;
193 | if (!obj_ || Object.keys(obj_).length === 0) {
194 | putError.call(this, "Object was not found. Please confirm it again.");
195 | }
196 | xlsxObj = newXLSXdata.call(this);
197 | setheaderFooter.call(this, obj_, xlsxObj);
198 | blob = xlsxObjToBlob.call(this, xlsxObj);
199 | createObj = {
200 | title: "SpreadsheetSample",
201 | mimeType: MimeType.GOOGLE_SHEETS,
202 | };
203 | if (obj_.hasOwnProperty("title")) {
204 | createObj.title = obj_.title;
205 | }
206 | if (obj_.hasOwnProperty("parent")) {
207 | createObj.parents = [
208 | {
209 | id: obj_.parent,
210 | },
211 | ];
212 | }
213 | try {
214 | tmpId = Drive.Files.insert(createObj, blob).id;
215 | } catch (error) {
216 | e = error;
217 | if (e.message === "Drive is not defined") {
218 | putError.call(
219 | this,
220 | "Please enable Drive API at Advanced Google services, and try again."
221 | );
222 | } else {
223 | putError.call(this, e.message);
224 | }
225 | }
226 | return tmpId;
227 | }
228 |
229 | getQuotePrefixCells() {
230 | gToM.call(this);
231 | if (this.obj.hasOwnProperty("sheetName")) {
232 | return new ExcelApp(this.mainObj.blob)
233 | .getSheetByName(this.obj.sheetName)
234 | .getQuotePrefixCells();
235 | }
236 | return "Please set sheet name.";
237 | }
238 |
239 | getNamedFunctions() {
240 | gToM.call(this);
241 | return new ExcelApp(this.mainObj.blob).getNamedFunctions();
242 | }
243 | }
244 |
245 | SpreadsheetAppp.name = "SpreadsheetAppp";
246 |
247 | // --- end methods
248 | gToM = function () {
249 | var obj, url;
250 | url = `https://www.googleapis.com/drive/v3/files/${this.obj.spreadsheetId}/export?mimeType=${MimeType.MICROSOFT_EXCEL}`;
251 | obj = UrlFetchApp.fetch(url, {
252 | headers: this.headers,
253 | });
254 | if (obj.getResponseCode() !== 200) {
255 | putError.call(
256 | this,
257 | "Spreadsheet ID might be not correct. Please check it again."
258 | );
259 | }
260 | this.mainObj.blob = obj.getBlob();
261 | };
262 |
263 | newXLSXdata = function () {
264 | var data;
265 | data =
266 | "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";
267 | return JSON.parse(
268 | Utilities.unzip(
269 | Utilities.newBlob(Utilities.base64Decode(data), MimeType.ZIP)
270 | )[0].getDataAsString()
271 | );
272 | };
273 |
274 | imagesToObj = function (obj_, ar_) {
275 | var dupCheckAr;
276 | dupCheckAr = [];
277 | return ar_.reduce((ar, e, i) => {
278 | var dupObj,
279 | ext,
280 | fileSize,
281 | filename,
282 | imgFilename,
283 | mimeType,
284 | orgFilename,
285 | tempObj;
286 | orgFilename = e.blob.getName();
287 | fileSize = e.blob.getBytes().length;
288 | mimeType = e.blob.getContentType();
289 | ext = "";
290 | switch (mimeType) {
291 | case MimeType.PNG:
292 | ext = "png";
293 | break;
294 | case MimeType.JPEG:
295 | ext = "jpg";
296 | break;
297 | case MimeType.GIF:
298 | ext = "gif";
299 | break;
300 | case MimeType.BMP:
301 | e.blob = e.blob.getAs(MimeType.PNG);
302 | ext = "png";
303 | break;
304 | default:
305 | putError.call(
306 | this,
307 | "In the current stage, this file type cannot be used."
308 | );
309 | }
310 | filename = `xl/media/image${i + 1}.${ext}`;
311 | dupObj = dupCheckAr.filter((e) => {
312 | return (
313 | e.orgFilename === orgFilename &&
314 | e.fileSize === fileSize &&
315 | e.mimeType === mimeType
316 | );
317 | });
318 | if (dupObj.length === 0) {
319 | imgFilename = `image${i + 1}.${ext}`;
320 | dupCheckAr.push({
321 | filename: imgFilename,
322 | orgFilename: orgFilename,
323 | fileSize: fileSize,
324 | mimeType: mimeType,
325 | });
326 | tempObj = {
327 | range: `A${i + 1}`,
328 | filename: imgFilename,
329 | rowIndex: i,
330 | mimeType: mimeType,
331 | from: {
332 | startRowIndex: i,
333 | endRowIndex: i + 1,
334 | startColumnIndex: 0,
335 | endColumnIndex: 1,
336 | },
337 | to: {
338 | startRowIndex: e.range.row - 1,
339 | endRowIndex: e.range.row,
340 | startColumnIndex: e.range.column - 1,
341 | endColumnIndex: e.range.column,
342 | },
343 | };
344 | ar.push(tempObj);
345 | obj_[filename] = e.blob.copyBlob().setName(filename);
346 | } else {
347 | tempObj = {
348 | range: `A${i + 1}`,
349 | filename: dupObj[0].filename,
350 | rowIndex: i,
351 | mimeType: mimeType,
352 | from: {
353 | startRowIndex: i,
354 | endRowIndex: i + 1,
355 | startColumnIndex: 0,
356 | endColumnIndex: 1,
357 | },
358 | to: {
359 | startRowIndex: e.range.row - 1,
360 | endRowIndex: e.range.row,
361 | startColumnIndex: e.range.column - 1,
362 | endColumnIndex: e.range.column,
363 | },
364 | };
365 | ar.push(tempObj);
366 | }
367 | return ar;
368 | }, []);
369 | };
370 |
371 | ContentTypesXml_ = function (obj, ar) {
372 | var filename, mimeTypeToExtension, mimeTypes, n, root, xmlObj;
373 | mimeTypeToExtension = {
374 | [MimeType.PNG]: "png",
375 | [MimeType.JPEG]: "jpg",
376 | [MimeType.GIF]: "gif",
377 | };
378 | mimeTypes = [
379 | ...new Set(
380 | ar.map(({ mimeType }) => {
381 | return mimeType;
382 | })
383 | ),
384 | ];
385 | filename = "[Content_Types].xml";
386 | xmlObj = XmlService.parse(obj[filename]);
387 | root = xmlObj.getRootElement();
388 | n = root.getNamespace();
389 | mimeTypes.forEach((e) => {
390 | var Default;
391 | Default = XmlService.createElement("Default", n)
392 | .setAttribute("ContentType", e)
393 | .setAttribute("Extension", mimeTypeToExtension[e]);
394 | return root.addContent(Default);
395 | });
396 | obj[filename] = XmlService.getRawFormat().format(root);
397 | };
398 |
399 | createSheet1Xml_ = function (obj, ar) {
400 | var filename, n, root, xmlObj;
401 | filename = "xl/worksheets/sheet1.xml";
402 | xmlObj = XmlService.parse(obj[filename]);
403 | root = xmlObj.getRootElement();
404 | n = root.getNamespace();
405 | ar.forEach((e) => {
406 | var c, row;
407 | c = XmlService.createElement("c", n)
408 | .setAttribute("r", e.range)
409 | .setAttribute("s", "1");
410 | row = XmlService.createElement("row", n)
411 | .setAttribute("r", e.rowIndex + 1)
412 | .addContent(c);
413 | return root.getChild("sheetData", n).addContent(row);
414 | });
415 | obj[filename] = XmlService.getRawFormat().format(root);
416 | };
417 |
418 | createDrawing1Xml_ = function (obj, ar) {
419 | var filename, n, n2, n3, root, xmlObj;
420 | filename = "xl/drawings/drawing1.xml";
421 | xmlObj = XmlService.parse(obj[filename]);
422 | root = xmlObj.getRootElement();
423 | n = root.getNamespace("xdr");
424 | n2 = root.getNamespace("r");
425 | n3 = root.getNamespace("a");
426 | ar.forEach((e, i) => {
427 | var avLst,
428 | blip,
429 | blipFill,
430 | cNvPicPr,
431 | cNvPr,
432 | clientData,
433 | col,
434 | colOff,
435 | ext,
436 | fillRect,
437 | form,
438 | nvPicPr,
439 | oneCellAnchor,
440 | pic,
441 | prstGeom,
442 | row,
443 | rowOff,
444 | spPr,
445 | stretch;
446 | col = XmlService.createElement("col", n).setText(0);
447 | colOff = XmlService.createElement("colOff", n).setText(0);
448 | row = XmlService.createElement("row", n).setText(e.rowIndex);
449 | rowOff = XmlService.createElement("rowOff", n).setText(0);
450 | form = XmlService.createElement("from", n)
451 | .addContent(col)
452 | .addContent(colOff)
453 | .addContent(row)
454 | .addContent(rowOff);
455 | ext = XmlService.createElement("ext", n)
456 | .setAttribute("cx", "314325")
457 | .setAttribute("cy", "200025");
458 | cNvPr = XmlService.createElement("cNvPr", n)
459 | .setAttribute("id", "0")
460 | .setAttribute("name", e.filename);
461 | cNvPicPr = XmlService.createElement("cNvPicPr", n).setAttribute(
462 | "preferRelativeResize",
463 | "0"
464 | );
465 | nvPicPr = XmlService.createElement("nvPicPr", n)
466 | .addContent(cNvPr)
467 | .addContent(cNvPicPr);
468 | blip = XmlService.createElement("blip", n3)
469 | .setAttribute("cstate", "print")
470 | .setAttribute("embed", `rId${i + 1}`, n2);
471 | fillRect = XmlService.createElement("fillRect", n3);
472 | stretch = XmlService.createElement("stretch", n3).addContent(fillRect);
473 | blipFill = XmlService.createElement("blipFill", n)
474 | .addContent(blip)
475 | .addContent(stretch);
476 | avLst = XmlService.createElement("avLst", n3);
477 | prstGeom = XmlService.createElement("prstGeom", n3)
478 | .setAttribute("prst", "rect")
479 | .addContent(avLst);
480 | spPr = XmlService.createElement("spPr", n).addContent(prstGeom);
481 | pic = XmlService.createElement("pic", n)
482 | .addContent(nvPicPr)
483 | .addContent(blipFill)
484 | .addContent(spPr);
485 | clientData = XmlService.createElement("clientData", n).setAttribute(
486 | "fLocksWithSheet",
487 | "0"
488 | );
489 | oneCellAnchor = XmlService.createElement("oneCellAnchor", n)
490 | .addContent(form)
491 | .addContent(ext)
492 | .addContent(pic)
493 | .addContent(clientData);
494 | return root.addContent(oneCellAnchor);
495 | });
496 | obj[filename] = XmlService.getRawFormat().format(root);
497 | };
498 |
499 | drawing1XmlRels_ = function (obj, ar) {
500 | var Relationships, filename, n, root;
501 | filename = "xl/drawings/_rels/drawing1.xml.rels";
502 | root = XmlService.createDocument();
503 | n = XmlService.getNamespace(
504 | "http://schemas.openxmlformats.org/package/2006/relationships"
505 | );
506 | Relationships = XmlService.createElement("Relationships").setNamespace(n);
507 | ar.forEach(({ rowIndex, filename }) => {
508 | var Relationship;
509 | Relationship = XmlService.createElement("Relationship", n)
510 | .setAttribute("Id", `rId${rowIndex + 1}`)
511 | .setAttribute(
512 | "Type",
513 | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
514 | )
515 | .setAttribute("Target", `../media/${filename}`);
516 | Relationships.addContent(Relationship);
517 | });
518 | root.addContent(Relationships);
519 | obj[filename] = XmlService.getRawFormat()
520 | .format(root)
521 | .replace(
522 | /<\?xml version="1.0" encoding="UTF-8"\?>/,
523 | ``
524 | );
525 | };
526 |
527 | setheaderFooter = function (obj_, obj) {
528 | var f,
529 | filename,
530 | h,
531 | headerFooter,
532 | n,
533 | oddFooter,
534 | oddHeader,
535 | root,
536 | unitX,
537 | unitY,
538 | xmlObj;
539 | if (obj_.hasOwnProperty("header") || obj_.hasOwnProperty("footer")) {
540 | unitX = "pixel";
541 | unitY = "pixel";
542 | if (
543 | !obj_.header.hasOwnProperty("l") &&
544 | !obj_.header.hasOwnProperty("r") &&
545 | !obj_.header.hasOwnProperty("c") &&
546 | !obj_.footer.hasOwnProperty("l") &&
547 | !obj_.footer.hasOwnProperty("r") &&
548 | !obj_.footer.hasOwnProperty("c")
549 | ) {
550 | putError.call(this, "Please set header and/or footer.");
551 | }
552 | filename = "xl/worksheets/sheet1.xml";
553 | xmlObj = XmlService.parse(obj[filename]);
554 | root = xmlObj.getRootElement();
555 | n = root.getNamespace();
556 | h = `&L${obj_.header.hasOwnProperty("l") ? obj_.header.l : ""}&C${
557 | obj_.header.hasOwnProperty("c") ? obj_.header.c : ""
558 | }&R${obj_.header.hasOwnProperty("r") ? obj_.header.r : ""}`;
559 | f = `&L${obj_.footer.hasOwnProperty("l") ? obj_.footer.l : ""}&C${
560 | obj_.footer.hasOwnProperty("c") ? obj_.footer.c : ""
561 | }&R${obj_.footer.hasOwnProperty("r") ? obj_.footer.r : ""}`;
562 | oddHeader = XmlService.createElement("oddHeader", n).setText(h);
563 | oddFooter = XmlService.createElement("oddFooter", n).setText(f);
564 | headerFooter = XmlService.createElement("headerFooter", n)
565 | .addContent(oddHeader)
566 | .addContent(oddFooter);
567 | root.addContent(headerFooter);
568 | obj[filename] = XmlService.getRawFormat().format(root);
569 | }
570 | };
571 |
572 | xlsxObjToBlob = function (xlsxObj) {
573 | var blobs;
574 | blobs = Object.entries(xlsxObj).reduce((ar, [k, v]) => {
575 | ar.push(
576 | v.toString() === "Blob"
577 | ? v
578 | : Utilities.newBlob(v, MimeType.PLAIN_TEXT, k)
579 | );
580 | return ar;
581 | }, []);
582 | return Utilities.zip(blobs, "temp.xlsx").setContentType(
583 | MimeType.MICROSOFT_EXCEL
584 | );
585 | };
586 |
587 | putError = function (m) {
588 | throw new Error(`${m}`);
589 | };
590 |
591 | putInternalError = function (m) {
592 | throw new Error(`Internal error: ${m}`);
593 | };
594 |
595 | return SpreadsheetAppp;
596 | }.call(this);
597 | return (r.SpreadsheetAppp = SpreadsheetAppp);
598 | })(this);
599 |
--------------------------------------------------------------------------------
/WordApp.js:
--------------------------------------------------------------------------------
1 | // --- WordApp ---
2 | (function(r) {
3 | var WordApp;
4 | WordApp = (function() {
5 | var disassembleWord, getXmlObj, parsDOCX, putError, putInternalError;
6 |
7 | class WordApp {
8 | constructor(blob_) {
9 | this.name = "WordApp";
10 | if (!blob_ || blob_.getContentType() !== MimeType.MICROSOFT_WORD) {
11 | throw new Error("Please set the blob of data of DOCX format.");
12 | }
13 | this.obj = {
14 | excel: blob_
15 | };
16 | this.contentTypes = "[Content_Types].xml";
17 | this.document = "word/document.xml";
18 | this.mainObj = {};
19 | parsDOCX.call(this);
20 | }
21 |
22 | // --- begin methods
23 | getTableColumnWidth() {
24 | var body, n1, obj, root, xmlObj;
25 | if (this.mainObj.fileObj.hasOwnProperty(this.document)) {
26 | xmlObj = getXmlObj.call(this, this.document);
27 | root = xmlObj.getRootElement();
28 | n1 = root.getNamespace("w");
29 | body = root.getChild("body", n1).getChildren("tbl", n1);
30 | obj = body.map((e, i) => {
31 | var tblGrid, tblPr, tblW, temp, w;
32 | temp = {
33 | tableIndex: i,
34 | unit: "pt"
35 | };
36 | tblPr = e.getChild("tblPr", n1);
37 | if (tblPr) {
38 | tblW = tblPr.getChild("tblW", n1);
39 | if (tblW) {
40 | w = tblW.getAttribute("w", n1);
41 | if (w) {
42 | temp.tableWidth = Number(w.getValue()) / 20;
43 | }
44 | }
45 | }
46 | tblGrid = e.getChild("tblGrid", n1);
47 | if (tblGrid) {
48 | temp.tebleColumnWidth = tblGrid.getChildren("gridCol", n1).map((f) => {
49 | return Number(f.getAttribute("w", n1).getValue()) / 20;
50 | });
51 | }
52 | return temp;
53 | });
54 | return obj;
55 | }
56 | }
57 |
58 | };
59 |
60 | WordApp.name = "WordApp";
61 |
62 | // --- end methods
63 | parsDOCX = function() {
64 | disassembleWord.call(this);
65 | };
66 |
67 | disassembleWord = function() {
68 | var blobs;
69 | blobs = Utilities.unzip(this.obj.excel.setContentType(MimeType.ZIP));
70 | this.mainObj.fileObj = blobs.reduce((o, b) => {
71 | return Object.assign(o, {
72 | [b.getName()]: b
73 | });
74 | }, {});
75 | };
76 |
77 | getXmlObj = function(k_) {
78 | return XmlService.parse(this.mainObj.fileObj[k_].getDataAsString());
79 | };
80 |
81 | putError = function(m) {
82 | throw new Error(`${m}`);
83 | };
84 |
85 | putInternalError = function(m) {
86 | throw new Error(`Internal error: ${m}`);
87 | };
88 |
89 | return WordApp;
90 |
91 | }).call(this);
92 | return r.WordApp = WordApp;
93 | })(this);
94 |
--------------------------------------------------------------------------------
/appsscript.json:
--------------------------------------------------------------------------------
1 | {
2 | "timeZone": "Asia/Tokyo",
3 | "dependencies": {
4 | "enabledAdvancedServices": [{
5 | "userSymbol": "Docs",
6 | "serviceId": "docs",
7 | "version": "v1"
8 | }, {
9 | "userSymbol": "Drive",
10 | "serviceId": "drive",
11 | "version": "v2"
12 | }, {
13 | "userSymbol": "Slides",
14 | "serviceId": "slides",
15 | "version": "v1"
16 | }, {
17 | "userSymbol": "Sheets",
18 | "serviceId": "sheets",
19 | "version": "v4"
20 | }],
21 | "libraries": [{
22 | "userSymbol": "ImgApp",
23 | "libraryId": "1T03nYHRho6XMWYcaumClcWr6ble65mAT8OLJqRFJ5lukPVogAN2NDl-y",
24 | "version": "8",
25 | "developmentMode": true
26 | }]
27 | },
28 | "exceptionLogging": "STACKDRIVER",
29 | "runtimeVersion": "V8"
30 | }
31 |
--------------------------------------------------------------------------------
/images/demo1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanaikech/DocsServiceApp/2b3d7171c6093630ddcb3f207a3c048157f9ac36/images/demo1.png
--------------------------------------------------------------------------------
/images/fig1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanaikech/DocsServiceApp/2b3d7171c6093630ddcb3f207a3c048157f9ac36/images/fig1.png
--------------------------------------------------------------------------------
/images/fig2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanaikech/DocsServiceApp/2b3d7171c6093630ddcb3f207a3c048157f9ac36/images/fig2.png
--------------------------------------------------------------------------------
/images/fig3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanaikech/DocsServiceApp/2b3d7171c6093630ddcb3f207a3c048157f9ac36/images/fig3.png
--------------------------------------------------------------------------------
/images/fig4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanaikech/DocsServiceApp/2b3d7171c6093630ddcb3f207a3c048157f9ac36/images/fig4.png
--------------------------------------------------------------------------------
/images/fig5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanaikech/DocsServiceApp/2b3d7171c6093630ddcb3f207a3c048157f9ac36/images/fig5.png
--------------------------------------------------------------------------------
/mainMethods.js:
--------------------------------------------------------------------------------
1 | /**
2 | * GitHub https://github.com/tanaikech/DocsServiceApp
3 | * Library name
4 | * @type {string}
5 | * @const {string}
6 | * @readonly
7 | */
8 | const appName = "DocsServiceApp";
9 |
10 | /**
11 | * @param {String} id Spreasheet ID.
12 | * @return {DocsServiceApp}
13 | */
14 | function openBySpreadsheetId(id) {
15 | return new SpreadsheetAppp(id);
16 | }
17 |
18 | /**
19 | * @param {Object} blob Blob of Excel file (XLSX file).
20 | * @return {DocsServiceApp}
21 | */
22 | function openByExcelFileBlob(blob) {
23 | return new ExcelApp(blob);
24 | }
25 |
26 | /**
27 | * @param {String} id Document ID.
28 | * @return {DocsServiceApp}
29 | */
30 | function openByDocumentId(id) {
31 | return new DocumentAppp(id);
32 | }
33 |
34 | /**
35 | * @param {Object} blob Blob of Word file (DOCX file).
36 | * @return {DocsServiceApp}
37 | */
38 | function openByWordFileBlob(blob) {
39 | return new WordApp(blob);
40 | }
41 |
42 | /**
43 | * @param {object} object Object including parameter for createing new Google Spreadsheet.
44 | * @return {string} Presentation ID of cerated Google Slides.
45 | */
46 | function createNewSpreadsheetWithCustomHeaderFooter(object) {
47 | return new SpreadsheetAppp("create").createNewSpreadsheetWithCustomHeaderFooter(object);
48 | }
49 |
50 | /**
51 | * @param {object} object Object including parameter for createing new Google Slides.
52 | * @return {string} Presentation ID of cerated Google Slides.
53 | */
54 | function createNewSlidesWithPageSize(object) {
55 | return new SlidesAppp("create").createNewSlidesWithPageSize(object);
56 | }
57 |
58 | // DriveApp.createFile() // This is used for automatically detected the scope of "https://www.googleapis.com/auth/drive"
59 | // SpreadsheetApp.create() // This is used for automatically detected the scope of "https://www.googleapis.com/auth/spreadsheets"
60 | // SlidesApp.create(name) // This is used for automatically detected the scope of "https://www.googleapis.com/auth/presentations"
61 | ;
62 |
63 |
--------------------------------------------------------------------------------