Conditionally apply Paragraph Style to text in a Table - adobe-indesign

I have this code that works:
var myTable = app.activeDocument.stories.everyItem().tables.everyItem().getElements();
for(i=0; i<myTable.length; i++) {
myTable[i].cells[0].insertionPoints[0].appliedParagraphStyle = app.activeDocument.paragraphStyleGroups.item("Wycena").paragraphStyles.item("Nazwa A. Numeracja2");
}
This code applies one Paragraph Style to all rows in a Table, however what I need is as follows:
If I paste text that does begin with a bullet symbol (•) into a Table then apply "Paragraph Style 1"
If I paste text that does not begin with a bullet symbol (•) into a Table then apply "Paragraph Style 2".
What I think I need is an if statement somewhere, but I cant work it out.

You can apply Paragraph Style 2 to all the text and then run the script to format only the text with the bullet symbol:
var myDocument = app.documents.item(0);
var allCells = myDocument.stories.everyItem().tables.everyItem().cells.everyItem().getElements();
for ( var i = 0; i < allCells.length; i++)
{
if ( allCells[i].contents.indexOf('•') > -1)
{
allCells[i].appliedCellStyle = 'Paragraph Style 1';
allCells[i].clearCellStyleOverrides();
}
}
You can change the "•" to any other text you want a specific format and that cell will be formatted accordingly.

Related

Indesign Script: Looping ALL paragraphs (including in overset)

Looking for a selector of ALL paragraphs in the selected TextFrame, including the "not visible ones" in the overset. Script is already working and looping through the visible paragraphs:
[...]
if(app.selection[0].constructor.name=="TextFrame") {
var myParagraphs = app.selection[0].paragraphs; // only visible ones?!
var myArray = myParagraphs.everyItem().contents;
for (var i=0; i<myArray.length; i++) {
// do some fancy styling - WORKING
myParagraphs[i].appliedParagraphStyle = app.activeDocument.paragraphStyles.item('Format XYZ');
}
}
myArray.length changes when I set another hight for the TextFrame. But how can I work with ALL paragraphs? Already tested .anyItem() with the same result :(
Well, the paragraphs in the overset are not paragraphs of the text frame, so it makes sense that they are skipped in your script. To access all the paragraphs of the text frames + those that are in the overset part, you will need to access all paragraphs of the parent story (a story is the text entity that describes all the text within linked text frames and the overset text) of the text frame.
You can do so like this:
if(app.selection[0].constructor.name === "TextFrame") {
var myParagraphs = app.selection[0].parentStory.paragraphs;
for (var i = 0; i < myParagraphs.length; i++) {
myParagraphs[i].appliedParagraphStyle = app.activeDocument.paragraphStyles.item("Format XYZ");
}
}
Be aware though that this will handle all paragraphs in all text frames that are linked to your text frame in case there are any of those.
Also, since it looks like you need to apply the paragraph style on each paragraph of the entire story, you might as well apply the paragraph style to the entire story directly instead of looping over the paragraphs:
app.selection[0].parentStory.appliedParagraphStyle = app.activeDocument.paragraphStyles.item("Format XYZ");

Google Slides API- How to change text color for all shapes of a certain color

I have 11 files with over 140 slides each, and none of the shapes are tied to a theme/master. My goal was the change the master font and also replace all the red text (there is SO much red text) with black text.
I successfully updated the master font (thanks to https://gist.github.com/dsottimano/20a50daded2128b4c86acb430cecba67), but have come up short in trying to write something for ForegoundColor.
I tried to adapt this code and cannot make it work: https://mashe.hawksey.info/2017/10/changing-the-color-of-all-links-in-google-slides-with-google-apps-script/
I need to replace all text formatted with foregroundcolor hex #e04935 with hex #000000.
Appreciate any tips on making this work!
Here is what I have done so far:
//original from: https://mashe.hawksey.info/2017/10/changing-the-color-of-all-links-in-google-slides-with-google-apps-script/
/**
* #OnlyCurrentDoc
*/
function changeTextColorforShapes(){
var deck = SlidesApp.getActivePresentation();
var slides = deck.getSlides();
slides.forEach(function(slide) {
// https://developers.google.com/apps-script/reference/slides/slide#getPageElements()
var elements = slide.getPageElements();
elements.forEach(function(element){
// https://developers.google.com/apps-script/reference/slides/page-element#getPageElementType()
var type = element.getPageElementType();
// Text boxes are 'SHAPES' (this code doesn't handle table cells)
if (type == "SHAPE"){
// https://developers.google.com/apps-script/reference/slides/text-range#getTextStyle()
var textStyle = element.asShape().getText().getForegroundColor();
// https://developers.google.com/apps-script/reference/slides/text-style#hasLink()
// Returns true if text is color #e04935 (https://www.color-hex.com/color/e04935) and changes text to color #ffffff (black)
if (ForegroundColor('#e04935')
textStyle.setForegroundColor('#ffffff');
}
});
});
}
If you want to change all the text from #E04935 to #000000, you can try the below snippet:
Snippet
// Copyright 2020 Google LLC.
// SPDX-License-Identifier: Apache-2.0
function changeColor() {
var presentation = SlidesApp.getActivePresentation();
var slides = presentation.getSlides();
for (let i = 0; i < slides.length; i++) {
var elements = slides[i].getPageElements();
for (let j = 0; j < elements.length; j++)
if (elements[j].asShape().getText().getTextStyle().getForegroundColor().asRgbColor().asHexString() == '#E04935')
elements[j].asShape().getText().getTextStyle().setForegroundColor('#000000');
}
}
Explanation
The reason your code was not working is because you were trying to use the getForegroundColor() method on an object of type TextRange while this method is expected to be called from an object of type TextStyle.
So in order to test exactly if the color of the text is the wanted one, you will have to retrieve first the color as a RGB color in order to get the HEX value of it.
Reference
Apps Script Editing & Styling Text Slides;
Apps Script Class TextStyle - getForegroundColor().

Change cell color based on selection from dropdown menu

This is a script I am writing to help me figure out how to write a more complex script.
In my spreadsheet, I have one column that contains a list of values ("testRange","testRangeValues"). I also have a dropdown list ("testCell","testCellValue"). The dropdown list contains some values that are in the "testRange" list and some that are not.
I would like my script to function in such a way that when I select a value from the dropdown list that matches value from the testRange list, the background color of the corresponding value in the testRange list changes to red.
function onEdit3(e) {
var testRange = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange("A4:A8");
var testRangeValues = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange("A4:A8").getValues();
var testCell = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange("C4");
var testCellValue = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange("C4").getValue();
for(var i = 0;i<testRange.length;i++){
if(testCellValue==testRangeValues[i]){
testRange[i].setBackground("Red");
}
}
}
Currently no color change is happening. I guess I'm not quite sure how to correctly write my for loop/if statement to achieve the intended effect. Is there perhaps a way to do this using just some sort of conditional formatting formula in my spreadsheet?
You want to change the background color of cell in the range of "A4:A8" that the value of dropdown list of "C4" is the same.
You want to achieve this using Google Apps Script.
From your script, you don't want to use the event object.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Modification points:
The sheet object can be written by var sheet = SpreadsheetApp.getActiveSheet();. By this, you can use sheet for retrieving the range.
sheet.getRange("A4:A8") and sheet.getRange("C4") can be used one time.
In this case, the range object cannot be used in the loop, because testRange.length returns null.
When above points are reflected to your script, it becomes as follows.
Pattern 1:
In this pattern, only background color of the selected value is changed to the red color. So for example, when "A" is selected, the background color of "A" is changed to the red color. And when "C" is selected, the background color of "C" is changed to the red color. In this case, the background color of "A" is reset.
Modified script:
function onEdit3(e) {
var sheet = SpreadsheetApp.getActiveSheet();
var testRange = sheet.getRange("A4:A8");
var testRangeValues = testRange.getValues();
var testCell = sheet.getRange("C4");
var testCellValue = testCell.getValue();
var backgroundColors = testRangeValues.map(function([a]) {return [a == testCellValue ? "Red" : ""]});
testRange.setBackgrounds(backgroundColors);
}
Pattern 2:
In this pattern, the background color of the selected value is saved. So for example, when "A" is selected, the background color of "A" is changed to the red color. And when "C" is selected, the background color of "C" is changed to the red color. In this case, the background color of "A" is kept the red color.
Modified script:
function onEdit3(e) {
var sheet = SpreadsheetApp.getActiveSheet();
var testRange = sheet.getRange("A4:A8");
var testRangeValues = testRange.getValues();
var testCell = sheet.getRange("C4");
var testCellValue = testCell.getValue();
for (var i = 0; i < testRangeValues.length; i++) {
if (testRangeValues[i] == testCellValue) {
sheet.getRange("A" + (4 + i)).setBackground("Red");
break;
}
}
}
Modern javascript:
You can use modern javascript syntax. For this you need to enable V8 runtime. After this you can
/**
*
* #param {GoogleAppsScript.Events.SheetsOnEdit} e
*/
const onEdit = e => {
const sheet = e.range.getSheet();
const value = e.range.getValue();
if (sheet.getName() == 'Sheet1' && e.range.getA1Notation() === 'C2') {
const range = sheet.getRange(2, 1, sheet.getLastRow() - 1, 1);
range.setBackgrounds(
range.getValues().map(row => [row[0] === value ? 'red' : ''])
);
}
};
References:
setBackground(color)
setBackgrounds(color)
If I misunderstood your question and this was not the direction you want, I apologize.

inDesign JSX scripted add of heading and content into textFrame

I'm attempting to use inDesign JSX scripts to insert the following data into a document:
data = [{heading:"Heading 1", content: ["Some content"]},
{heading:"Heading 2", content: ["Some other content with", "Multiple paragraphs"]}]
The data has to be placed into a single TextFrame, but have different styling on the heading and content.
The only way I can see to add the text is in one go via the textFrame.contents variable:
allContent = "";
headingParagraphs = []; // keep track of which paragraphs are headings
paragraph = 0;
for (var i = 0; i < data.length; i++) {
allContent += data.heading + "\r"; // Use a newline to split the paragraph
headingParagraphs.push(paragraph);
paragraph++;
for (var j = 0; j < data.content.length; j++) {
allContent += data.content[j] + "\r"; // Use a newline to split the paragraph
paragraph++;
}
}
textFrame.contents = allContent; // all data is in, but all text is styled the same
Then once the data is in, I iterate the paragraphs and add some style to the headings:
for (var i = 0; i < textFrame.paragraphs.count(); i++) {
if (headingParagraphs.indexOf(i) != -1) { // this is a heading paragraph
textFrame.paragraphs[i].pointSize = 20;
}
}
This works fine for small data sets that fit on one page, but once the contents gets bigger than the frame, paragraphs only returns visible paragraphs. And if I follow on to a new textFrame, paragraphs get split and the headingParagraphs[] array no longer lines up.
Ideally I'd like to append to the contents and set styles before I append the next content - but the API docs aren't very clear on how you might do that (if at all)
// Pseudo code:
for all sections:
append the heading to the frame, split to next page if needed
style all the *new* paragraphs as headings
for all section contents
append the content to the frame, split to next page if needed
style any *new* paragraphs as normal content
Is there a way to achieve this using either an append function or some other way to assign headings to the right place after content has been added? Perhaps special characters in the content to define style?
Your longer text gets messed up because currently you are working inside a single text frame. As soon as the text runs out of this one frame, you can't refer to them as this frame's "owned" paragraphs anymore. Use parentStory instead, as it points to the whole story, inside one text frame or spanning more than one. It also keeps on working if the text gets overset.
So if you have a starting frame called textFrame, set a new variable story to textFrame.parentStory and use that to add text.
As for adding text to this frame(/story): indeed, there is no fast way to add formatted text. Setting contents only works for long swathes with the same formatting. One way I've used is to write INX formatted text to a temporary file and importing that. It's slow for short fragments, but larger stories (up to several hundreds of pages) can be created very efficiently in Javascript itself, and then importing it into ID is .. well, it aint fast but faster than trying to do it "manually".
The other way is to add contents one paragraph at a time. The trick is to set formatting and add your text to story.insertionPoints[-1]. This, in a particularly handy notation, refers to the very last text insertion point of the story. You can think of an insertion point as "the text cursor"; you can 'apply' formatting to it, and any text added will then have this formatting as well.
Your code snippet reworked to add one data item at a time:
for (var i = 0; i < data.length; i++)
{
story.insertionPoints[-1].pointSize = 20;
story.insertionPoints[-1].contents = data[i].heading + "\r"; // Use a newline to split the paragraph
story.insertionPoints[-1].pointSize = 10;
for (var j = 0; j < data[i].content.length; j++)
{
story.insertionPoints[-1].contents = data[i].content[j] + "\r"; // Use a newline to split the paragraph
}
}
One thing to note is that you cannot temporarily override the pointSize here. If you set it to your larger size, you must also set it back to the original size again (the '10' in my snippet).
Can I convince you to look in to using paragraph styles? With paragraph styles, you'd have something like
hdrStyle = app.activeDocument.paragraphStyles.item("Header");
textStyle = app.activeDocument.paragraphStyles.item("Text");
for (var i = 0; i < data.length; i++)
{
story.insertionPoints[-1].contents = data[i].heading + "\r"; // Use a newline to split the paragraph
story.insertionPoints[-2].appliedParagraphStyle = hdrStyle;
for (var j = 0; j < data[i].content.length; j++)
{
story.insertionPoints[-1].contents = data[i].content[j] + "\r"; // Use a newline to split the paragraph
story.insertionPoints[-2].appliedParagraphStyle = textStyle;
}
}
Note that it's worth here to invert inserting contents and applying formatting. This is so any previous 'temporary' formatting gets cleared; applying a paragraph style this way overrides any and all local overrides. As you have to apply the style to the previous paragraph (the one before the hard return you just inserted), you would use insertionPoints[-2] here.
The advantages of using styles over local formatting are countless. You can apply all formatting you want with a single command, safely remove all local overridden formatting, and change any part of the formatting globally if you are not satisfied with it, rather than having to re-run your script with slightly different settings.

How to replace selected text in InDesign via script?

In my scripted UI panel, I have a button that is supposed to insert some text. I came up with this routine, which, indeed, inserts whatever text wherever I want, but if there is any text already selected, it doesn't replace the selection.
How can I modify this function to replace the selection? If there is nothing selected, it should just insert the text normally.
function insertText(whattext){
if( app.selection.length < 1 ){ exit(); }
var tf = app.selection;
for( var q = 0; q < tf.length; q++ ){
var thisframe = tf[q];
var originaltext = thisframe.contents;
thisframe.contents = originaltext + whattext;
}
}
Hmmm... well, this seems to work pretty well... [embarassed look on face]
function insertText(whattext){
app.selection[0].contents = whattext;
}

Resources