How to get text ranges based on fonts - ms-word

I have a paragraph that has multiple fonts applied. There are a number of ranges because of that. Is there a way (without working with the OOXML directly) to get these ranges, their fonts, and their text? Here is an example OOXML snippet I'm talking about:
<w:p w:rsidR="00301FAD" w:rsidRDefault="00301FAD">
<w:r w:rsidRPr="001D4040">
<w:rPr>
<w:b/>
<w:bCs/>
</w:rPr>
<w:t>Spam</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve"/>
</w:r>
<w:r w:rsidRPr="001D4040">
<w:rPr>
<w:b/>
<w:bCs/>
<w:i/>
<w:iCs/>
</w:rPr>
<w:t>and</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve"/>
</w:r>
<w:r w:rsidRPr="001D4040">
<w:rPr>
<w:i/>
<w:iCs/>
</w:rPr>
<w:t>eggs</w:t>
</w:r>
</w:p>
The paragraph text in Word looks like this:
Spam and eggs

You can use the paragraph class' split method which can split the paragraph into ranges based on a string. I used this function to print the font and the text of the example provided:
async function run() {
await Word.run(async (context) => {
const body = context.document.body;
var par = body.paragraphs.getFirst();
let words = par.split([" "]);
let first_word = words.getFirst();
first_word.load(["font", "text"]);
await context.sync();
console.log(f_word.font);
console.log(f_word.text);
});
}
One downside to this is that you can't differentiate between a word that has fonts like this: Spam, or like this: Spam since it will set the bold property to null both times.

Related

document.contentControls not returning all ContentControls in the document

I have a document with three ContentControl objects that looks like this:
Here is the .docx file in its entirety - but essentially the markup of the document body looks like this:
<w:body>
<w:p w:rsidR="0075044D" w:rsidRDefault="0075044D">
<w:r>
<w:t xml:space="preserve">Video provides a powerful way to help you </w:t>
</w:r>
<w:sdt>
<w:sdtPr>
<w:alias w:val="cc1"/>
<w:tag w:val="prove"/>
<w:id w:val="806369342"/>
<w:placeholder>
<w:docPart w:val="1F3FDE3D075A4E8AADE251C4E318E379"/>
</w:placeholder>
<w15:color w:val="FF9900"/>
<w15:appearance w15:val="tags"/>
<w:text/>
</w:sdtPr>
<w:sdtContent>
<w:r>
<w:t>prove</w:t>
</w:r>
</w:sdtContent>
</w:sdt>
<w:r>
<w:t xml:space="preserve"> your point. When you click Online Video, you can paste in the embed code for the video you want to add. You can also </w:t>
</w:r>
<w:sdt>
<w:sdtPr>
<w:alias w:val="cc2"/>
<w:tag w:val="number 2"/>
<w:id w:val="1463999480"/>
<w:placeholder>
<w:docPart w:val="1F3FDE3D075A4E8AADE251C4E318E379"/>
</w:placeholder>
<w15:color w:val="FF0000"/>
<w15:appearance w15:val="tags"/>
</w:sdtPr>
<w:sdtContent>
<w:r>
<w:t>type</w:t>
</w:r>
</w:sdtContent>
</w:sdt>
<w:r>
<w:t xml:space="preserve"> a keyword to search online for the video that best fits your document.</w:t>
</w:r>
</w:p>
<w:p w:rsidR="0075044D" w:rsidRDefault="0075044D">
<w:r>
<w:t xml:space="preserve">To make your document look professionally produced, Word provides </w:t>
</w:r>
<w:sdt>
<w:sdtPr>
<w:alias w:val="cc3"/>
<w:tag w:val="xxx"/>
<w:id w:val="1703202634"/>
<w:placeholder>
<w:docPart w:val="1F3FDE3D075A4E8AADE251C4E318E379"/>
</w:placeholder>
<w15:color w:val="FF99CC"/>
<w15:appearance w15:val="tags"/>
<w:text/>
</w:sdtPr>
<w:sdtContent>
<w:r>
<w:t>header</w:t>
</w:r>
</w:sdtContent>
</w:sdt>
<w:r>
<w:t>, footer, cover page, and text box designs that complement each other. For example, you can add a matching cover page, header, and sidebar. Click Insert and then choose the elements you want from the different galleries.</w:t>
</w:r>
</w:p>
<w:p w:rsidR="0075044D" w:rsidRDefault="0075044D"/>
<w:p w:rsidR="00000000" w:rsidRDefault="0075044D"/>
<w:sectPr w:rsidR="00000000">
<w:pgSz w:w="11906" w:h="16838"/>
<w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="708" w:footer="708" w:gutter="0"/>
<w:cols w:space="708"/>
<w:docGrid w:linePitch="360"/>
</w:sectPr>
</w:body>
When I run the code below, only the control in the middle is returned by document.contentControls and therefore changed by my code. Any ideas why the other two controls are not returned? Did anyone else encounter this issue? Is there a way to fix it?
Word.run(function (context) {
var myContentControls = context.document.contentControls;
myContentControls.load("tag");
return context.sync()
.then(function () {
for (var i = 0; i < myContentControls.items.length; i++)
{
myContentControls.items[i].color = "blue";
myContentControls.items[i].title = "myCC";
myContentControls.items[i].appearance = "tags";
}
return context.sync();
});
}).catch(OfficeHelpers.Utilities.log);
Here is a ScriptLab gist for convenience.
Interestingly, this VBA code returns the correct result (3):
Sub Main()
MsgBox ActiveDocument.ContentControls.Count
End Sub
I have only tried this on Windows 10 / Office 365 desktop client.
As stated in the Word JS APIs' documentation for content controls, only Rich Text content controls are supported / recognized. So code will not "see" plain text content controls.
Whether a content control is plain text or rich text is not visually recognizable (unless it contains formatting or content other than text). There's also nothing in the Word Open XML to differentiate the type of content control, unless it contains formatting or a non-text object.
As Cindy Meister already said, the Word OfficeJS API only returns RichText content controls - see Word.ContentControl.
If you dive into the OOXML, you'll find that plain text context controls (the ones that are not returned) main difference from the rich text ones is that they are marked with <w:text/>. This essentially means that if that tag is removed, then the plain text content control becomes a rich text content control. So here is my workaround to this issue:
var ooxml = context.document.body.getOoxml();
await context.sync();
var newxml = ooxml.value.replace(/<w:text\/>/g, '');
context.document.body.insertOoxml(newxml, Word.InsertLocation.replace);
var myContentControls = context.document.contentControls;
myContentControls.load();
await context.sync();
console.log(myContentControls.items.length); // now returns 3. Yay!!!
return context.sync();
Nota Bene: getOoxml() and insertOoxml() are slow methods and this workaround will take a long time to execute, so only use when strictly necessary.

DYMO print label text getting cut off

I am trying to print Address label on dymo labelwriter 450 turbo
But the text is getting cutoff
I am using the below xml to format the text
function getAddressLabelXml()
{
var labelXml = '<?xml version="1.0" encoding="utf-8"?>\
<DieCutLabel Version="8.0" Units="twips">\
<PaperOrientation>Landscape</PaperOrientation>\
<Id>Address</Id>\
<PaperName>30252 Address</PaperName>\
<DrawCommands>\
<RoundRectangle X="0" Y="0" Width="1581" Height="5040" Rx="270" Ry="270" />\
</DrawCommands>\
<ObjectInfo>\
<AddressObject>\
<Name>Address</Name>\
<ForeColor Alpha="255" Red="0" Green="0" Blue="0" />\
<BackColor Alpha="0" Red="255" Green="255" Blue="255" />\
<LinkedObjectName></LinkedObjectName>\
<Rotation>Rotation0</Rotation>\
<IsMirrored>False</IsMirrored>\
<IsVariable>True</IsVariable>\
<HorizontalAlignment>Left</HorizontalAlignment>\
<VerticalAlignment>Middle</VerticalAlignment>\
<TextFitMode>ShrinkToFit</TextFitMode>\
<UseFullFontHeight>True</UseFullFontHeight>\
<Verticalized>False</Verticalized>\
<StyledText/>\
<ShowBarcodeFor9DigitZipOnly>False</ShowBarcodeFor9DigitZipOnly>\
<BarcodePosition>BelowAddress</BarcodePosition>\
<LineFonts/>\
</AddressObject>\
<Bounds X="332" Y="150" Width="4455" Height="1260" />\
</ObjectInfo>\
</DieCutLabel>';
return labelXml;
}
Depending on the length and height of the text, the text is either getting cutoff on the top or on the right
I am looking for a way to auto fit the text inside the label
Thanks in advance.
Change the TextFitMode value from 'ShrinkToFit' to 'AlwaysFit'

Does the w:style with the w:type="table" and w:default="1" attribute automatically apply to a w:tbl without a w:tblStyle?

I found a table has a padding sytle, but its w:tbl does not have a w:tblStyle. Does the w:style which has the w:type="table" and w:default="1" attributes have an effect in this case?
The background is that I'm using XSLT to transform the Open XML markup.
The short answer to your question is "Yes"; the default style will apply if no style is explicitly assigned.
There are four different types of styles in WordprocessingML, i.e., paragraph, character, table, and numbering styles. For each type (e.g., table), one style is marked as the default style for related Open XML elements (e.g., w:tbl elements) by having an attribute w:default="1". The typical default styles are shown below:
<w:style w:type="paragraph" w:default="1" w:styleId="Normal">
<w:name w:val="Normal"/>
<w:qFormat/>
</w:style>
<w:style w:type="character" w:default="1" w:styleId="DefaultParagraphFont">
<w:name w:val="Default Paragraph Font"/>
<w:uiPriority w:val="1"/>
<w:semiHidden/>
<w:unhideWhenUsed/>
</w:style>
<w:style w:type="table" w:default="1" w:styleId="TableNormal">
<w:name w:val="Normal Table"/>
<w:uiPriority w:val="99"/>
<w:semiHidden/>
<w:unhideWhenUsed/>
<w:tblPr>
<w:tblInd w:w="0" w:type="dxa"/>
<w:tblCellMar>
<w:top w:w="0" w:type="dxa"/>
<w:left w:w="108" w:type="dxa"/>
<w:bottom w:w="0" w:type="dxa"/>
<w:right w:w="108" w:type="dxa"/>
</w:tblCellMar>
</w:tblPr>
</w:style>
<w:style w:type="numbering" w:default="1" w:styleId="NoList">
<w:name w:val="No List"/>
<w:uiPriority w:val="99"/>
<w:semiHidden/>
<w:unhideWhenUsed/>
</w:style>
For example, if you have w:p (paragraph), w:r (run), or w:tbl (table) elements without an explicit style being assigned to them (e.g., using w:pStyle, w:rStyle, or w:tblStyle), the default styles for those types of elements will apply.

