Skip to content

Instantly share code, notes, and snippets.

@richie5um
Created September 2, 2022 06:41
Show Gist options
  • Save richie5um/483c1696038bc3c0376190da0a0e63db to your computer and use it in GitHub Desktop.
Save richie5um/483c1696038bc3c0376190da0a0e63db to your computer and use it in GitHub Desktop.
name: Smz-CustomXml-v4
description: ''
host: WORD
api_set: {}
script:
content: |
OfficeExtension.config.extendedErrorLogging = true;
$("#get-xml").click(() =>
tryCatch(() => {
getCustomJson();
})
);
$("#get-contentcontrols").click(() =>
tryCatch(() => {
getContentControls();
})
);
$("#delete-contentcontrol").click(() =>
tryCatch(() => {
deleteContentControl();
})
);
$("#insert-contentcontrol").click(() =>
tryCatch(() => {
insertContentControl();
})
);
$("#get-bodyooxml").click(() =>
tryCatch(() => {
bodyOoxml();
})
);
$("#get-selectionooxml").click(() =>
tryCatch(() => {
selectionOoxml();
})
);
$("#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.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 bodyOoxml() {
if (typeof Word === "undefined") {
return Promise.reject();
}
return Word.run(async (ctx) => {
let selectionOoxml = ctx.document.body.getOoxml();
await ctx.sync();
console.table({ OOXML: selectionOoxml.value });
}).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 selectionOoxml() {
if (typeof Word === "undefined") {
return Promise.reject();
}
return Word.run(async (ctx) => {
let selection = ctx.document.getSelection();
var selectionOoxml = selection.getOoxml();
ctx.load(selection);
await ctx.sync();
console.table({ OOXML: selectionOoxml.value });
}).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 insertContentControl() {
if (typeof Word === "undefined") {
return Promise.reject();
}
return Word.run(async (ctx) => {
let selection = ctx.document.getSelection();
ctx.load(selection);
await ctx.sync();
const contentControl = selection.insertContentControl();
contentControl.appearance = "Tags";
contentControl.title = "TestContentControl";
contentControl.tag = "tag";
contentControl.color = "#DAD4F3";
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} (${item.id})</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=\"get-bodyooxml\" class=\"ms-Button\">Get Body Ooxml</button>\n\t<button id=\"get-selectionooxml\" class=\"ms-Button\">Get Selection Ooxml</button>\n\t<button id=\"insert-contentcontrol\" class=\"ms-Button\">Insert ContentControl</button>\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
[email protected]/dist/css/fabric.min.css
[email protected]/dist/css/fabric.components.min.css
[email protected]/client/core.min.js
@types/core-js
[email protected]
@types/[email protected]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment