iText7: Allow ListItem to flow horizontal next to each other - itext

I'm looking for a way to have up to 3 list items next to each other. I've seen similar question with text blocks in the past with the recommendation to use Table as future proof mechanism. This isn't possible in my case, because accessibility requires me to use the semantic correct element.
Visual example:
# Fruits
| 1. Apple | 2. Banana | 3. ...
| 4. ... | 5. ...
I tried the following and some neaunces of it:
List list = new List();
list.setWidth(UnitValue.createPercentValue(100));
var listItem1 = new ListItem("Apple");
listItem1.setWidth(UnitValue.createPercentValue(30));
listItem1.setKeepTogether(true);
listItem1.setHorizontalAlignment(HorizontalAlignment.LEFT);
listItem1.setVerticalAlignment(VerticalAlignment.TOP);
list.add(listItem1);
var listItem2 = new ListItem("Banana");
listItem2.setWidth(UnitValue.createPercentValue(30));
listItem2.setKeepTogether(true);
listItem2.setHorizontalAlignment(HorizontalAlignment.CENTER);
listItem2.setVerticalAlignment(VerticalAlignment.TOP);
list.add(listItem2);
var listItem3 = new ListItem("...");
listItem3.setWidth(UnitValue.createPercentValue(30));
listItem3.setKeepTogether(true);
listItem3.setHorizontalAlignment(HorizontalAlignment.RIGHT);
listItem3.setVerticalAlignment(VerticalAlignment.TOP);
list.add(listItem3);
document.add(list);

Related

OpenXML Property to Indent Nested List

I created a bullet list with OpenXML. However, I can't figure out how to enable indentation when tab is pressed on a bullet.
Here is the code snippet to create bullet rows:
var abstractLevel1 = new Level(new NumberingFormat() {Val = NumberFormatValues.Bullet}, new LevelText() {Val = "●"}) {LevelIndex = 0};
var abstractLevel2 = new Level(new NumberingFormat() {Val = NumberFormatValues.Bullet}, new LevelText() {Val = "○"}) {LevelIndex = 1};
var abstractLevel3 = new Level(new NumberingFormat() {Val = NumberFormatValues.Bullet}, new LevelText() {Val = "■"}) {LevelIndex = 2};
var abstractNum1 = new AbstractNum(abstractLevel1, abstractLevel2, abstractLevel3) {AbstractNumberId = abstractNumberId};
In the created document, when I try to create a sub/nested bullet by hitting tab, it results in the following:
● Apples
○ Green Apples
● Pears
The bullet type changes as I expect but the indentation is wrong for Green Apples.
I took a document that has a working bullet list and converted it to an XML. Here is the section for the bullet list style:
<text:list-style style:name="WWNum1">
<text:list-level-style-bullet text:level="1" text:style-name="ListLabel_20_1" style:num-suffix="●" text:bullet-char="●">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" fo:text-indent="-0.25in" fo:margin-left="0.5in"/>
</style:list-level-properties>
</text:list-level-style-bullet>
<text:list-level-style-bullet text:level="2" text:style-name="ListLabel_20_2" style:num-suffix="○" text:bullet-char="○">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" fo:text-indent="-0.25in" fo:margin-left="1in"/>
</style:list-level-properties>
</text:list-level-style-bullet>
<text:list-level-style-bullet text:level="3" text:style-name="ListLabel_20_3" style:num-suffix="■" text:bullet-char="■">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" fo:text-indent="-0.25in" fo:margin-left="1.5in"/>
</style:list-level-properties>
Notice the properties fo:text-indent and fo:margin-left. These properties are missing in the XML document produced by my code. I suspect this is the reason why sub/nested bullets are not being indented as shown in the example above. I searched through the OpenXML documentation and I could not find any information on these 2 properties. Which OpenXML class is responsible for those properties? I'm sure I need to add another argument when I instantiate a Level class but I could not figure out from the doc what it needs to be. Any ideas?
So far I've tried playing around with the ParagraphStyleIdInLevel and Indentation classes to no success.

Google Form Grid prevent 2 rows from having a same column value

