I currently have an AppleScript that makes small changes to text boxes in an indesign document. The script goes page by page, and if an applied object style is called a certain name and it contains a certain character, it will apply a paragraph style. Here's an example of my script:
tell application "Adobe InDesign"
repeat with x from 1 to count pages
set ThisPage to page x
tell ThisPage
if exists (text frames whose (name of applied object style is "PriceBox" and contents contains "/$")) then
set myFrames to (text frames whose (name of applied object style is "PriceBox" and contents contains "/$"))
tell myFrames
repeat with r from 1 to count items
set applied paragraph style of paragraphs of item r of myFrames to "2forPrice"
end repeat
end tell
end if
end tell
end repeat
end tell
What this does is it goes to the first page of a document, and if there is a text box that is called "PriceBox" and the text box has the characters "/$" in it, it will change the paragraph style to a named style "2forPrice".
This works great when there is 1 "listing" on each page. I am trying to make this work where there are multiple groups of listings and make the script go to each and every group of boxes separately and run the script. Any way to tell if this can be done by group, rather than by page?
Thank you for your help!!
UPDATE:
Here are the screenshots of what it does, I skipped a few steps to make it work, but I rather use groups of boxes.
Picture1: This is what's considered a "group", I want to put all these boxes in one group.
Picture2: Here is how all the groups are laid out on one page
Picture3: Take a look at the changes to the prices if it's a "2for", for example 2/$6
I want my script to go group by group, instead of page by page, to do the if statement and change the paragraph style. Thanks again for your help!
#Ted: Depending on how well an app’s Apple Event Object Model is implemented, you should be able to do all that in a single command:
tell application "Adobe InDesign"
tell front document
tell pages
tell (text frames whose name of applied object style is "PriceBox" and contents contains "/$")
set applied paragraph style of paragraphs to "2forPrice"
end tell
end tell
end tell
end tell
(Tip: Apple event IPC is RPC + queries, not OOP.)
[ETA] As commenter below notes, this won’t work on grouped text frames, so here’s a recursive variation that will:
to walkGroups(groupRef)
tell application "Adobe InDesign CS6"
tell groupRef
tell (text frames whose name of applied object style is "PriceBox" and contents contains "/$")
if it exists then
set applied paragraph style of paragraphs to "2forPrice"
end if
end tell
repeat with subgroupRef in groups
my walkGroups(subgroupRef)
end repeat
end tell
end tell
end walkGroups
tell application "Adobe InDesign CS6"
my walkGroups(front document)
end tell
I think you can use "page items" of the page. If there is a group, it will count as a page item. You will then have to programmatically inspect each group for text frames.
Eg, if there are 3 text frames and one group of 2 text frames, the text frame count for the page will be 3, but the page items count will be 4 (the three ungrouped text frames plus the one group of 2 text frames.
ONE-LINER / STORY approach
As you can see, searching for text frames by scouring pages, spreads, paste boards, groups, etc. can be difficult. The script API doesn't have a command for "give me all text frames in the layout regardless of where they are".
The workaround here is to use the story object. If you ask InDesign to give you a list of all stories (or text flows) in a layout, you'll get them regardless of where they may exist within the layout.
The example below starts with all stories that are associated with a text frame and then matches only the stories where the text frame's object style is "test". It then applies a paragraph style to the paragraphs of those stories.
tell application "Adobe InDesign CC 2018"
set applied paragraph style of paragraphs of (stories of document 1 whose class of (object reference of item 1 of text containers) is text frame and name of applied object style of item 1 of text containers = "test" and contents contains "/$") to "Body Text"
end tell
IF NESTED TELLS ARE PREFERRED
tell application "Adobe InDesign CC 2018"
tell document 1
tell (stories whose class of (object reference of item 1 of text containers) is text frame and name of applied object style of item 1 of text containers = "test" and contents contains "/$")
set applied paragraph style of paragraphs to "Body Text"
end tell
end tell
end tell
I don't really know how to work InDesign — I have an old copy of it, but it would be nice if you provided an example document that I could download and test — but just in terms of AppleScript you probably want to do something like so:
tell application "Adobe InDesign"
repeat with this_page in pages
tell this_page
set text_frames_list to (text frames whose name of applied object style is "PriceBox" and contents contains "/$")
repeat with a_text_frame in text_frames_list
tell a_text_frame
set applied paragraph style of paragraphs of a_text_frame to "2forPrice"
end tell
end repeat
end tell
end repeat
end tell
Related
I've been trying to get this simple script to work, it's supposed to search for a string, replace it while applying some styling, e.g. setting the text bold and red.
Here's what I have so far:
tell application "Finder"
set fl to files of folder POSIX file "/Users/Sc/Desktop/app/" as alias list
end tell
repeat with f in fl
tell application "TextEdit"
open f
set text of front document to replace_chars(text of front document, "a", "0000") of me
end tell
end repeat
on replace_chars(this_text, search_string, replacement_string)
set AppleScript's text item delimiters to the search_string
set the item_list to every text item of this_text
set the size of replacement_string to 14
set AppleScript's text item delimiters to the replacement_string
set this_text to the item_list as string
set AppleScript's text item delimiters to ""
return this_text
end replace_chars
However this produces an error, I understand why, but not sure how to go about styling it before replacement, any help would be appreciated.
TextEdit uses Cocoa Scripting's standard Text Suite implementation, which is pretty naff at the best of times. If you're doing whole-word replacement, the following should work:
tell application "TextEdit"
set aRef to a reference to (every word of document 1 where it is "OLDWORD")
set aRef's color to {65535, 0, 0}
set aRef's contents to "NEWWORD"
end tell
The same approach should also work for single-character or whole-paragraph replacement; just modify the every word of... query appropriately. In each case though, you must match exactly one word/character/paragraph and replace it with exactly one word/character/paragraph, otherwise you'll get hilarious off-by-N errors throughout subsequent matches[1] due to Cocoa Scripting being made of dumb and incompetent[2] (e.g. try changing a recurring word to two new words, e.g. "foo" -> "boo boo" to see what I mean).
Also, unlike Text Suite implementations found in better written apps, Cocoa Scripting's Text Suite provides no way to describe to text ranges (e.g. text (character i) thru (character j) of.../text i thru j of...), so it's impossible to tell TextEdit to match, say, "oo" in "baboon", "fool", "spitoon", etc. If you need to match arbitrary character ranges, you'll have to get the text into AppleScript and calculate the start and end of each match yourself.
[1] When making multiple replacements, CS's Text Suite first calculates the positions of all of the text ranges that need changed, and then performs each substitution starting at the first match and finishing at the last. Thus, any differences in the length of the new vs old text mean all of the remaining match indexes it already calculated are no longer correct because the characters previously at that position have now shifted to the left or right. To do the job right, CS should've calculated all the positions from first to last, and then replaced them starting at the last and working backwards to the first.
[2] (CocoaScripting.framework was originally designed by Cocoa developers who didn't understand how AppleScript works, and since then has been maintained by AppleScript developers who don't understand either. So it goes.)
TextEdit is not the best tool to search and replace styled text, for example the free TextWrangler has more powerful skills to do that.
Anyway, try this, it affects only one opened document in TextEdit
The "algorithm" is to calculate the offset of the search string, replace it with the replace string and keeps the location in a repeat loop. At the end reassign the changed text to the text object of TextEdit and change the style at the stored locations to {font: Helvetica Bold, size: 24 and color: red}.
property searchString : "a"
property replaceString : "0000"
tell application "TextEdit"
set completed to false
set ranges to {}
set theText to text of front document
set theSize to size of text of front document
repeat while completed is false
tell current application to set o to offset of searchString in theText
if o is 0 then
set completed to true
else
tell theText to set newText to text 1 thru (o - 1) & replaceString & text (o + (length of searchString)) thru -1
set end of ranges to o
copy newText to theText
end if
end repeat
set text of front document to theText
set size of text of front document to theSize
repeat with aRange in ranges
tell characters aRange thru (aRange + (length of replaceString) - 1) of front document
set size to 24
set its color to {65535, 0, 0}
set font to "Helvetica Bold"
end tell
end repeat
end tell
Since the other posters both noted how poorly suited TextEdit is for this task, allow me to make an "out of the box" suggestion: Use MS Word
The Find and Replace tool in Word can easily handle this task, and much more complicated replacements.
If you have a lot of source documents in RTF format, you could open them in Word, make the changes, and save back to the same (or different) RTF file. It would be very easy to create a Word VBA macro to do this.
You could then either write an AppleScript to open each RTF file in Word and run the macro, or you could do all of the processing using a master Word VBA. You could do it in either way, but I would choose the all VBA route since, IMO, it is a much better language for processing MS documents than AppleScript.
Of course, this requires that you have MS Word installed. I'm still running MS Office 2011 on all of my Macs, and don't plan to upgrade to Office 2016 for a while. Word 2011 works very well.
Good luck.
I am writing some text in to word file i want to change the color of that text any one can help on that one plz.
I want to print the 'message' from following script in red color.
Here is the Script:
set message to "mostly these windows are popup in application"
on ResultCreationFuction(message)
try
set text_to_save to message as text
tell application "System Events"
tell application "Finder"
set sortedList to sort (get files of folder "SofTestAutomationResult" of desktop) by modification date
set FileCount to get count of sortedList
set theFile to (item FileCount of sortedList) as alias
end tell
set file_ref to open for access theFile with write permission
write (text_to_save & return) to the file_ref starting at eof
close access file_ref
delay 2
end tell
end try
end ResultCreationFuction
Some Details:
The file is word which is all ready present on above location having name "10.012.2014_17_4_20.doc" (the name of .doc file is not fix)
What you are attempting is the wrong way to do it.
To manipulate content like that, including formatted text (not plain
text), you need to work within, ideally, a well-scriptable app, like
Pages (or Word, perhaps, but I don't have that on the machine I'm
writing this from).
Don't use System Events if you don't need to. Use the apps with the appropriate AppleEvents/dictionary, etc. If you don't know what I'm talking about, you need to take advantage of the infinite resource known as the web.
"Fuction" is just bad form.
I would suggest doing a lot more reading up on how AppleScript works (or scripting in general), but to start you out, here is a script I just wrote in pages which sets the color of a specific word of the open document after putting text in there:
tell application "Pages"
set body text of document 1 to "hello there mister fancy pants"
set color of word 3 of body text of page 1 of document 1 to {64614, 0, 111}
end tell
If you have Pages, try this by starting with a blank page and running this script. Obviously, you could get rid of "word 3 of" in the 2nd line, and the whole body text will be red.
I hope this makes sense and is of help.
[edit]
I should mention that even TextEdit is scriptable and can open Word documents. Here's an example using TextEdit:
tell application "TextEdit"
set text of document 1 to "hello mister fancy pants"
set color of words 2 thru 3 of text of document 1 to {65535, 0, 0}
end tell
There is a little danger of non-Word apps losing formatting of Word files. But it just seems you are attempting something very simple, and I'm not sure if Word is really necessary here.
You can't add color using the write to eof. You should open the document in Word and then insert the line and add the color. Here's a script that should demonstrate how:
set text_to_add to "mostly these windows are popup in application"
set theFile to ((path to desktop folder) & "10.012.2014_17_4_20.doc") as string
tell application "Microsoft Word"
set theFile to theFile as string -- assuming theFile is an alias or :: path
open file theFile
tell active document
set endOfDoc to end of content of text object -- insert the text to end of document
set theRange to create range start (endOfDoc - 1) end endOfDoc
insert text text_to_add at theRange
set myRange to create range start endOfDoc end (endOfDoc + (length of text_to_add))
set color index of font object of myRange to red
save
end tell
end tell
Can anyone help me to get the active list on display in the Reminders app on OS X?
According to the applescript dictionary for reminders, the application has a "default list" property which is "the list currently active in the Reminders application."
However, this property always seems to return the first list in order in the lists sidebar, not the list which is actually being displayed and is active. I have found that if I rearrange the order of the lists in the sidebar, I will always get whichever I have made the first list, regardless of which is actually being viewed and worked with.
My application is to create a Keyboard Maestro trigger to run an AppleScript to print the list I am currently working on, but it does not appear that the Reminders app functions as is documented in its dictionary. (I have temporarily used a workaround of having the script pop up a chooser listing all the lists so I can select the one i want to print, but that's inefficient and inelegant).
Thanks!
Yes, you can, but you will have to use the bad GUI scripting. And in a bad way. Look:
--Do some GUI scripting to get the decription of a specific group
tell application "Reminders" to activate
tell application "System Events"
tell process "Reminders"
tell window "Reminders"
tell splitter group 1
tell group 1
set des to get description
end tell
end tell
end tell
end tell
end tell
--This description is in the format "Viewing MyList, 1 reminder" so get the part to the "," from des.
set text item delimiters to ","
set texitems to text items of des
set firstPart to get text item 1 of texitems
--Setting the delimiters back
set text item delimiters to ""
--Jump to charcter 9 of firstPart then converting to text
set listname to characters 9 thru end of firstPart as text
--Now we know the name of the current list, so do whatever you want:
tell application "Reminders" to get list listname
This works. But only if Reminders is open. And if Apple changes Reminders structure...
The following script, when run in AppleScript Editor returns as text the autoshape type of the objects on the page. However, when run from the applescript menu from within PowerPoint, it returns a script constant instead.
I'm using a more complicated version of this to send properties of the objects to different applications based on what auto shape type it is... tables go one place, placeholders another, and rectangles et al to third. I'm also launching this from within PPT to push out the data, and can't really pull it from any of the other apps, so the AppleScript menu would be where I want it to be.
Can anyone tell me why the same script gives two results?
Thanks,
Alex
tell application "Microsoft PowerPoint"
set currentSlideNumber to slide index of slide range of selection of document window 1
set theSlide to slide currentSlideNumber of active presentation
end tell
getProperty(theSlide)
to getProperty(theSlide)
tell application "Microsoft PowerPoint"
repeat with thisShape in (get every shape of theSlide)
set shapeType to shape type of thisShape
set shapeContent to content of text range of text frame of thisShape
display alert (shapeType as string)
end repeat
end tell
end getProperty
Converting constants (or application properties which standard applescript doesn't understand) to text is tricky. My guess is that when in the powerpoint menu the script understands the constant better and thus you see that.
In any case, I had the same issue with Finder constants and decided to handle the conversion to text myself with an if statement. It's a cumbersome solution because you have to account for every constant but at least you know it will happen properly.
Here's an example. Suppose there is a shape constant of "rect" which stands for a rectangle, and "circ" standing for circle.
NOTE: you can probably use the name of the actual property instead of the constant in the code.
to getProperty(theSlide)
tell application "Microsoft PowerPoint"
repeat with thisShape in (get every shape of theSlide)
set shapeType to shape type of thisShape
if shapeType is <<rect>> then
set shapeTypeText to "rectangle"
else if shapeType is <<circ>> then
set shapeTypeText to "circle"
end if
set shapeContent to content of text range of text frame of thisShape
display alert (shapeTypeText)
end repeat
end tell
end getProperty
AppleScript’s list data type has only a very limited support for boolean test specifiers. Besides picking items by range (with the item keyword), specifying a class will work:
get every «class furl» of {1, "Test", (POSIX file "/posix/path")} --> {file ":hfs:path"}
When the list items are references, dereferencing with the contents keyword will work:
get every «class furl» of {1, "Test", a reference to (POSIX file "/posix/path")} --> {}
get every «class furl» of contents of {1, "Test", a reference to (POSIX file "/posix/path")} --> {file ":hfs:path"}
So why does the following code set allTextAreas to an empty list:
tell application "System Events"
set allUIElements to entire contents of window 1 of someApplication
set allTextAreas to every text area of contents of allUIElements --> {}
end tell
given that allUIElements is a list of references to UI element objects, and that at least one of them is of class text area?
Note I am not looking for suggestions how to retrieve all UI elements of a certain type from the list (a repeat loop will do that) – I would like to understand why the selector pattern fails in this specific case.
Here's how I would do it if I wanted to find all the buttons of the front window in Safari. Just apply this logic to your situation.
tell application "System Events"
tell process "Safari"
set allButtons to UI elements of window 1 whose class is button
end tell
end tell
Getting the UI elements from the application results in a list of object specifiers: application objects (a form of nested containers) where each item in the hierarchy has several properties, including a class – Technical Note TN2106 might shed more light on this –, while your first example used a file URL (a type of file reference) which has a base class.
So you will need to use either an application filter reference form when getting the objects from the application or query the desired properties of the returned objects, for example:
set allButtons to {}
tell application "System Events" to tell application process "Safari"
set allUIElements to entire contents of window 1
repeat with anElement in allUIElements
try
if class of anElement is button then set end of allButtons to contents of anElement
end try
end repeat
end tell
allButtons