Would it be possible to write a script to export comments from Pages?

Hi,

I have a Pages '09 document that I have been asked to make comments on, which I have done. I am wondering if it would be possible to write an applescript to export the comments to another document with just the text that they refer to (i.e. the text highlighted in the main document)?

From an initial look at the applescript dictionary there doesn’t appear to be a way of referring to the comments or the text that they relate to in the main document, but I may be wrong.

Thanks

Nick

Hello

Here is the script posted in the Apple’s Pages forum.
This time, it use do_your_duty as a handler (not a script).


--{code}
--[SCRIPT list_comments]
(*
Enregistrer le script en tant que Script ou Application : list_comments.xxx
déplacer le fichier ainsi créé dans le dossier
<VolumeDeDémarrage>:Users:<votreCompte>:Library:Scripts:Applications:Pages:
Il vous faudra peut-être créer le dossier Pages et peut-être même le dossier Applications.

Ouvrir un document Pages
Aller au menu Scripts , choisir Pages puis choisir  "list_comments"
Le script crée une liste des commentaires insérés dans le document.

--=====

L'aide du Finder explique:
L'Utilitaire AppleScript permet d'activer le Menu des scripts :
Ouvrez l'Utilitaire AppleScript situé dans le dossier Applications/AppleScript.
Cochez la case "Afficher le menu des scripts dans la barre de menus".
Sous 10.6.x,
aller dans le panneau "Général" du dialogue Préférences de l'Éditeur Applescript
puis cocher la case "Afficher le menu des scripts dans la barre des menus".

--=====

Save the script as a Script or an Application : list_comments.xxx

Move the newly created file into the folder:
<startup Volume>:Users:<yourAccount>:Library:Scripts:Applications:Pages:
Maybe you would have to create the folder Pages and even the folder Applications by yourself.

Open a Pages document
Go to the Scripts Menu, choose Pages, then choose "list_comments"
The script builds a list of comments embedded in the document.

--=====

The Finder's Help explains:
To make the Script menu appear:
Open the AppleScript utility located in Applications/AppleScript.
Select the "Show Script Menu in menu bar" checkbox.
Under 10.6.x,
go to the General panel of AppleScript Editor's Preferences dialog box
and check the "Show Script menu in menu bar" option.

--=====

Yvan KOENIG (VALLAURIS, France)

2011/03/14 -- first draft
*)

--=====

on run
	
	--run script do_your_duty
	my do_your_duty()
end run

--=====

--script do_your_duty
on do_your_duty()
	local nom_du_doc, le_rapport
	
	my activateGUIscripting()
	
	tell application "Pages" to tell document 1
		set nom_du_doc to its name
	end tell
	
	set le_rapport to my get_comments()
	
	if le_rapport is not {} then
		set le_rapport to my recolle({nom_du_doc, le_rapport, current date}, return & return)
		
		set myNewDoc to my makeAnIworkDoc("Pages")
		tell application "Pages" to tell document myNewDoc
			set body text to le_rapport
		end tell
	end if
end do_your_duty
--end script

--=====

on parleAnglais()
	local z
	try
		tell application "Pages" to set z to localized string "Cancel"
	on error
		set z to "Cancel"
	end try
	return (z is not "Annuler")
end parleAnglais

--=====

on recolle(l, d)
	local oTIDs, t
	set oTIDs to AppleScript's text item delimiters
	set AppleScript's text item delimiters to d
	set t to l as text
	set AppleScript's text item delimiters to oTIDs
	return t
end recolle

--=====

on activateGUIscripting()
	(* to be sure than GUI scripting will be active *)
	tell application "System Events"
		if not (UI elements enabled) then set (UI elements enabled) to true
	end tell
end activateGUIscripting

--=====

