Skip to content

Instantly share code, notes, and snippets.

@richie5um
Last active August 22, 2022 09:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save richie5um/8ce69e7827c17a9c581d6a1dcd30cc9b to your computer and use it in GitHub Desktop.
Save richie5um/8ce69e7827c17a9c581d6a1dcd30cc9b to your computer and use it in GitHub Desktop.
name: Smz-CustomXml-v3
description: ''
host: WORD
api_set: {}
script:
content: |
$("#get-xml").click(() =>
tryCatch(() => {
getCustomJson();
})
);
$("#get-contentcontrols").click(() =>
tryCatch(() => {
getContentControls();
})
);
$("#delete-contentcontrol").click(() =>
tryCatch(() => {
deleteContentControl();
})
);
$("#list-xml").on("click", ".delete", function() {
const id = $(this).attr("id");
console.log(id);
removeCustomJsonById(id);
$(this)
.parent()
.remove();
});
$("#list-contentcontrols").on("click", ".view", async function() {
let id = $(this).attr("id");
console.log(id);
id = id.substr(1);
var index = parseInt(id, 10);
let item = _contentControls[index];
await Word.run(async (ctx) => {
item.select();
item.context.sync();
console.log(id + " selected");
});
});
$("#list-contentcontrols").on("click", ".show", async function() {
let id = $(this).attr("id");
console.log(id);
id = id.substr(1);
var index = parseInt(id, 10);
let item = _contentControls[index];
await Word.run(async (ctx) => {
console.log(item.title);
console.log(item.tag);
console.log(item.appearance);
item.appearance = "BoundingBox";
item.context.sync();
// await ctx.sync();
});
});
$("#list-contentcontrols").on("click", ".show-tags", async function() {
let id = $(this).attr("id");
console.log(id);
id = id.substr(1);
var index = parseInt(id, 10);
let item = _contentControls[index];
await Word.run(async (ctx) => {
console.log(item.title);
console.log(item.tag);
console.log(item.appearance);
item.appearance = "Tags";
item.context.sync();
// await ctx.sync();
});
});
$("#list-contentcontrols").on("click", ".hide", async function() {
let id = $(this).attr("id");
console.log(id);
id = id.substr(1);
var index = parseInt(id, 10);
let item = _contentControls[index];
await Word.run(async (ctx) => {
console.log(item.title);
console.log(item.tag);
console.log(item.appearance);
item.appearance = "Hidden";
// item.appearance = "BoundingBox";
// item.color = '#DAD4F3';
item.context.sync();
});
});
let _contentControls = [];
// $("#list-contentcontrols").on("click", ".delete", function () {
// const id = $(this).attr("id");
// console.log(id);
// removeCustomJsonById(id);
// $(this)
// .parent()
// .remove();
// });
async function getCustomJson() {
await Word.run(async (ctx) => {
const promise = new Promise((resolve, reject) => {
const smzNamespace = "https://schemas.summize.com/token/1.0";
Office.context.document.customXmlParts.getByNamespaceAsync(smzNamespace, async (result) => {
if (result.status !== "succeeded") {
return reject(result);
}
const xmlParts = result.value;
let customJsons = [];
for (let xmlPart of xmlParts) {
const id = xmlPart.id.replace("{", "").replace("}", "");
const customJson = await this.getCustomJsonById(id);
customJsons.push({ id, json: customJson });
}
customJsons = customJsons.filter((x) => x !== undefined);
return resolve(customJsons);
});
});
await promise.then((items) => {
$("#list-xml").empty();
for (let item of items) {
const json = JSON.stringify(item, null, 2);
$("#list-xml").append(
`<li><pre>${json}</pre><button id="${item.id}" class="delete" value="Delete">X</button></li>`
);
console.log(json);
}
});
});
}
async function getCustomJsonById(id) {
if (typeof Word === "undefined") {
return Promise.reject();
}
return Word.run(async (ctx) => {
id = `{${id}}`;
const promise = new Promise((resolve, reject) => {
Office.context.document.customXmlParts.getByIdAsync(id, async function(result) {
if (result.status !== "succeeded" || result.value === undefined) {
return reject(result);
}
const xmlPart = result.value;
xmlPart.getNodesAsync("*/*", async (result) => {
if (result.status !== "succeeded") {
return reject(result);
}
// This doesn't feel right, but I can't get the xpath working. So, hey ho.
const nodes = result.value.filter((x) => x.baseName === "json");
if (nodes.length === 0) {
return reject(result);
}
nodes[0].getTextAsync((result) => {
if (result.status !== "succeeded") {
return reject(result);
}
const json = JSON.parse(decodeForXml(result.value));
return resolve(json);
});
});
});
});
return promise;
}).catch((err) => {
console.log("OfficeService-Error: " + JSON.stringify(err));
if (err instanceof OfficeExtension.Error) {
console.log("OfficeService-Debug info: " + JSON.stringify(err.debugInfo));
}
});
}
async function removeCustomJsonById(id: string) {
if (typeof Word === "undefined") {
return Promise.reject();
}
return Word.run(async (ctx) => {
id = `{${id}}`;
const promise = new Promise((resolve, reject) => {
Office.context.document.customXmlParts.getByIdAsync(id, async (result) => {
if (result.status !== "succeeded" && result.value !== undefined) {
return reject(result);
}
const xmlPart = result.value;
xmlPart.deleteAsync((result) => {
if (result.status !== "succeeded") {
return reject(result);
}
console.log(`Deleted SmzToken => ${result.value.id}`);
return resolve(true);
});
});
});
return promise;
}).catch((err) => {
console.log("OfficeService-Error: " + JSON.stringify(err));
if (err instanceof OfficeExtension.Error) {
console.log("OfficeService-Debug info: " + JSON.stringify(err.debugInfo));
}
});
}
async function deleteContentControl() {
if (typeof Word === "undefined") {
return Promise.reject();
}
return Word.run(async (ctx) => {
let selection = ctx.document.getSelection();
ctx.load(selection);
await ctx.sync();
ctx.load(selection.paragraphs, "*");
await ctx.sync();
for (const paragraph of selection.paragraphs.items) {
ctx.load(paragraph.contentControls);
}
await ctx.sync();
for (const paragraph of selection.paragraphs.items) {
if (!paragraph.contentControls.isNull) {
for (let contentControl of paragraph.contentControls.items) {
console.log("Deleting Content Control");
contentControl.delete(true);
}
}
}
await ctx.sync();
}).catch((err) => {
console.log("OfficeService-Error: " + JSON.stringify(err));
if (err instanceof OfficeExtension.Error) {
console.log("OfficeService-Debug info: " + JSON.stringify(err.debugInfo));
}
});
}
async function getContentControls() {
if (typeof Word === "undefined") {
return Promise.reject();
}
return Word.run(async (ctx) => {
let contentControls = ctx.document.body.contentControls;
ctx.load(contentControls);
await ctx.sync();
$("#list-contentcontrols").empty();
for (let contentControl of _contentControls) {
contentControl.untrack();
}
await ctx.sync();
_contentControls = [];
if (!contentControls.isNull) {
for (let item of contentControls.items) {
item.track();
console.log(`${item.title}:${item.tag}`);
$("#list-contentcontrols").append(
`<li><div>${item.title}</div><pre>${item.tag}</pre><button id="V${_contentControls.length}" class="view" value="View">View</button><button id="S${_contentControls.length}" class="show" value="Show">Show</button><button id="T${_contentControls.length}" class="show-tags" value="ShowTags">Show (Tags)</button><button id="H${_contentControls.length}" class="hide" value="Hide">Hide</button></li>`
);
_contentControls.push(item);
}
await ctx.sync();
}
}).catch((err) => {
console.log("OfficeService-Error: " + JSON.stringify(err));
if (err instanceof OfficeExtension.Error) {
console.log("OfficeService-Debug info: " + JSON.stringify(err.debugInfo));
}
});
}
function encodeForXml(xml: string) {
return xml
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&apos;");
}
function decodeForXml(xml: string) {
return xml
.replace(/&apos;/g, "'")
.replace(/&quot;/g, '"')
.replace(/&gt;/g, ">")
.replace(/&lt;/g, "<")
.replace(/&amp;/g, "&");
}
/** Default helper for invoking an action and handling errors. */
async function tryCatch(callback) {
try {
await callback();
} catch (error) {
// Note: In a production add-in, you'd want to notify the user through your add-in's UI.
console.error(error);
}
}
language: typescript
template:
content: "<section class=\"samples ms-font-m\">\n\t<button id=\"delete-contentcontrol\" class=\"ms-Button\">Delete ContentControl</button>\n\t<button id=\"get-xml\" class=\"ms-Button\">Read CustomXml</button>\n\t<ul id=\"list-xml\">\n\t\t<li>Empty</li>\n\t</ul>\n\n\t<button id=\"get-contentcontrols\" class=\"ms-Button\">Read ContentControl</button>\n\t<ul id=\"list-contentcontrols\">\n\t\t<li>Empty</li>\n\t</ul>\n</section>"
language: html
style:
content: |-
section.samples {
margin-top: 20px;
}
section.samples .ms-Button, section.setup .ms-Button {
display: block;
margin-bottom: 5px;
margin-left: 20px;
min-width: 80px;
}
.delete {
background: red;
color: white;
}
language: css
libraries: |-
https://appsforoffice.microsoft.com/lib/1/hosted/office.js
@types/office-js
office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
core-js@2.4.1/client/core.min.js
@types/core-js
jquery@3.1.1
@types/jquery@3.3.1
name: Smz-UploadFile
description: ''
host: WORD
api_set: {}
script:
content: >
$("#get-docx").click(() =>
tryCatch(() => {
getDocumentAsCompressed();
})
);
// The following example gets the document in Office
// Open XML ("compressed") format in 65536 bytes (64 KB)
// slices. Note: The implementation of app.showNotification
// in this example is from the Visual Studio template for
// Office Add-ins.
function getDocumentAsCompressed() {
Office.context.document.getFileAsync(Office.FileType.Compressed, { sliceSize: 65536 /*64 KB*/ },
function (result) {
if (result.status == "succeeded") {
// If the getFileAsync call succeeded, then
// result.value will return a valid File Object.
const myFile = result.value;
const sliceCount = myFile.sliceCount;
const docdataSlices = [];
let slicesReceived = 0, gotAllSlices = true;
$("#result").text("File size:" + myFile.size + " #Slices: " + sliceCount);
// Get the file slices.
getSliceAsync(myFile, 0, sliceCount, gotAllSlices, docdataSlices, slicesReceived);
}
else {
$("#result").text("Error:", result.error.message);
}
});
}
function getSliceAsync(file, nextSlice, sliceCount, gotAllSlices,
docdataSlices, slicesReceived) {
file.getSliceAsync(nextSlice, function (sliceResult) {
if (sliceResult.status == "succeeded") {
if (!gotAllSlices) { // Failed to get all slices, no need to continue.
return;
}
// Got one slice, store it in a temporary array.
// (Or you can do something else, such as
// send it to a third-party server.)
docdataSlices[sliceResult.value.index] = sliceResult.value.data;
if (++slicesReceived == sliceCount) {
// All slices have been received.
file.closeAsync();
onGotAllSlices(docdataSlices);
}
else {
getSliceAsync(file, ++nextSlice, sliceCount, gotAllSlices, docdataSlices, slicesReceived);
}
}
else {
gotAllSlices = false;
file.closeAsync();
$("#result").text("getSliceAsync Error:", sliceResult.error.message);
}
});
}
function onGotAllSlices(docdataSlices) {
let docdata = [];
for (let i = 0; i < docdataSlices.length; i++) {
docdata = docdata.concat(docdataSlices[i]);
}
let fileContent = new String();
for (let j = 0; j < docdata.length; j++) {
fileContent += String.fromCharCode(docdata[j]);
}
$("#result").text(fileContent);
// Now all the file content is stored in 'fileContent' variable,
// you can do something with it, such as print, fax...
}
// var i = 0;
// var slices = 0;
// async function getDocx() {
// Office.context.document.getFileAsync("compressed", { sliceSize: 2097152
}, function(result) {
// if (result.status == "succeeded") {
// // If the getFileAsync call succeeded, then
// // result.value will return a valid File Object.
// var myFile = result.value;
// slices = myFile.sliceCount;
// $("#result").text("File size:" + myFile.size + " #Slices: " +
slices);
// // Iterate over the file slices.
// for (i = 0; i < slices; i++) {
// var slice = myFile.getSliceAsync(i, function(result) {
// if (result.status == "succeeded") {
// result.value.data;
// if (slices == i) {
// // Means it's done traversing...
// $("#result").text("complete"); //SendFileComplete();
// }
// } else $("#result").text(result.error.message);
// });
// }
// myFile.closeAsync();
// } else $("#result").text(result.error.message);
// });
// }
/** Default helper for invoking an action and handling errors. */
async function tryCatch(callback) {
try {
await callback();
} catch (error) {
// Note: In a production add-in, you'd want to notify the user through your add-in's UI.
console.error(error);
}
}
language: typescript
template:
content: "<script src=\"https://unpkg.com/axios/dist/axios.min.js\">const axios = require('axios').default;</script>\n\n<section class=\"samples ms-font-m\">\n\t<button id=\"get-docx\" class=\"ms-Button\">Read File</button>\n\t<div id=\"result\">\n\t</div>\n</section>"
language: html
style:
content: |-
section.samples {
margin-top: 20px;
}
section.samples .ms-Button, section.setup .ms-Button {
display: block;
margin-bottom: 5px;
margin-left: 20px;
min-width: 80px;
}
.delete {
background: red;
color: white;
}
language: css
libraries: |-
https://appsforoffice.microsoft.com/lib/1/hosted/office.js
@types/office-js
office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
core-js@2.4.1/client/core.min.js
@types/core-js
jquery@3.1.1
@types/jquery@3.3.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment