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

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.

Related

How to get text ranges based on fonts

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.

TYPO3 10.4.12 optionSplit in IMAGE srcset

In my TypoScript object the optionSplit failed. Always a comma is added in srcset and W3C validator said: Bad value for attribute srcset on element img: Ends with empty image-candidate string.
This TypoScript snippet
layoutKey = srcset
layout {
srcset {
element = <img src="###SRC###" srcset="###SOURCECOLLECTION###" ###PARAMS### ###ALTPARAMS### ###SELFCLOSINGTAGSLASH###>
source = ###SRC### ###SRCSETCANDIDATE###,|*|###SRC### ###SRCSETCANDIDATE###,|*|###SRC### ###SRCSETCANDIDATE###
}
}
results in
<img src="/storage/shared/hochschule/labels/swissuniversities-logo.png"
srcset="
/storage/_processed_/5/6/csm_swissuniversities-logo_685d915ef8.png 687w,
/storage/_processed_/5/6/csm_swissuniversities-logo_57966614b3.png 436w,
/storage/_processed_/5/6/csm_swissuniversities-logo_74d43a23bf.png 255w,"
class="image-embed-item img-fluid"
sizes="(max-width: 767px) 687px, (min-width: 768px) and (max-width: 991px) 436px, (min-width: 992px) 255px" alt="">
Is this a bug?
Optionsplit only has three values (per level). the separation on main level is done by |*|, the second level separation is ||. As the default wrap-separation is | you could get a confusion if you miss some spaces. Especially if one side of the wrap is empty.
as you can remove values, you can work with only one separator, but you can't include more values. you also can ommit the |*| separators at all and only use second level separators ||
The first (before the first separator) or only 'normal' wrapping is the beginning, then following the middle part. And after a second separator the ending part.
more confusion can be generated if you use optionSplit with the wrapping .noTrimWrap where there also are | separators around the whole wrap. So be careful with your separators and spaces.

Multiple lines in bootstrap navbar

I am using bootstrap-vue. I try to convert existing header to the navbar. There shall be a big brand name and a smaller slogan under it. I tried to use H1 and b-nav-text with BR but both texts are always rendered side by side. How can I place the slogan below the brand title?
<b-navbar-brand href="/">
<img src="./assets/logo.png" :alt="$t('app.logo-alt')" class="d-inline-block align-top">
</b-navbar-brand>
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
<b-collapse id="nav-collapse" is-nav>
<b-navbar-nav>
<b-nav-text class="text-white">{{ $t('app.name') }}</b-nav-text>
<br>
<b-nav-text class="text-white">{{ $t('app.slogan') }}</b-nav-text>
</b-navbar-nav>
The upper side of picture is b-nav output, the below is original header built with b-container.
d-inline-flex flex-column
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
<b-collapse id="nav-collapse" is-nav>
<b-navbar-nav>
<b-nav-text class="d-inline-flex flex-column">
<span>Lorem ipsum is placeholder text commonly used in</span>
<span>the graphic, print</span>
</span>
</b-nav-text>
</b-navbar-nav>

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.

Change icon color if condition

I am using a list that prints data from a model and one should have an icon. The thing is that the icon changes depending on the value and I should also change its color.
I have in my view :
<ObjectListItem title="State" type="Active" number="{/Data/8/state}"
icon="{= ${/Data/8/state}.toUpperCase() === 'OK' ? 'sap-icon://accept' :
'sap-icon://decline' }"></ObjectListItem>
Options like addStyleClass doesn't seem to work. I have changed the color by adding css to the id that SAP adds to the Icon, but since it has to change according to the value I don't know how to achieve it.
Another option was to add color directly to these two icons but I wasn't able to add the classes.
You can use CustomData and then create a css selector to match it:
<ObjectListItem title="State" type="Active" number="{/Data/8/state}"
icon="{= ${/Data/8/state}.toUpperCase() === 'OK' ? 'sap-icon://accept' :
'sap-icon://decline' }">
<customData>
<core:CustomData writeToDom="true" key="class" value="{= ${/Data/8/state}.toUpperCase()}" />
</customData>
</ObjectListItem>
This will render your control with an additional data-class attribute (actually, data-{key}, where key is the key that you defined on your core:CustomDatatag).
You can then match that with the CSS selector
[data-class='OK'] {
color: blue !important;
}
[data-class='NOT-OK']{
color: red !important;
}