on get_comments()
	local nb_pages, liste_rapport, page_num, les_commentaires, maybe, liste_des_commentaires
	tell application "Pages" to activate
	tell application "System Events" to tell application process "Pages"
		set frontmost to true
		tell (first UI element whose role is "AXLayoutArea") of last scroll area of first splitter group of window 1
			set nb_pages to count group
			set liste_rapport to {}
			repeat with page_num from 1 to nb_pages
				tell group page_num
					set les_commentaires to (a reference to (UI elements whose description is "figure"))
					set maybe to count of les_commentaires
					set liste_des_commentaires to {}
					if maybe > 0 then
						copy "page #" & page_num to end of liste_rapport
						repeat with i from 1 to maybe
							copy "comment #" & i & return & (value of first text area of item i of les_commentaires) to end of liste_rapport
						end repeat
					end if -- maybe > 0
				end tell -- group page_num
			end repeat
		end tell -- layout
	end tell -- System Events
	return liste_rapport
end get_comments

--=====
(*
Creates a new iWork document from the Blank template and returns its name.
example:
set myNewDoc to my makeAnIworkDoc(theApp)
 *)
on makeAnIworkDoc(the_app)
	local maybe, path_to_the_App, nb_doc, doc_name
	if the_app is "Pages" then
		tell application "Pages"
			set nb_doc to count of documents
			make new document with properties {template name:item 1 of templates}
		end tell
	else if the_app is "Pages" then
		tell application "System Events" to set maybe to the_app is in title of every application process
		if not maybe then tell application theApp to activate
		tell application "System Events"
			set path_to_the_App to get application file of application process the_app
		end tell
		tell application "Pages"
			set nb_doc to count of documents
			open ((path_to_the_App as text) & "Contents:Resources:Templates:Blank.nmbtemplate:")
		end tell
	else
		if my parleAnglais(theApp) then
			error "The application "" & the_app & "" is not accepted !"
		else
			error "l'application « " & the_app & " » n'est pas gérée !"
		end if
	end if
	
	tell application the_app
		repeat until (count of documents) > nb_doc
			delay 0.1
		end repeat
		set doc_name to name of document 1
	end tell -- the_App
	return doc_name
end makeAnIworkDoc

--=====
--[/SCRIPT]
--{code}

Yvan KOENIG (VALLAURIS, France) lundi 14 mars 2011 21:18:45

Here is an enhanced version which, when the doc is a word Processing one, return also the contents of the commented paragraphs.


--{code}
--[SCRIPT list_comments]
(*
Enregistrer le script en tant que Script ou Application : list_comments.xxx
déplacer le fichier ainsi créé dans le dossier
<VolumeDeDémarrage>:Users:<votreCompte>:Library:Scripts:Applications:Pages:
Il vous faudra peut-être créer le dossier Pages et peut-être même le dossier Applications.

Ouvrir un document Pages
Aller au menu Scripts , choisir Pages puis choisir  "list_comments"
Le script crée une liste des commentaires insérés dans le document.

--=====

L'aide du Finder explique:
L'Utilitaire AppleScript permet d'activer le Menu des scripts :
Ouvrez l'Utilitaire AppleScript situé dans le dossier Applications/AppleScript.
Cochez la case "Afficher le menu des scripts dans la barre de menus".
Sous 10.6.x,
aller dans le panneau "Général" du dialogue Préférences de l'Éditeur Applescript
puis cocher la case "Afficher le menu des scripts dans la barre des menus".

--=====

Save the script as a Script or an Application : list_comments.xxx

Move the newly created file into the folder:
<startup Volume>:Users:<yourAccount>:Library:Scripts:Applications:Pages:
Maybe you would have to create the folder Pages and even the folder Applications by yourself.

Open a Pages document
Go to the Scripts Menu, choose Pages, then choose "list_comments"
The script builds a list of comments embedded in the document.

--=====

The Finder's Help explains:
To make the Script menu appear:
Open the AppleScript utility located in Applications/AppleScript.
Select the "Show Script Menu in menu bar" checkbox.
Under 10.6.x,
go to the General panel of AppleScript Editor's Preferences dialog box
and check the "Show Script menu in menu bar" option.

--=====

Yvan KOENIG (VALLAURIS, France)

2011/03/14 -- first draft
2011/03/15 -- added close_palettes handler
			changed the test extracting the comments. 
			I asked for Description = "Figure" but this value is localized. In English it's "shape". 
			Alas I don't know the file in which it's defined.
			So, I no longer extract this way. Now I use an awful but safe request.
2011/03/16 -- Extract the text of commented paragraphs
2011/03/20 -- Found a way to get the localized string "shape" so re-introduced a cleaner test.
*)

property shape_loc : missing value
property viewScale : missing value

--=====

on run
	
	--run script do_your_duty
	my do_your_duty()
	(* 
Clear two  properties
*)
	--set viewScale to missing value
end run

--=====

--script do_your_duty
on do_your_duty()
	(* viewScale is a global property *)
	local racine_du_nom_de_forme, nb_documents, nom_du_document, corps_du_texte, dLeft, dTop, dRight
	local dBottom, newLeft, newTop, Xleft, Ytop, xRight, yBottom, oWidth, oHeight, newHeight, topTruePage
	local nb_de_paragraphes, le_rapport, premier_paragraphe, dernier_paragraphe, page_index, un_para, maybe
	local page_number, commentaires_de_la_page, prems, commentaire, comment_loc, nom_forme, vPos, cible
	
	my activateGUIscripting()
	set shape_loc to my getLocalizedDrawablesFrameWorksName("Pages", "shape")
	
	tell application "Pages" to tell document 1 to set {nom_du_document, corps_du_texte} to {name, body text}
	(*
As one or several inspector(s) may be open, close it (them).
*)
	my close_palettes()
	
	if corps_du_texte is missing value then
		(*
Here if the doc is a Layout one *)
		set le_rapport to my get_comments()
		if le_rapport is not {} then
			tell application "Pages" to tell document (my makeAnIworkDoc("Pages"))
				set body text to my recolle({nom_du_document, le_rapport, current date}, return & return)
			end tell
		end if
	else
		(*
Here if the doc is a Word Processing one *)
		set racine_du_nom_de_forme to "rectangle_elgnatcer"
		tell application (path to frontmost application as text)
			if my parleAnglais() then
				display dialog "Don't touch the mouse or the keyboard until the end of the process." giving up after 120
			else
				display dialog "Ne pas toucher la souris ou le clavier avant la fin de l'opération." giving up after 120
			end if
		end tell -- application (path to frontmost application as text).
		(*
Resize the Pages window
*)
		tell application "Finder" to set {dLeft, dTop, dRight, dBottom} to bounds of window of desktop
		set {newLeft, newTop} to {5, 25}
		set newHeight to dBottom - newTop
		
		tell application "Pages" to tell window nom_du_document
			set {Xleft, Ytop, xRight, yBottom} to bounds
			set {oWidth, oHeight} to {xRight - Xleft, yBottom - Ytop}
			set bounds to {newLeft, newTop, newLeft + newHeight, newTop + newHeight}
		end tell -- Pages.
		
		(*
Applying "Fit Page" make the task really easier
*)
		my selectSubMenu("Pages", 8, 13, 5) (* View > Zoom > Fit Page *)
		
		tell application "Pages" to tell document nom_du_document
			(*
Grabs the view scale to calculate the true vertical locations.
*)
			tell its window to set viewScale to view scale / 100
			
			set topTruePage to my get_page_top()
			set nb_de_paragraphes to count of paragraphs
			set le_rapport to {nom_du_document}
			set {premier_paragraphe, dernier_paragraphe} to {1, 1}
			(*
Init the loop upon pages ==========================================
*)
			repeat with page_index from 1 to count pages
				(*
Bring the current page in the visible area
*)
				reveal page page_index
				(*
Loop defining the index of the last paragraph in the page 
*)
				set un_para to premier_paragraphe
				repeat
					set page_number to page number of (get containing page of paragraph un_para)
					if page_number > page_index then
						set dernier_paragraphe to un_para - 1
						exit repeat
					else
						set un_para to un_para + 1
						if un_para > nb_de_paragraphes then exit repeat
					end if
				end repeat
				tell page page_index
					set commentaires_de_la_page to {}
					try
						set commentaires_de_la_page to my get_contents_infos(page_index)
					end try
				end tell
				if commentaires_de_la_page is not {} then
					set prems to true
					repeat with commentaire from 1 to count of commentaires_de_la_page
						set comment_loc to item 2 of (item commentaire of commentaires_de_la_page)
						set un_para to premier_paragraphe
						repeat
							set nom_forme to racine_du_nom_de_forme & un_para
							tell body text to make new shape at before character 1 of paragraph un_para with properties {shape type:rectangle, name:nom_forme, height:5, width:1}
							set vPos to vertical position of shape nom_forme
							delete shape nom_forme
							
							if (topTruePage + (vPos * viewScale)) < comment_loc then
								set un_para to un_para + 1
							else
								if prems then copy "----- page #" & page_index & " -----" to end of le_rapport
								set prems to false
								set cible to contents of paragraph (un_para - 1)
								if (count of cible) = 1 then
									set cible to ""
								else
									set cible to text 1 thru -2 of cible
								end if
								copy "« " & cible & " »" to end of le_rapport
								copy "--> " & item 1 of (item commentaire of commentaires_de_la_page) to end of le_rapport
								exit repeat
							end if
						end repeat -- un_para
					end repeat -- with commentaire.
				end if -- if commentaires_de_la_page
				set premier_paragraphe to dernier_paragraphe + 1
			end repeat -- loop to next page if there is one
		end tell -- Pages.
		
		set shape_loc to missing value
		set viewScale to missing value
		
		if le_rapport is not {nom_du_document} then
			tell application "Pages" to tell document (my makeAnIworkDoc("Pages"))
				set body text to my recolle(le_rapport, return & return)
			end tell
		end if -- le_rapport is not.
	end if
end do_your_duty
--end script

--=====

on parleAnglais()
	local z
	try
		tell application "Pages" to set z to localized string "Cancel"
	on error
		set z to "Cancel"
	end try
	return (z is not "Annuler")
end parleAnglais

--=====

on decoupe(t, d)
	local oTIDs, l
	set oTIDs to AppleScript's text item delimiters
	set AppleScript's text item delimiters to d
	set l to text items of t
	set AppleScript's text item delimiters to oTIDs
	return l
end decoupe

--=====

on recolle(l, d)
	local oTIDs, t
	set oTIDs to AppleScript's text item delimiters
	set AppleScript's text item delimiters to d
	set t to l as text
	set AppleScript's text item delimiters to oTIDs
	return t
end recolle

--=====
(*
Creates a new iWork document from the Blank template and returns its name.
example:
set myNewDoc to my makeAnIworkDoc(theApp)
 *)
on makeAnIworkDoc(the_app)
	local maybe, path_to_the_App, nb_doc, nom_du_document
	if the_app is "Pages" then
		tell application "Pages"
			set nb_doc to count of documents
			make new document with properties {template name:item 1 of templates}
		end tell
	else if the_app is "Pages" then
		tell application "System Events" to set maybe to the_app is in title of every application process
		if not maybe then tell application theApp to activate
		tell application "System Events"
			set path_to_the_App to get application file of application process the_app
		end tell
		tell application "Pages"
			set nb_doc to count of documents
			open ((path_to_the_App as text) & "Contents:Resources:Templates:Blank.nmbtemplate:")
		end tell
	else
		if my parleAnglais(theApp) then
			error "The application "" & the_app & "" is not accepted !"
		else
			error "l'application « " & the_app & " » n'est pas gérée !"
		end if
	end if
	
	tell application the_app
		repeat until (count of documents) > nb_doc
			delay 0.1
		end repeat
		set nom_du_document to name of document 1
	end tell -- the_App
	return nom_du_document
end makeAnIworkDoc

--=====

on activateGUIscripting()
	(* to be sure than GUI scripting will be active *)
	tell application "System Events"
		if not (UI elements enabled) then set (UI elements enabled) to true
	end tell
end activateGUIscripting

--=====

on get_contents_infos(page_num)
	local liste_rapport, les_commentaires, nb_commentaires, i, x, y, w, h
	(* viewScale is a global property *)
	set liste_rapport to {}
	tell application "Pages" to activate
	tell application "System Events" to tell application process "Pages"
		set frontmost to true
		tell (first UI element whose role is "AXLayoutArea") of last scroll area of first splitter group of window 1
			tell group page_num
				set les_commentaires to (a reference to (UI elements where role is "AXLayoutItem" and description is shape_loc))
				set nb_commentaires to count of les_commentaires
				if nb_commentaires > 0 then
					repeat with i from 1 to nb_commentaires
						tell item i of les_commentaires
							set {x, y} to position
							set {w, h} to size
							set comment_value to value of first text area
						end tell
						(*
CAUTION, the grabbed size values are absolute ones, must apply the view scale to match the displayed ones
*)
						copy {comment_value, y + (h * viewScale / 2)} to end of liste_rapport
					end repeat -- i
				end if -- nb_commentaires > 0	
			end tell -- image
		end tell -- layout
	end tell -- System Events
	
	return liste_rapport
end get_contents_infos

--=====

on close_palettes()
	local w, buttonX, buttonY, buttonW, buttonH
	
	tell application "Pages" to activate
	tell application "System Events" to tell application process "Pages"
		set frontmost to true
		repeat with w from (count of windows) to 1 by -1
			tell window w
				if (subrole is not "AXStandardWindow") then
					tell first button to set {{buttonX, buttonY}, {buttonW, buttonH}} to {position, size}
					click button 1 at {buttonX + (buttonW div 2), buttonY + (buttonH div 2)}
				end if
			end tell
		end repeat
	end tell
end close_palettes

--=====

