I’m trying to loop through a Keynote presentation and move the presenter notes into a Pages document. I’m close, but I have two problems so far. The one I’ve been working on mostly is trying to add pages to the bottom of the Pages document. Right now, every time I add a page or a section, it adds a page after the selected page, and page 1 stays selected. Therefore, my notes are copying in reverse order.
The other problem that I haven’t really explored yet – not sure how to explore it – is how to copy the rich text from the presenter notes and not just the plain text.
Here’s the code that I have so far. I’ve had some tips from a user on another board for the Pages, but I think he’s stuck at the same place I am. There doesn’t seem to be a way to select the last page in the code. I found out that if I put a breakpoint in the code before the Make statement and select the last page manually, then the code would work. If I had a way to set the insertion point at the bottom of the document right before the Make command, then I think it would work.
property defaultTemplateName : "Blank"
property Slide_notes : ""
tell application "Keynote"
set theNumberOfSlides to count of slides in document 1
end tell
tell application "Pages"
activate
set Number_of_pages to count of documents
if Number_of_pages = 0 then
set myDocument to make new document with properties {document template:template defaultTemplateName}
else
set myDocument to document Number_of_pages
end if
end tell
tell application "Keynote"
set myPresentation to document 1
end tell
repeat with Slide_count from 1 to theNumberOfSlides
tell application "Keynote"
tell myPresentation
set mySlide to slide Slide_count
set Slide_notes to (presenter notes of mySlide)
end tell
end tell
tell application "Pages"
tell myDocument
if Slide_count is 1 then
set body text to Slide_notes
else
set newPage to make new page at the end of sections
set body text of newPage to Slide_notes
end if
end tell
end tell
end repeat
It seems to be a bug in Pages rather than anything you’re doing wrong. The only way I can see so far to add pages and put text into the correct ones is to make all the pages first and then populate them. That is, replace your last repeat with these two:
-- Make the required number of additional pages.
repeat theNumberOfSlides - 1 times
tell application "Pages" to tell myDocument to make new page
end repeat
-- Then add the required texts.
repeat with Slide_count from 1 to theNumberOfSlides
tell application "Keynote"
tell myPresentation
set mySlide to slide Slide_count
set Slide_notes to (presenter notes of mySlide)
end tell
end tell
tell application "Pages" to set body text of page Slide_count of myDocument to Slide_notes
end repeat
In broad terms, it’s fairly simple. Get the properties of the each slide’s presenter notes and set the properties of the corresponding page’s body text to the same values:
-- Make the required number of additional pages.
repeat theNumberOfSlides - 1 times
tell application "Pages" to tell myDocument to make new page
end repeat
-- Then add the required texts.
repeat with Slide_count from 1 to theNumberOfSlides
tell application "Keynote"
tell myPresentation
set mySlide to slide Slide_count
set Slide_notes to ({it, font, color, size} of presenter notes of mySlide)
end tell
end tell
tell application "Pages"
tell page Slide_count of myDocument
set {body text, font of body text, color of body text, size of body text} to Slide_notes
end tell
end tell
end repeat
If you want to match style changes within each text, you have to go through character-by-character searching for them. The iWork text suite doesn’t seem to support attribute runs.
I haven’t had to work much with characters and strings – only a couple of scripts a few years ago that I don’t remember. I’ll play with examining and copying characters one at a time. Do you have any samples to go by?
The following’s not very pleasant, but fairly effective. Effects like bold, italic, and underline can only be reproduced where Keynote uses separate fonts for them.
property defaultTemplateName : "Blank"
tell application "Keynote"
set myPresentation to document 1
set theNumberOfSlides to (count myPresentation's slides)
end tell
tell application "Pages"
activate
if ((count documents) is 0) then
set myDocument to (make new document with properties {document template:template defaultTemplateName})
else
set myDocument to back document -- Equivalent to the original 'document Number_of_pages'. Change to 'front document' or 'document 1' if that's what's meant.
end if
-- Make the required number of additional pages. (This script assumes that the document starts with only one page.)
repeat theNumberOfSlides - 1 times
tell myDocument to make new page
end repeat
end tell
-- Then add the required texts.
repeat with slideCount from 1 to theNumberOfSlides
tell application "Keynote"
tell myPresentation
set mySlide to slide slideCount
-- Get the text of the presenter notes and three lists containing respectively the fonts, colours, and sizes of all the text's characters.
tell mySlide's presenter notes to set {noteText, fontList, colourList, sizeList} to {it, font of characters, color of characters, size of characters}
end tell
end tell
-- Initialise an attribute details list to the index and font attributes of the first character.
set previousAttributes to {1, {beginning of fontList, beginning of colourList, beginning of sizeList}}
-- Initialise a collector for pseudo-"attribute runs".
set attributeRuns to {}
-- Work through the attributes for each of the remaining characters in turn.
repeat with c from 2 to (count fontList)
-- Get this character's font, colour, and size.
set theseAttributes to {item c of fontList, item c of colourList, item c of sizeList}
-- If any of them have changed since the previous character …
if (previousAttributes does not end with {theseAttributes}) then
-- … replace the start index in the previousAttributes list with the full text to which those attributes apply …
set item 1 of previousAttributes to text (get beginning of previousAttributes) thru (c - 1) of noteText
-- … store the list in attributeRuns …
set end of attributeRuns to previousAttributes
-- … and start a new previousAttributes list with the current character index and the character's attributes.
set previousAttributes to {c, theseAttributes}
end if
end repeat
-- Finish the attribute run in progress at the end of the repeat.
set item 1 of previousAttributes to text (get beginning of previousAttributes) thru c of noteText
set end of attributeRuns to previousAttributes
tell application "Pages"
tell page slideCount of myDocument
-- The only way I can find to append text directly to Pages 7.1 body text is to set the body text's last character to itself and the additional text.
-- Initialise this page's body text to a space so that it actually contains a last character.
set body text to space
-- Work through the collected "attribute runs" in turn.
repeat with theseAttributes in attributeRuns
-- Get the text, font, colour, and size of this run.
set {txt, fontColourAndSize} to theseAttributes
-- I've not been able to set the attributes of a _range_ of characters in a Pages 7.1 body text.
-- Rather than append the additional text and then set the attributes of each of its characters in turn, this code just appends a space, changes its attributes, and then replaces it with (sets it to) the additional text.
tell body text
set character -1 to character -1 & space
tell character -1 to set {its font, its color, its size} to fontColourAndSize
set character -1 to txt
end tell
end repeat
-- When done, delete the original initialisation space.
set character 1 of body text to ""
end tell
end tell
end repeat
Thanks for the example – I think it would’ve been a long time before I reached this same code. And you’re right, it’s not very elegant.
I have to step back and reconsider how badly I want to move the formatting. I tend to make large-point speaker notes. I was running tests yesterday, and moving the formatted text conflicted with our method of pre-adding pages and then copying each slides’ value separately because the notes on some slides are longer than one page. That returned me to the problem that I would have to add pages to the bottom of the document within the loop that populates the text – which we found to not be possible.
You may create a document for each slide then merge them in a single one.
You will get the pages in the desired order.
An other way would be to use an index specific to the target page.
If the inserted ‘note’ use one page the index will be incremented by one. If it use say 3 pages, the index will be incremented by 3.
Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) jeudi 13 septembre 2018 19:23:54
The solution may be to add ‘sections’ rather than ‘pages’. If a note text is longer than a page, Pages will create extra page(s) within the current, numbered section.
Texts as long as or longer than a page are going to have huge numbers of characters, so I’ve modified the script to reference the list variables and make them non-persistent. It may still hesitate over very long texts, but this is due to the time it takes to Keynote to return all the characters’ properties. The script’s analysis of them is actually pretty fast.
property defaultTemplateName : "Blank"
-- Code in a handler to make the variables local and therefore non-persistent.
on main()
-- Script object to allow references to the list variables, for speed of access to the lists' items.
script o
property fontList : missing value
property colourList : missing value
property sizeList : missing value
property attributeRuns : missing value
end script
tell application "Keynote"
set myPresentation to document 1
set theNumberOfSlides to (count myPresentation's slides)
end tell
tell application "Pages"
activate
if ((count documents) is 0) then
set myDocument to (make new document with properties {document template:template defaultTemplateName})
else
set myDocument to back document -- Equivalent to the original 'document Number_of_pages'. Change to 'front document' or 'document 1' if that's what's meant.
end if
-- Make the required number of additional sections. (This script assumes that the document starts with only one section.)
repeat theNumberOfSlides - 1 times
tell myDocument to make new section
end repeat
end tell
-- Repeat with every slide in the Keynote document.
repeat with slideCount from 1 to theNumberOfSlides
-- Get the presenter notes data from the Keynote slide.
tell application "Keynote"
tell myPresentation
set mySlide to slide slideCount
-- Get the text of the slide's presenter notes and three lists containing respectively the fonts, colours, and sizes of all the text's characters.
tell mySlide's presenter notes
set noteText to it
set {o's fontList, o's colourList, o's sizeList} to {font, color, size} of characters
end tell
end tell
end tell
-- Analyse the data into pseudo-"attribute runs".
set o's attributeRuns to {}
-- Initialise an attribute details list to the index and font attributes of the first character.
set previousAttributes to {1, {beginning of o's fontList, beginning of o's colourList, beginning of o's sizeList}}
-- Work through the attributes for each of the remaining characters in turn.
repeat with c from 2 to (count o's fontList)
-- Get this character's font, colour, and size.
set theseAttributes to {item c of o's fontList, item c of o's colourList, item c of o's sizeList}
-- If any of them have changed since the previous character …
if (previousAttributes does not end with {theseAttributes}) then
-- … replace the start index in the previousAttributes list with the full text to which those attributes apply …
set item 1 of previousAttributes to text (get beginning of previousAttributes) thru (c - 1) of noteText
-- … store the list in attributeRuns …
set end of o's attributeRuns to previousAttributes
-- … and start a new previousAttributes list with the current character index and the character's attributes.
set previousAttributes to {c, theseAttributes}
end if
end repeat
-- Finish the attribute run in progress at the end of the repeat.
set item 1 of previousAttributes to text (get beginning of previousAttributes) thru c of noteText
set end of o's attributeRuns to previousAttributes
-- Insert the data into the relevant section of the Pages document.
tell application "Pages"
tell myDocument
tell section slideCount
-- The only way I can find to append text directly to Pages 7.1 body text is to set the body text's last character to itself and the additional text.
-- Initialise this section's body text to a space so that it actually contains a last character.
set body text to space
-- Work through the collected "attribute runs" in turn.
repeat with theseAttributes in o's attributeRuns
-- Get the text, font, colour, and size of this run.
set {txt, fontColourAndSize} to theseAttributes
-- I've not been able to set the attributes of a _range_ of characters in a Pages 7.1 body text.
-- Rather than append the additional text and then set the attributes of each of its characters in turn, this code just appends a space, changes its attributes, and then replaces it with (sets it to) the additional text.
tell body text
set character -1 to character -1 & space
tell character -1 to set {its font, its color, its size} to fontColourAndSize
set character -1 to txt
end tell
end repeat
-- When done, delete the original initialisation space.
set character 1 of body text to ""
end tell
end tell
end tell
end repeat
end main
main()