Image is not displayed sapui5

I am displaying images in my page so i am using Image control
<m:Image src="{path: 'MyModel>Link', formatter:'.formatter.imageFormatter' }" visible= "true" alt="{i18n>picname}"></m:Image>
and the formatter
imageFormatter: function(val) {
return val;
},
when i see the network in the debbuger the image is loaded perfectlly with status 200 and when i see preview it is an empty image But in My page nothing is displayed (When i open the image in other tab when i go back to my app all images are displayed )
I Don't know the problem
Set the "densityAware" property to false in the sap.m.Image control and try again
Simon.
Set a value in the Column Header - e.g.: (please namespace correctly - you need to prefix with m:)
<Column
hAlign="Center"
visible="true"
width="145px">
<Text text="Image"/>
</Column>
Not doing so may be having consequences you are not anticipating.
Also, to me, your cells collection seems incorrect - can you try:
<m:items>
<m:ColumnListItem type="Navigation" detailPress="onEdit">
<m:cells>
<m:Image src="{path: 'MyModel>Link', formatter:'.formatter.imageFormatter' }" visible="true" alt="{i18n>picname} />
</m:cells>
</m:ColumnListItem>
</m:items>

How to create an SVG "tooltip"-like box?

Given an existing valid SVG document, what's the best way to create "informational popups", so that when you hover or click on certain elements (let's say ) you popup a box with an arbitrary amount (i.e. not just a single line tooltip) of extra information?
This should display correctly at least in Firefox and be invisible if the image was rasterized to a bitmap format.
This question was asked in 2008. SVG has improved rapidly in the intervening four years. Now tooltips are fully supported in all platforms I'm aware of. Use a <title> tag (not an attribute) and you will get a native tooltip.
Here are the docs:
https://developer.mozilla.org/en-US/docs/SVG/Element/title
<svg>
<text id="thingyouhoverover" x="50" y="35" font-size="14">Mouse over me!</text>
<text id="thepopup" x="250" y="100" font-size="30" fill="black" visibility="hidden">Change me
<set attributeName="visibility" from="hidden" to="visible" begin="thingyouhoverover.mouseover" end="thingyouhoverover.mouseout"/>
</text>
</svg>
Further explanation can be found here.
Since the <set> element doesn't work with Firefox 3, I think you have to use ECMAScript.
If you add the following script element into your SVG:
<script type="text/ecmascript"> <![CDATA[
function init(evt) {
if ( window.svgDocument == null ) {
// Define SGV
svgDocument = evt.target.ownerDocument;
}
tooltip = svgDocument.getElementById('tooltip');
}
function ShowTooltip(evt) {
// Put tooltip in the right position, change the text and make it visible
tooltip.setAttributeNS(null,"x",evt.clientX+10);
tooltip.setAttributeNS(null,"y",evt.clientY+30);
tooltip.firstChild.data = evt.target.getAttributeNS(null,"mouseovertext");
tooltip.setAttributeNS(null,"visibility","visible");
}
function HideTooltip(evt) {
tooltip.setAttributeNS(null,"visibility","hidden");
}
]]></script>
You need to add onload="init(evt)" into the SVG element to call the init() function.
Then, to the end of the SVG, add the tooltip text:
<text id="tooltip" x="0" y="0" visibility="hidden">Tooltip</text>
Finally, to each of the element that you want to have the mouseover function add:
onmousemove="ShowTooltip(evt)"
onmouseout="HideTooltip(evt)"
mouseovertext="Whatever text you want to show"
I've written a more detailed explanation with improved functionality at http://www.petercollingridge.co.uk/interactive-svg-components/tooltip
I haven't yet included multi-line tooltips, which would require multiple <tspan> elements and manual word wrapping.
This should work:
nodeEnter.append("svg:element")
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; })
.append("svg:title")
.text(function(d) {return d.Name+"\n"+d.Age+"\n"+d.Dept;}); // It shows the tool tip box with item [Name,Age,Dept] and upend to the svg dynamicaly