Using body.getOoxml() in an add-in for Word 2016 does not include the numbering package part. This leads to errors when executing insertooxml() since the API creates new numbering definitions which are wrong or default to the standard (as 1,2,3 etc.). Hence numberings that have other logic, like lower letters or roman letters, will be set back to the standard on executing insertooxml().
This applies to Word 2016 MSO which still uses IE 11 in add-ins. (nothing we can do about that).
In Word for M365 it works correctly.
The Word version in use is 16.0.5369.1000 MSO 16.0.5366.1000 32-Bit (Running on Windows 10)
We currently use Office-js version 1.1.82 (the newest 1.1.83-custom.0 has a bug that throws an exception on insertooxml in Word 2016)
We need this for our solution which removes sensitive data from word documents. Since Word Js Api 1.1 does not include hyperlinks, we need to operate on ooxml to fix hyperlinks as well.
Steps to recreate:
Create a new word document
Add one or two titles
Change title numbering to "a,b,c"
Execute the following code in an add-in:
var body = context.document.body;
var body_ooxml = body.getOoxml();
await context.sync();
var body_ooxml_value = body_ooxml.value;
body.insertOoxml(body_ooxml_value, Word.InsertLocation.replace);
await context.sync();
What I expected:
The content of the document should remain the same. Without any changes to the numbering
current findings
I made several tests and found out that in Word 2016 MSO, getOOXML does not return the numbering - even though the file numbering.xml exists and is correct. After executing insertOoxml it seems as if the api is trying to re-create the numbering from scratch which leads to an overwrite in numbering.xml that includes standard numbering (1,2,3).
I don't see a workaround (but would be happy for any advice).This seems to be a product bug and needs to fixed.
Just FYI, in case you didn't know: Microsoft no longer requires support for IE in add-ins that are distributed through AppSource. That said, it does seem to be a bug, so you could create a bug issue on the office-js repo. But I don't think a bug in an Office version that old will have a high priority.
Related
I'm developing a MS Word Add-In using the JS API. Currently, I need to find and edit or delete specific links inside the entire document. I know that this works using context.document.body.fields and then item.result.delete() and item.result.insertText('new text', 'Replace'). But context.document.body.fields is only available in the latest versions of Word (technically since requirement set 1.4).
I just want to know, are there alternative ways to do this in older Word versions before rs 1.4? And if so, what are those?
I think you can use document.body.search() method to find the hyperlink and this method will return a Range object, you can futher call something like InsertText() to replace it or call range.hyperlink = "" to remove the hyperlink.
Running into an issue when using EncodeForHTML for certain characters (Emojis in this case)
The text in this case is:
⌛️a😊b👍c😟 💥🍉🍔 💩 🤦🏼♀️🤦🏼♀️🤦🏼♀️ 😘
Now if I just a straight output
<cfoutput>#txt#</cfoutput>
It displays correctly, no issues, but if I use EncodeForHTML first
<cfoutput>#EncodeForHTML(txt)#</cfoutput>
I get this
⌛️a��b��c�� ������ �� ����♀️����♀️����♀️ ��
I tested it with EncodeForXML & esapiEncode as well to be sure; all are giving me the same result.
I've verified the encoding settings in Lucee are UTF-8, and the meta charset tag is also set to UTF-8. I can't find any documenation re: EncodeForHTML saying if it make any changes to the character encoding, if it requires the character encoding to be something specific, or if it has any known issues with emojis or certain code points.
I appreciate any help or clarification anyone can provide.
Edit: Thank you everyone. Wish I could accept multiple answers.
I was required to sanitize emojis in order ensure that third-party content was cross-compatible with external services. Some of the content contained emojis and was causing export/import problems. I wrote a ColdFusion wrapper for the emoji-java library to identify, sanitize and convert emojis.
https://github.com/JamoCA/cf-emoji-java
For example, the parseToAliases() function "replaces all the emoji's unicodes found in a string by their aliases".
emojijava = new emojijava();
emojijava.parseToAliases('I like 🍕'); // I like :pizza:
To "encode" you could use either the parseToHtmlDecimal() or parseToHtmlHexadecimal() functions prior to using EncodeForHTML().
emojijava = new emojijava();
test = emojijava.parseToHtmlDecimal('I like 🍕'); // I ❤️ 🍕
EncodeForHTML(test);
At the time of this writing, ColdFusion's latest version is 2018 update 9
In turn, it uses ESAPI 2.1.1
Recent release notes don't mention Emoji,
https://github.com/ESAPI/esapi-java-legacy/tree/develop/documentation
But they do mention in Pull request 413
"Fixing ESAPI's inability to handle non-BMP codepoints."
This dates from 2017
https://github.com/ESAPI/esapi-java-legacy/pull/413
So based on all this information, I would recommend doing both of the following
Try using ESAPI directly. This is how it was done before ESAPI was added to CF. This issue may or may not still exist in ESAPI
Put in a ticket with Adobe to update this library.
Yes, ESAPI 2.2.0.0 addressed the issue of not correctly encoding non-BMP characters (see https://github.com/ESAPI/esapi-java-legacy/issues/300) as part of PR #413 that James mentioned above.
But I just uploaded release ESAPI 2.2.1.0-RC1 (release candidate 1) to Maven Central early this morning and hope to have an official 2.2.1.0 release out by next weekend, so if you are going to put in a ticket with Adobe for fix this with an updated version of ESAPI, I'd wait another week and then tell them to update to 2.2.1.0.
I have one program which uses mailmerge in Word and it works perfectly in office 2007 and tested in 2010. But in office 2016 it throws an error
Code is below
ASSIGN lv_cDocument = fiFile. /* chosen from program select */
ASSIGN lv_cDataFile = "C:\a\data.dat".
ASSIGN lv_cMailMergeFile = "C:\a\dataOutput.doc".
MailMerge(lv_cDocument, /* Main Document */
lv_cDataFile, /* File that holds all the data */
lv_cMailMergeFile, /* File to hold new mail merge document */
NO).
DEFINE VARIABLE oWord AS COM-HANDLE NO-UNDO.
CREATE "Word.Application" oWord.
oWord:Documents:Open("C:\a\dataOutput.doc").
oWord:Visible = True.
RELEASE OBJECT oWord.
Any thoughts what is "new" in new office so i can modify my program that it works on all version of MS-Offices?
When doing COM, both applications (OrenEdge and Word) should be same "bitness". To be safe, both products should be 32 bit - I'm not 100% sure if 64 bit Word supports Automation interfaces.
The alternative on 11.6 might be the Interop API's (.NET): https://msdn.microsoft.com/de-de/library/microsoft.office.interop.word(v=office.11).aspx
The problem was in Word options.
Steps to resolve the auto launch errors:
Open MS Word.
Click on File > Options.
In the General section under Start up options, uncheck the "Open e-mail attachments and other uneditable files in reading view" box.
Close Word and try to export and auto launch your document again. It may take a couple of tried for Word to realize the setting has been changed.
Source
Problem for me was although it shows only ms office 2016 is installed and only one version of it. When I looked under start and went to outlook it showed the normal icon for outlook and the another one that said outlook 2016.
So I set up the user profile on the normal outlook, made sure that is open and not the outlook 2016 one and now the mail merge works for me.
Hope this helps someone out.
About one year ago I developed an app that, among other things, had to select parts of word documents and let them blink... just one line like this
Selection.Range.Font.Animation = MSWord.WdAnimation.wdAnimationBlinkingBackground;
The app worked pretty: if you open those docm documents (they have some macro inside) you can see some part blinking...
Now my customer tried it on a brand new laptop using Office 2013 and, surprise, when you open same word documents blinking effect is missing.
Is there a known reason for this?
Is there a way I can solve it?
According to MSDN, the WdAnimation enumeration has been deprecated:
This object, member, or enumeration is deprecated and is not intended
to be used in your code.
I can't find any other reference as to why it was dropped, or suggested replacement.
As a workaround, I just changed the background color. Non-blinking.
What is a good method to localize labels (column headings, field labels, headers/footers, etc) on Crystal Reports?
We are currently on XI R2 SP4 but are looking to migrate to 2008. It looks like 2008 offers better localization of the viewer UI. Does it have a content localization story?
Found a way to for localization of values such as DateTimes in Crystal Reports.
For instance if date is Aug-2009 and culture is French then would display as août-2009.
All this WITHOUT switching the current Thread culture to French.
Relevant Code snippet (example):
//Locale must be set BEFORE report is opened
if (this.IsEnglish)
{
ReportDoc.ReportClientDocument.PreferredViewingLocaleID =
CrystalDecisions.ReportAppServer.DataDefModel.CeLocale.ceLocaleEnglishCanada;
ReportDoc.ReportClientDocument.LocaleID =
CrystalDecisions.ReportAppServer.DataDefModel.CeLocale.ceLocaleEnglishCanada;
ReportDoc.ReportClientDocument.ProductLocaleID =
CrystalDecisions.ReportAppServer.DataDefModel.CeLocale.ceLocaleEnglishCanada;
}
else
{
ReportDoc.ReportClientDocument.PreferredViewingLocaleID =
CrystalDecisions.ReportAppServer.DataDefModel.CeLocale.ceLocaleFrenchCanada;
ReportDoc.ReportClientDocument.LocaleID =
CrystalDecisions.ReportAppServer.DataDefModel.CeLocale.ceLocaleFrenchCanada;
ReportDoc.ReportClientDocument.ProductLocaleID =
CrystalDecisions.ReportAppServer.DataDefModel.CeLocale.ceLocaleFrenchCanada;
}
//Load the report from file path
ReportDoc.Load(reportPath.ToString());
The two options that I can think of are: 1) Have a separate report for each localized version (this gets ugly quick and I don't recommend it very highly) or 2) Have the report generated from an application (say a c# windows/web app) and then you can localize using .net's localization standards and setting all of the localized text (read in from resource files) in the code.
I am not certain about 2008 but we are also on XI R2. We have localized reports for each language but only because we * know * that we will only need three different localized versions.
A client asked me to do develop a localization strategy for them. I've been meaning to write an article on it. Thanks to you, I've done just that. http://www.cogniza.com/blog/?p=55
Edit:
I was able to use an embedded subreport (in the report-header section) that referenced a database of localization values. I would have added that to my posting, but it was quite complex.
Another option is to create a user-function library (UFL) that handles this tasks. Store the data in a database or XML file. Most likely, however, you will lose the ContentLocale functionality.
We finally got around to implementing report localization. Loading of Crystal Reports is already the laggiest/worst-performing part of the user experience in our app, so we wanted to avoid any performance impact. The other idea that informed our decision was that the translations won't change within a shipped release.
We developed an application that uses the Crystal Reports API (2008 - so there's no RDC) and works in two phases.
First phase is to scrape all of the text and output to an English .resx file. Toughest part of this is identifying translatable text within functions, and replacing embedded fields with tokens indicating "don't translate."
After the localized versions of the resx come back, the second phase of the app takes each report along with each resx and saves out new reports with English replaced with translated text. This also allowed us to switch out the fonts only in Japanese reports to MS Gothic, thereby avoiding the need to license a "universal" font. The Japanese characters in "universal" fonts (e.g. Arial Unicode MS) tend to look like crap.
The Crystal API is byzantine, and you need to be careful with edge cases around detecting translatable strings within functions and embedded fields. Be careful with the builtin fields like PageNofM, they aren't enclosed in curly braces (not to mention that you should replace this with Page {field} of {field} so "page" and "of" can be translated). One pointer, use the controllers to replace existing items with cloned/modified copies, you can't just modify the text content of items in place. Good luck if you go this route, but in the end we think it's the best option.
Single Crystal report Use for multiple language
if (CultureInfo.CurrentCulture.Name == "en-US")
{
(obj.ReportDefinition.ReportObjects["lbleverest"] as TextObject).Text = resBundle.GetString("Localization", "everest");
(obj.ReportDefinition.ReportObjects["lblmandlicode"] as TextObject).Text = resBundle.GetString("Localization", "SocietyCode");
(obj.ReportDefinition.ReportObjects["MandliName1"] as FieldObject).ApplyFont(new Font(resBundle.GetString("Localization", "Font"), Convert.ToInt32(resBundle.GetString("Localization", "FontSize")), FontStyle.Regular));
(obj.ReportDefinition.ReportObjects["shortName1"] as FieldObject).ApplyFont(new Font(resBundle.GetString("Localization", "Font"), Convert.ToInt32(resBundle.GetString("Localization", "FontSize")), FontStyle.Regular));
}
else
{
(obj.ReportDefinition.ReportObjects["lbleverest"] as TextObject).Text = resBundle.GetString("Localization", "everest");
(obj.ReportDefinition.ReportObjects["lblmandlicode"] as TextObject).Text = resBundle.GetString("Localization", "SocietyCode");
(obj.ReportDefinition.ReportObjects["MandliName1"] as FieldObject).ApplyFont(new Font(resBundle.GetString("Localization", "Font"), Convert.ToInt32(resBundle.GetString("Localization", "FontSize")), FontStyle.Regular));
(obj.ReportDefinition.ReportObjects["shortName1"] as FieldObject).ApplyFont(new Font(resBundle.GetString("Localization", "Font"), Convert.ToInt32(resBundle.GetString("Localization", "FontSize")), FontStyle.Regular));
}
obj.DataDefinition.FormulaFields["lang"].Text = "'" + CultureInfo.CurrentCulture.Name + "'";
cv.crystalReportViewer1.ReportSource = obj;
cv.Show();