I have a Grid in my google form, where I want to add a script or an add-on that prevents both rows from having a same answer
In the above box Restless cannot be MOST and Least both
I want to disable option for LEAST for Restless when MOST is selected
If MOST has one column, LEAST can have any column other than the column taken by MOST
For Example
Solution:
Use GridValidationBuilder to limit multiple choice items to one response per column, with the method requireLimitOneResponsePerColumn().
Code snippet:
For example, to create your item:
function createItem() {
var form = FormApp.getActiveForm();
var gridItem = form.addGridItem();
gridItem.setTitle('Fill the options below')
.setRows(['MOST', 'LEAST'])
.setColumns(['Restless', 'Neighborly', 'Appealing', 'Careful']);
var gridValidation = FormApp.createGridValidation()
.setHelpText("Select one item per column.")
.requireLimitOneResponsePerColumn()
.build();
gridItem.setValidation(gridValidation);
}
Then, in your form, if you try to select the same column in the two rows:

Updating Embedded Charts in Google Docs with Google Apps Script

TLDR; How do I use the Script Editor in Docs to update an embedded Sheets chart in the document?
I know there is a script that does this for Google Slides, but I'm trying to do it in Google Docs and can't find any documentation thereof.
https://developers.google.com/slides/how-tos/add-chart#refreshing_a_chart
To be specific, I have a Google Doc. This doc contains about thirty tables and embedded charts that are all linked to a separate Google Sheet. All thirty come from a single Google Sheet. Now, I can have our non-geeky people click on all thirty "Update" hover buttons every time the spreadsheet changes, but I expect the spreadsheet to change a lot, and I would like to idiot-proof the document to ensure it's always up-to-date. As far as I can tell, this isn't a feature Google Apps does out of the box, so I wanted to write a script to do it.
But I can't find any way to access an EmbeddedChart from a Google Doc.
If I could run something like this like you can in Sheets, I could probably figure it out, but I can't:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var charts = sheet.getCharts();
for (var i in charts) {
var chart = charts[i];
// Update the chart
}
}
Although docs has the following function, DocumentApp.getActiveDocument(), an object Document doesn't contain a function getCharts(). I believe they're considered to be Images, but Images don't have an update function.
Is it even possible to access/update an EmbeddedChart in Docs using a script? Maybe by running the script through the spreadsheet on edit and updating the doc from there? Seems weird that you can do it in Slides of all things, but not Docs.
in Google Docs DOM charts as InlineImages here is the script that logs images attributes. but in they looks to be read only and documentation for this method ends with dead end: "null if the element contains multiple values for this attribute." https://developers.google.com/apps-script/reference/document/inline-image#getLinkUrl()
function myFunction() {
var doc = DocumentApp.getActiveDocument()
var body = doc.getBody()
var pars = body.getParagraphs()
var atts = img.getAttributes();
// Log the paragraph attributes.
for (var att in atts) {
Logger.log(att + ":" + atts[att]);
}
for (var par in pars) {
Logger.log(pars[par].getText());
var chN = pars[par].getNumChildren()
Logger.log(chN);
if(chN>0){
var type = pars[par].getChild(0).getType()
Logger.log(type);
if(type=="INLINE_IMAGE"){
var atts = pars[par].getChild(0).getAttributes()
Logger.log(JSON.stringify(atts));
for (var att in atts) {
Logger.log(att + ":" + atts[att]);
}
}
}
}
return
}
The goal is to update the ranges of each chart to encompass the number of columns and rows of the sheet referenced by the range.
The approach is to enumerate all ranges within all charts within all sheets, clear the range and re-add it with the right size. The getDataRange() function is a convenient way to get the right-sized range. The only tricky part is that you don't update the chart directly -- you need to get its builder, modify that, rebuild it, and then update the chart with the built object.
for (const sheet of SpreadsheetApp.getActive().getSheets()) {
for (const chart of sheet.getCharts()) {
const embeddedChartBuilder = chart.modify();
const ranges = chart.getRanges();
embeddedChartBuilder.clearRanges();
for (const range of ranges) {
const dataRange = range.getSheet().getDataRange();
embeddedChartBuilder.addRange(dataRange);
}
const embeddedChart = embeddedChartBuilder.build();
sheet.updateChart(embeddedChart);
}
}
The code sample assumes that your ranges are intended to encompass all the columns and rows of the referenced sheet.

Unable to set a global variable

I want to use a function and the parameter I am passing should be set to global all the time. How can I do that? Here is my code:
function ReadExcelfunction($FileName,$SheetName,$RowNum,$ColNum,$Parameter)
{
var $excel = _getExcel($FileName,$SheetName);
var $excelData=$excel.getData();
var $Parameter=$excelData[$RowNum][$ColNum];
//_setGlobal($Parameter,$excelData[$RowNum][$ColNum]) -- Commented
}
Now suppose I pass the parameters as -- File sheet 1 1 Name.
What I want is this: name with the Value is stored as Global value.
Earlier I used _setGlobal($Parameter,$excelData[$RowNum][$ColNum]) which solved the purpose but this API has been removed and now I need to change my script.
I am using the sahi scripting language which is similar to JavaScript.
You don't need to use _setGlobal, you only need to declare a var before the function declaration. For example, you can declare a new Array and then set/get values just like _setGlobal.
// www.google.com used as start URL
var $globalVariable = new Array();
function SetGlobalVariable(key, newValue) {
$globalVariable[key] = newValue;
}
SetGlobalVariable('inputValue', 'stack overflow');
_setValue(_textbox("q"), $globalVariable['inputValue']);
A probable solution for you is to write value to an existing excel sheet cell from the sahi script on the fly and then retrieve the same value from the corresponding cell of excel sheet from another sahi script.
I have done a similar thing using a simple text file.
First File
\\ script 1
var $str = "Hello World";
var$filePath = "C:\\temp\\mystring.txt";
_writeToFile($str, $filePath);
Second File
\\ script 2
var $filePath = "C:\\temp\\mystring.txt";
var $mystr = _readFile($filePath);
Edit: Extended Answer
--------------------------------
| VariableName | VariableValue |
--------------------------------
| MyVar1 | MyVar1Value |
--------------------------------
| MyVar2 | MyVar2Value |
--------------------------------
| MyVar3 | MyVar3Value |
--------------------------------
Create a Sahi Function to creating a new excel sheet:
function _createExcelFile($fileName, $sheetName){
if($sheetName == null || $sheetName == ""){
$sheetName = "Sheet1";
}
_debug("Excel File Name :: " + $fileName);
_debug("Excel File Sheet Name :: " + $sheetName);
var $excelPoi = new Packages.net.sf.sahi.util.ExcelPOI($fileName, $sheetName);
$excelPoi.createNew();
}
Further you can refer the _getExcel($filePath[, $sheetName]) API from Sahi Pro. You need to do some iterations to get things done. You can read and write data as required.
Note: I have tried this only in the latest version of Sahi Pro i.e. 6.1.0.

Fitnesse smartrics.rest.fitnesse.fixture.RestFixture.setBaseUrl

I have a requirement for a test to make a call to one REST endpoint that generates a security token then make a second to the actual system under test. In order to do this I am using smartrics.rest.fitnesse.fixture.RestFixture and setting the baseurl in instantiation to the first base. I am trying to make this call and then set the new baseurl to the new location but am having trouble doing so.
It appears from perusing the code that there is a method setBaseUrl(Url url) but I cannot find an example of using this and am failing trying to figure it out myself.
Has anyone had any luck with this or is there another, better/easier way to achieve this?
The problem lies in RestFixture:processRow - since it uses Java reflection, it attempts to call method without parameters. This will fail since setBaseUrl accepts one argument (Url). I have tried one modification, though not the best way to achieve it - current code RestFixture v3.0 (RestFixture.processRow()):
method1 = getClass().getMethod(methodName);
method1.invoke(this);
Modified code in RestFixture.processRow():
Method[] methods = getClass().getMethods();
int i = 0;
for(i = 0; i < methods.length; i++){
if(methodName.equals(methods[i].getName())){
method1 = methods[i];
break;
}
}
Class[] paramTypes = method1.getParameterTypes();
List<Object> params = new ArrayList<Object>();
for(i = 0; i < paramTypes.length; i++){
String cellText = row.getCell(i+1).text();
Object param = paramTypes[i].getConstructor(String.class).newInstance(cellText);
params.add(param);
}
method1.invoke(this, params.toArray());
Once this modification is done (you might need to add required imports - java.lang.InstantiationException, java.lang.Object, java.util.ArrayList; and an exception handler for InstantiationException), re-build the RestFixture and that should work.
We had what sounds like a similar requirement - we needed to use RestFixture(POST) to retrieve a URL for use in a subsequent RestFixture call(GET).
(Note that we're using an ancient RestFixture 1.1)
I modified the processArguments() method in RestFixture.java thus:
// baseUrl = new Url(args[0]); // original line
baseUrl = new Url(resolve(args[0])); // modified
With this modification in place, my Fitnesse test looks like this:
`!| RestFixture | http:///fds |
| setBody |{"param1":"blah","param2":"blather"} |
| POST | /GetThatUrl | 200 | | |
| let | $urlresult | body | |
!| RestFixture | $urlresult |
| GET| | 200 | Content-Length:[\d]+ | ||`
Without the code change, $urlresult was not resolved and I could not pass in the URL as a variable.