Web clipping script: Safari to Mail, Notes and TextEdit as HTML

This is a short script to help me with web-clipping sort of activities while composing email and notes. I use it mainly with Mail, Notes and sometimes TextEdit to insert page title, link and selection from web pages. Grabbing the selection and pasting is not as perfect as copying it directly from Safari, but still useful.

This is one of my first scripts - please let me know of any glaring errors and also of any improvements.

Thanks.


-- Crude 'web-clipping' script to grab URL, page title and selected text from Safari
-- and insert the info in HTML
-- Written mainly to be used with Mail, Notes and TextEdit (via FastScripts)

-- What it will try to do:
--	Grab info from all the windows and tabs in Safari
--	Present a list selection with multiple selection showing the page titles
--	Paste the information from the selected tabs into the current application (clipboard will be modified)
--		If a single item is selected it is pasted as HTML paragraph
--		Multiple selections are pasted as items of unordered list enclosed in a DIV element
--		Only inline css-styles seem to work with the above mentioned application (other methods didn't work)

-- Code contains snippets gleaned from other postings

-- version 0.1: 2013-Sep-27 Friday: 04:51:33 pm
-- version 0.2: 2013-Nov-14 Thursday: 07:37:42 am
--         Corrected occasional error "Safari got an error: Can't get every tab of window id ..." when extension dialog had been open


set {leftArrow, rightArrow, downArrow, upArrow} to {123, 124, 125, 126}

set jsCode1 to "

function getSelectionHtml() {
    var html = \"\";
    if (typeof window.getSelection != \"undefined\") {
        var sel = window.getSelection();
        if (sel.rangeCount) {
            var container = document.createElement(\"div\");
            for (var i = 0, len = sel.rangeCount; i < len; ++i) {
                container.appendChild(sel.getRangeAt(i).cloneContents());
            }
            html = container.innerHTML;
        }
    } else if (typeof document.selection != \"undefined\") {
        if (document.selection.type == \"Text\") {
            html = document.selection.createRange().htmlText;
        }
    }
    return html;
}

function htmlEncode( html ) {
	
	var myString = document.createElement( 'a' ).appendChild(
	        document.createTextNode( html ) ).parentNode.innerHTML;
	return myString.replace(/\"/g, '\\"').replace(/\\n/g, '\\
').replace(/( )/g,\" \");
};

[document.title, htmlEncode(document.title), window.location.href, getSelectionHtml()]; 
 "

set tabsInfo to {}
set listInfo to {}
set listIndex to 0
set theSelection to {}

set AppleScript's text item delimiters to return

tell application "System Events"
	set foreMostApplication to item 1 of (get name of processes whose frontmost is true)
end tell

tell application "Safari"
	
	set windowsList to (windows whose visible is true) as list
	repeat with currWindow in windowsList
		
		set tabsList to tabs of currWindow as list
		
		repeat with currTab in tabsList
			
			set {unencodedPageTitle, pageTitle, currURL, selectedText} to (do JavaScript jsCode1 in currTab)
			
			set infoText to {unencodedPageTitle, pageTitle, currURL, selectedText} as text
			copy infoText to end of tabsInfo
			set listIndex to listIndex + 1
			copy {unencodedPageTitle, listIndex} as text to the end of listInfo
			
		end repeat -- tabsList
		
	end repeat -- windowsList
	
end tell -- Safari

if length of tabsInfo is equal to 1 then
	set theSelection to tabsInfo
else
	try
		set listOfSelected to (choose from list listInfo ¬
			with title ¬
			"Grab page information (as HTML)" with prompt ¬
			"Select page(s) to grab:" with multiple selections allowed)
	on error number -128 # Cancelled
		return
	end try
	
	set theSelection to {}
	repeat with eachItem in listOfSelected
		set {unencodedPageTitle, listIndex} to paragraphs of eachItem
		copy item listIndex of tabsInfo to the end of theSelection
	end repeat
	
end if


outputHTML(theSelection)

-- Assumes invocation from an application capable of accept pasting
delay 0.25
tell application foreMostApplication
	activate
	delay 0.25
	tell application "System Events"
		keystroke return
		delay 0.25
		key code upArrow
		delay 0.25
		keystroke "v" using command down
		delay 0.25
		key code downArrow
	end tell
end tell


to outputHTML(selectedItems)
	
	set HTMLout to ""
	set pageInfo to ""
	
	repeat with theSelection in selectedItems
		set {unencodedPageTitle, pageTitle, pageURL, selectedText} to text items of theSelection
		set pageInfo to "<em style=\"display:block;\"><a href=\"" & pageURL & "\">" & pageTitle & "</a></em>" & return
		if selectedText is not equal to "" then
			set pageInfo to pageInfo & "<div style=\"padding:8px; border-left: 1px solid #999; margin-bottom: 1em; \">" & selectedText & "</div>" & return
		end if
		
		if (count of selectedItems) > 1 then
			set HTMLout to HTMLout & "<li><p>" & pageInfo & "</p></li>" & return
		else
			set HTMLout to HTMLout & "<p>" & pageInfo & "</p>" & return
		end if
	end repeat
	
	-- Wrap around in a box with unordered list items
	set divStyle to "padding: .5em; margin-bottom: .5em; font-size: 1.2em; font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif;"
	if (count of selectedItems) > 1 then
		set HTMLout to "<ul>" & return & HTMLout & return & "</ul>" & return
		set divStyle to divStyle & " border-style: dotted; border-width: thin; border-color: black;"
	end if
	set HTMLout to "<div style=\"" & divStyle & "\">" & return & HTMLout & return & "</div>"
	set HTMLout to HTMLout -- & return & "<p></p>" -- this helps to place the cursor outside the inserted element
	
	set HTMLout to ¬
		"<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Clipped items</title>
</head>
<body>
" & HTMLout & "
</body>
</html>"
	
	-- set the clipboard to HTMLout
	
	set htmlData to do shell script "echo " & (quoted form of HTMLout) & " | hexdump -ve '1/1 \"%.2x\"'"
	run script "set the clipboard to «data HTML" & htmlData & "»"
	
end outputHTML