on get_page_top()
	local ScrollV_left, ScrollV_top, HR_left, HR_top, VR_left, VR_top, Y_top
	
	tell application "Pages" to activate
	tell application "System Events" to tell application process "Pages"
		set frontmost to true
		tell last scroll area of first splitter group of window 1
			(*
Grab some vertical scroll bar's properties *)
			tell scroll bar 2 to set {ScrollV_left, ScrollV_top} to get position
			try
				(*
Try to grab some properties of horizontal ruler *)
				tell (first UI element whose role is "AXRuler") to set {HR_left, HR_top} to get position
				try
					(*
Try to grab some properties of vertical ruler *)
					tell (last UI element whose role is "AXRuler") to set {VR_left, VR_top} to get position
				on error
					(*
Exist horizontal ruler but no vertical one *)
					set {VR_left, VR_top} to {0, 0}
				end try
			on error
				(*
No ruler at all *)
				set {HR_left, HR_top} to {0, 0}
			end try
			
			if {HR_left, HR_top} = {0, 0} then
				(*
No horizontal ruler, full page top edge is the vertical scroll bar top one *)
				set Y_top to ScrollV_top
			else
				(*
full page top edge is the vertical ruler top one *)
				set Y_top to VR_top
			end if
		end tell -- layout
	end tell -- System Events
	return Y_top
end get_page_top

--=====
(*
Requires :
decoupe()
*)
on get_iWorkNum(a)
	local verNum
	tell application a to set verNum to item 1 of my decoupe(get version, ".")
	if (a is "Numbers" and verNum is "2") or (a is "Pages" and verNum is "4") then
		return "09"
	else
		return "11"
	end if
end get_iWorkNum

--=====
(*
Example
set shape_loc to my getLocalizedDrawablesFrameWorksName("Pages", "shape")

Requires :
decoupe()
get_iWorkNum()
getLocalizedName()
*)
on getLocalizedDrawablesFrameWorksName(theApp, x)
	local p2bndl
	set p2bndl to (path to application support as text) & "iWork '" & my get_iWorkNum(theApp) & ":Frameworks:SFDrawables.framework:Versions:A:Resources:"
	return my getLocalizedName(theApp, x, p2bndl)
end getLocalizedDrawablesFrameWorksName

--=====

on getLocalizedName(a, x, f)
	tell application a to return localized string x from table "Localizable" in bundle file f
end getLocalizedName

--=====
(*
my selectSubMenu("Pages", 8, 13, 5) (* View > Zoom > Fit Page *)
==== Uses GUIscripting ====
*)
on selectSubMenu(theApp, mt, mi, ms)
	tell application theApp to activate
	tell application "System Events" to tell process theApp to tell menu bar 1 to ¬
		tell menu bar item mt to tell menu 1 to tell menu item mi to tell menu 1 to click menu item ms
end selectSubMenu

--=====
(*
useful to get the indexs of the triggered item
my select_SubMenu("Pages", 8, 13, 5) (* View > Zoom > Fit Page *)
*)
on select_SubMenu(theApp, mt, mi, ms)
	
	tell application theApp to activate
	tell application "System Events" to tell process theApp to tell menu bar 1
		get name of menu bar items
		(*{
01 - "Apple", 
02 - "Pages", 
03 - "Fichier", 
04 - "Édition", 
05 - "Insertion", 
06 - "Format", 
07 - "Disposition", 
08 - "Présentation",	<--
09 - "Fenêtre", 
10 - "Partage", 
11 - "Aide"}
*)
		get name of menu bar item mt
		-- {"Tableau"}
		tell menu bar item mt to tell menu 1
			get name of menu items
			(* 
01 - "Vignettes de page", 
02 - "Rechercher", 
03 - missing value, 
04 - "Afficher le tiroir des styles", 
05 - "Masquer les règles", 
06 - "Masquer la barre des formats", 
07 - "Afficher les commentaires", 
08 - missing value, 
09 - "Afficher la mise en page", 
10 - "Masquer les caractères invisibles", 
11 - "Afficher la structure du document", 
12 - missing value, 
13 - "Zoom",		<--
14 - missing value, 
15 - "Afficher l'inspecteur", 
16 - "Nouvel inspecteur", 
17 - missing value, 
18 - "Afficher les couleurs", 
19 - "Afficher Ajuster l'image", 
20 - "Afficher le navigateur multimédia", 
21 - "Afficher les avertissements du document", 
22 - missing value, 
23 - "Activer le mode plein écran", 
24 - missing value, 
25 - "Masquer la barre d'outils", 
26 - "Personnaliser la barre d'outils."
*)
			get name of menu item mi
			--"Rangs de bas de tableau"
			tell menu item mi to tell menu 1
				get name of menu items
				(* {
1 - "Zoom avant", 
2 - "Zoom arrière", 
3 - "Taille réelle", 
4 - "Ajuster la largeur", 
5 - "Ajuster la page"	<--	}
*)
				get name of menu item ms
				click menu item ms
			end tell -- menu item mi
		end tell -- menu bar item mt
	end tell -- System Events.
end select_SubMenu

--=====

on get_comments()
	local nb_pages, liste_rapport, page_num, les_commentaires, maybe, liste_des_commentaires
	tell application "Pages" to activate
	tell application "System Events" to tell application process "Pages"
		set frontmost to true
		tell (first UI element whose role is "AXLayoutArea") of last scroll area of first splitter group of window 1
			set nb_pages to count group
			set liste_rapport to {}
			repeat with page_num from 1 to nb_pages
				tell group page_num
					(* the awful request *)
					set les_commentaires to (a reference to (UI elements where role is "AXLayoutItem" and description is not "text box" and description is accessibility description))
					set maybe to count of les_commentaires
					set liste_des_commentaires to {}
					if maybe > 0 then
						copy "page #" & page_num to end of liste_rapport
						repeat with i from 1 to maybe
							copy "comment #" & i & return & (value of first text area of item i of les_commentaires) to end of liste_rapport
						end repeat
					end if -- maybe > 0
				end tell -- group page_num
			end repeat
		end tell -- layout
	end tell -- System Events
	return liste_rapport
end get_comments

--=====
--[/SCRIPT]
--{code}

Yvan KOENIG (VALLAURIS, France) dimanche 20 mars 2011 15:56:15