Saturday, July 21, 2018

#1 2013-03-23 09:28:24 pm

murkie
Member
Registered: 2013-03-23
Posts: 4

Safari Tabs Window

Hi,

I'd like to make a window for Safari like Chrome's "Task Manager" - a window listing All tabs in All windows, so you could jump to any one at a click. Here's my first attempt (which gets the -10000 event handler error)
[code]try
    tell application "Safari"
        activate
        --        set numWindows to count windows
        --        set numTabs to 0
        --        set tabName[]
       
        set tabsList to {}
        set windowList to every window
       
        set pageContent to "<html><body>" & linefeed
        repeat with thisWindow in windowList
            set myName to the name of thisWindow
            if myName is not "" then
                set myTabs to every tab of thisWindow
                copy myTabs to the end of tabsList
                set numTabs to count of myTabs
                -- display dialog "There are " & numTabs & " tabs in window " & name of thisWindow buttons {"OK"} default button {"OK"}
                repeat with thisTab in myTabs
                    set tabName to the name of thisTab
                    set tabURL to the URL of thisTab
                    set pageContent to (pageContent & "<a href=" & (tabURL as text) & ">" & tabName & "</a><br>" & linefeed)
                end repeat
            end if
        end repeat
        set pageContent to (pageContent & "</body></html>")
        -- set numTabs to count of tabsList
        -- display dialog "There are " & numTabs & " tabs in Safari " buttons {"OK"} ¬
        --    default button {"OK"}
        try
            make new document at end of documents with properties {name:"Safari Tabs", source:pageContent}
        on error error_message
            activate
            display dialog error_message buttons {"OK"} default button 1
        end try
    end tell
on error error_message
    activate
    display dialog error_message buttons {"OK"} default button 1
end try[/code]


Filed under: Safari Tabs

Offline

 

#2 2013-03-24 12:40:05 am

McUsrII
Member
Registered: 2012-11-21
Posts: 3046
Website

Re: Safari Tabs Window

Hello.

Have a look at this. You'll get a list of all tabs if you don't enter any search string, regular expressions is allowed, and it searches both the url, and the tabname, fast, thanks to Nigel Garvey. It even tells you that the tab is in another space.

Caveat: Not idiot proof, it fails if the downloads window is in front, or you have no windows open in Safari.


Filed under: safari

Offline

 

#3 2013-03-30 01:42:23 am

murkie
Member
Registered: 2013-03-23
Posts: 4

Re: Safari Tabs Window

Well, McUsrII, I appreciate your suggestion. But it might be more helpful to understand why my approach is failing and how to make it work.

Offline

 

#4 2013-03-30 02:17:11 am

StefanK
Member
From:: St. Gallen, Switzerland
Registered: 2006-10-21
Posts: 11499
Website

Re: Safari Tabs Window

The error occurs because the source property is read only


regards

Stefan

Offline

 

#5 2013-03-30 06:27:47 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4604

Re: Safari Tabs Window

Hi murkie. Welcome to MacScripter.

I also get an error from your script which is caused trying to get the tabs of an invisible, tabless "Bookmarks" window which Safari appears to have. I've coded round this in the adaptation of your script below.

As a work-round to the 'new document' problem, you could write your HTML to a temporary file and have Safari open the file. This works for me, but it may be because my Safari preferences are set to open things in new tabs.

Unfortunately, clicking the links shown in the new tab opens yet more tabs instead of going to the existing ones. You may be able to achieve what you want by writing the links in "applescript" protocol instead of "http" and using them to trigger another, suitably set-up script (or more code in the same script) which makes Safari switch to the existing tabs instead of connecting to the remote sites again. I've never tried this myself, but there's a tutorial here if you fancy it as a project.

MacScripter's BBCode has [applescript] and [/applescript] tags which you can put round your script code when posting it to make it appear as below. It's considered good practice to use these. The "Open this Scriplet in your Editor:" link in the resulting script display uses the "applescript" protocol I mentioned above to open the script in your default script editor. (This is already set up. You don't need to do anything special in this case.)

The correct forum here for posting queries about AppleScript code is AppleScript | Mac OS X. "Code Exchange" is for sharing working code or techniques which you think may be useful to others.

Applescript:

try
   tell application "Safari"
       activate
       -- set numWindows to count windows
       -- set numTabs to 0
       -- set tabName[]
       
       set tabsList to {}
       set windowList to windows where its document is not missing value -- 'its' or 'of it' necessary to avoid confusion with the 'document' class.
       
       set pageContent to "<html><body>" & linefeed
       repeat with thisWindow in windowList
           set myName to the name of thisWindow
           if myName is not "" then
               set myTabs to every tab of thisWindow
               copy myTabs to the end of tabsList
               set numTabs to count of myTabs
               -- display dialog "There are " & numTabs & " tabs in window " & name of thisWindow buttons {"OK"} default button {"OK"}
               repeat with thisTab in myTabs
                   set tabName to the name of thisTab
                   set tabURL to the URL of thisTab
                   set pageContent to (pageContent & "<a href=" & (tabURL as text) & ">" & tabName & "</a><br>" & linefeed)
               end repeat
           end if
       end repeat
       set pageContent to (pageContent & "</body></html>")
       
       -- Write the HTML to a temporary file.
       set tempFilePath to (path to temporary items as text) & "Safari Tabs.html"
       set accessRef to (open for access file tempFilePath with write permission)
       try
           set eof accessRef to 0
           write pageContent to accessRef
       end try
       close access accessRef
       
       -- Open the file in Safari.
       open file tempFilePath
       
       -- set numTabs to count of tabsList
       -- display dialog "There are " & numTabs & " tabs in Safari " buttons {"OK"} ¬
       -- default button {"OK"}
   end tell
on error error_message
   activate
   display dialog error_message buttons {"OK"} default button 1
end try


NG

Offline

 

#6 2013-03-31 05:56:35 pm

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4604

Re: Safari Tabs Window

I wrote:

Unfortunately, clicking the links shown in the new tab opens yet more tabs instead of going to the existing ones. You may be able to achieve what you want by writing the links in "applescript" protocol instead of "http" and using them to trigger another, suitably set-up script (or more code in the same script) which makes Safari switch to the existing tabs instead of connecting to the remote sites again. I've never tried this myself, but there's a tutorial here if you fancy it as a project


Well. I thought it was interesting enough to make it a weekend project of my own. Here in the spirit of Code Exchange is what I got.

It turns out that the "applescript" protocol I mentioned is already claimed by the default AppleScript editor on one's computer, so you have to invent your own. The script below periodically scans the tabs in all suitable Safari windows and creates an HTML page in the same way as murkie's script. However, the URLs in it are of the "safaritabchooser:" protocol, which I've invented. Its form is:

safaritabchooser://com.murkie.SafariTabChooser?windowid=<ID>&taburl=<URL>


… where <ID> and <URL> should be replaced by respectively a Safari window ID and the URL of a page displayed in a tab of that window. I used murkie's name in the bundle identifier as it's unique on my machine. Professional developers will no doubt want to use their own personal identifiers.

The 'open location' handler in the script receives a URL from the operating system when a "safaritabchooser:" link is clicked and it tells Safari to display the relevant tab. For the script to receive these URLs, it has to claim the "safaritabchooser:" protocol, and this is arranged by adding details to the Info.plist file in its bundle's "Contents" folder.

So first save the script as a stay-open application. The script code can be altered later if necessary, but the initial creation of the applet must be in the final form. If it's resaved as stay-open when it originally wasn't, the edits about to made in its Info.plist file will be lost.

Applescript:

-- This is two scripts in one applet.
-- The 'idle' handler calls the 'updateTabBookmarks()' handler, which creates and/or updates a "Tab Bookmarks" window in Safari.
-- The 'open location' handler receives a URL from the system when one of the custom-protocol links in the window is clicked. It analyses the URL and tells Safari to display the relevant tab.

-- The script should be saved as a stay-open application and then its "Info.plist" file edited as described elsewhere to set up its custom "safaritabchooser:" URL protocol.

-- Based on a script idea by "murkie" <[url]http://macscripter.net/viewtopic.php?pid=161636#p161636[/url]>
------------------------------------------

-- CREATE OR UPDATE A "TAB BOOKMARKS" WINDOW.

on idle
   -- If Safari's open, check the tabs in all its applicable windows and create or update a "Tab Bookmarks" window accordingly. Idle for ten seconds between rounds.
   -- Otherwise idle for two minutes between tests for Safari being open.
   
   tell application "System Events" to set SafariOpen to (application process "Safari" exists)
   
   if (SafariOpen) then
       updateTabBookmarks()
       return 10
   else
       return 2 * minutes
   end if
end idle

on updateTabBookmarks()
   set tabBookmarkWindowName to "Tab Bookmarks"
   -- The HTML for the "Tab Bookmarks" window can't be inserted directly into Safari and will have to be saved to a temporary file.
   set tempFilePath to (path to temporary items as text) & tabBookmarkWindowName & ".html"
   
   -- We'll use a unique HTML comment for positive identification of the "Tab Bookmarks" tab when updating.
   set tabBookmarkHTMLComment to "<!--- MURKIE'S TAB BOOKMARKS --->"
   
   try
       -- Get the names and URLs of all Safari's existing tabs and the IDs of its windows. Unsuitable windows without tabs will be ignored below.
       tell application "Safari" to set {{tabNames, tabURLs}, windowIDs} to {{name, URL} of tabs, id} of windows
       
       -- Build a simple HTML page source containing clickable links to the tabs with URLs in our custom protocol. The links are grouped by window and the Tab Bookmark tab itself is not included. The urls are in the form:
       -- safaritabchooser://com.murkie.SafariTabChooser?windowid=<ID>&taburl=<URL>.
       set pageContent to "<html><head><title>" & tabBookmarkWindowName & "</title><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /></head><body>" & linefeed & tabBookmarkHTMLComment & linefeed
       set tabBookmarksExist to false
       repeat with i from 1 to (count tabNames)
           set theseTabNames to item i of tabNames
           if (theseTabNames is not {}) then
               set theseTabURLs to item i of tabURLs
               set thisWindowID to item i of windowIDs
               repeat with j from 1 to (count theseTabNames)
                   set notTabBookmarkTab to true
                   set thisTabName to item j of theseTabNames
                   if (thisTabName is tabBookmarkWindowName) then
                       set tabBookmarkTabURL to item j of theseTabURLs
                       set tabBookmarkWindowID to thisWindowID
                       tell application "Safari" to set thisTabSource to (source of first tab of window id tabBookmarkWindowID whose URL is tabBookmarkTabURL)
                       set tabBookmarksExist to (paragraph 2 of thisTabSource is tabBookmarkHTMLComment)
                       set notTabBookmarkTab to (not tabBookmarksExist)
                   end if
                   if (notTabBookmarkTab) then
                       set pageContent to pageContent & "<a href=safaritabchooser://com.murkie.SafariTabChooser?windowid=" & thisWindowID & "&taburl=" & item j of theseTabURLs & ">" & thisTabName & "</a><br>" & linefeed
                   end if
               end repeat
               if ((notTabBookmarkTab) or (j > 1)) then set pageContent to pageContent & "<br>" & linefeed
           end if
       end repeat
       set pageContent to (pageContent & "</body></html>")
       
       -- Write the HTML to a temporary file.
       set accessRef to (open for access file tempFilePath with write permission)
       try
           set eof accessRef to 0
           write pageContent as «class utf8» to accessRef
       end try
       close access accessRef
       
       -- Get the file's URL and open it in Safari — in the existing Tab Bookmarks window if there is one; in a new one if not.
       tell application "System Events" to set u to URL of disk item tempFilePath
       
       tell application "Safari"
           if (tabBookmarksExist) then
               set URL of (first tab of window id tabBookmarkWindowID whose URL is tabBookmarkTabURL) to u
           else
               make new document with properties {URL:u}
               set bounds of window 1 to {1125, 180, 1440, 800} -- Adjust as required.
           end if
       end tell
   on error error_message
       displayError(error_message)
   end try
end updateTabBookmarks


-- HANDLE THE URL ISSUED WHEN A TAB BOOKMARK IS CLICKED.

on open location this_url
   -- Handle a URL with our custom protocol, passed to the script by the system.
   -- Parse it for the window ID and tab URL and get Safari to act accordingly.
   -- As a reminder, the form of the URL is:
   -- safaritabchooser://com.murkie.SafariTabChooser?windowid=<ID>&taburl=<URL>.
   
   -- It's assumed the ID will come before the URL, but the code can cope with the URL not being given should it ever be decided to add the facility just to bring a window to the front without going to a particular tab.
   
   try
       set c to (offset of "&taburl=" in this_url)
       if (c > 0) then
           set tabURL to text (c + 8) thru -1 of this_url
       else
           set tabURL to missing value
       end if
       set windowID to (text ((offset of "?windowid=" in this_url) + 10) thru (c - 1) of this_url) as integer
       
       tell application "Safari"
           activate
           tell window id windowID
               if (it exists) then
                   -- AppleScript can only focus a Safari 5.1.8 window by flicking its visibility off and on again, which looks bad. The JavaScript focus() function smoothly focuses both window and tab, but only if the tab's been in focus before! The trick appears to be to use JavaScript to focus the window in the current tab and then switch tabs with AppleScript.
                   do JavaScript "window.focus()" in current tab
                   if ((tabURL is not missing value) and (URL of tabs contains tabURL)) then set current tab to first tab whose URL is tabURL
               end if
           end tell
       end tell
   on error error_message
       displayError(error_message)
   end try
end open location


on displayError(msg)
   tell application (path to frontmost application as text)
       display dialog msg buttons {"OK"} default button 1 with title "Safari Tab Chooser" with icon caution
   end tell
end displayError

Ignore the "Bundle Contents" button in AppleScript Editor. Instead, control-click the applet file wherever it's been saved and select "Show Package Contents" from the contextual menu. A window should appear showing the Contents folder. In this is the Info.plist file, which should be opened in a plain text editor like TextWrangler or possibly TextEdit.

Here's what my plist text looked like after I'd added the extra details. I've coloured my bits red here for clarity, but of course they shouldn't be coloured in the plist file! The keys are presumably mandatory, but the strings can be whatever you decide in the given format. I used murkie's posting name in the bundle identifier, because using "apple" as in the tutorial caused another stay-open applet I have to come to the front whenever relevant links were clicked. Presumably it was being passed the URLs, but that particular script wouldn't know a URL if it met one in the street. The one string in the CFBundleURLSchemes array is the protocol name I chose with which to head the URLs.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleIdentifier</key>
    <string>com.murkie.SafariTabChooser</string>
    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleURLName</key>
            <string>Safari Tab Chooser</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>safaritabchooser</string>
            </array>
        </dict>
    </array>

    <key>CFBundleAllowMixedLocalizations</key>
    <true/>
    <key>CFBundleDevelopmentRegion</key>
    <string>English</string>
    <key>CFBundleExecutable</key>
    <string>applet</string>
    <key>CFBundleIconFile</key>
    <string>applet</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>Safari Tab Chooser</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleSignature</key>
    <string>aplt</string>
    <key>LSMinimumSystemVersionByArchitecture</key>
    <dict>
        <key>x86_64</key>
        <string>10.6</string>
    </dict>
    <key>LSRequiresCarbon</key>
    <true/>
    <key>WindowState</key>
    <dict>
        <key>dividerCollapsed</key>
        <false/>
        <key>eventLogLevel</key>
        <integer>-1</integer>
        <key>name</key>
        <string>ScriptWindowState</string>
        <key>positionOfDivider</key>
        <real>333</real>
        <key>savedFrame</key>
        <string>736 281 602 597 0 0 1440 878 </string>
        <key>selectedTabView</key>
        <string>event log</string>
    </dict>
</dict>
</plist>


I typed the addtional stuff at the top of the main dict, as shown. But after the script had been run once, everything had been resorted alphabetically by key.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleAllowMixedLocalizations</key>
    <true/>
    <key>CFBundleDevelopmentRegion</key>
    <string>English</string>
    <key>CFBundleExecutable</key>
    <string>applet</string>
    <key>CFBundleIconFile</key>
    <string>applet</string>
    <key>CFBundleIdentifier</key>
    <string>com.murkie.SafariTabChooser</string>

    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>Safari Tab Chooser</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleSignature</key>
    <string>aplt</string>
    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleURLName</key>
            <string>Safari Tab Chooser</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>safaritabchooser</string>
            </array>
        </dict>
    </array>

    <key>LSMinimumSystemVersionByArchitecture</key>
    <dict>
        <key>x86_64</key>
        <string>10.6</string>
    </dict>
    <key>LSRequiresCarbon</key>
    <true/>
    <key>WindowState</key>
    <dict>
        <key>dividerCollapsed</key>
        <false/>
        <key>eventLogLevel</key>
        <integer>-1</integer>
        <key>name</key>
        <string>ScriptWindowState</string>
        <key>positionOfDivider</key>
        <real>333</real>
        <key>savedFrame</key>
        <string>736 281 602 597 0 0 1440 878 </string>
        <key>selectedTabView</key>
        <string>event log</string>
    </dict>
</dict>
</plist>


In theory, the protocol recognition should be effective from the moment the script's first run, but you may find you need to try a few things first like quitting any other script applets or (according to one theory I read on the Web) move the applet to another folder to get the system to notice it.

There are several cosmetic improvements one would want to make to what's presented on screen, but this is just to crack the nut of getting a script to respond to dedicated links in a Web browser.

Edit: Now uses a simple JavaScript function to bring the appropriate window to the front, in focus, and with the required tab displayed.
Edit 2: Dropped "AppleScript." from the bundle identifier. Slightly reduced the size of the tab link window. Worked round the unreliability of the JavaScript function. Expanded the HTML to give the Tab Bookmarks window a definite title and to recognise UTF-8 Unicode text. The temporary file is now also written as «class utf8».

Last edited by Nigel Garvey (2013-04-02 06:54:58 am)


NG

Offline

 

#7 2013-04-01 02:16:38 am

McUsrII
Member
Registered: 2012-11-21
Posts: 3046
Website

Re: Safari Tabs Window

Hello.

It seems appropriate to add to Nigel's excellent project, that you can indeed have javascripts installed on your bookmark bar, that calls such a non-standard protocol, providing another interface for an application that works closely with Safari. in fact giving you the same close interfacing with Safari, as a Safari plugin. ( I am a huge fan of a plugin called Sessions, that present all webpages and tabs in a single window, it has a sidebare, like the read later facility, so you can choose what session, (organized by date), to choose from. )

I am seriously considering such an approach, since I actually sometimes ends up with like 250 tabs in my browser. The downside for me right now, is that the number of tabs aren't persistant, and that the output adds to the tab count, I am still processing the approach however, for there are upsides to this as well, making a whole slew of sought for functionality available for Safari. smile


If someone should be interested in watching a full blown example of an app, that is triggered by bookmarks of javascript,  then skip over to MacOSAutomation.com, and  look for linktrigger.

Edit

Using your own protocol with such an app that is registred for said protocol, also enables you to provide cheap and different interfaces, that aren't dependent of safari or any other browser, as you can launch the generated html file with  qlmanage -p. The links in the webpage, referencing your protocol, should still work. smile

Edit+

I had to test if it acutally worked, by clicking a link, since it sunk in over me that I had just tested links that would open in a browser earlier, and just local anchors.

So I used the command line qlmanage -p qlmandemo.html in a terminal window, on the html below that I saved as qlmandemo.html, and it worked! I do take that as a proof of qlmanage invoking the launchd service with clickable links from a webpage, so a homegrown protocol should work equally well from this interface as well.

What I haven't tried, is to set the size of the window with css, maybe that works too. smile Colors and fonts works with CSS from qlmanage however, so the interface to a "protocol-app" can be made good looking.

[code]<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>QLmanage Demo</title>
</head>
<body>
<a href="http://macscripter.net">Go to Macscripter</a>
</body>
</html>[/code]
Edit++

There is nothing that would hinder you to build a really beautiful interface to an applescript "protocol-app", by using dashcode, providing you have the resources for it, as dashboard widgets are  rather expensive, -but can be truly good looking.

Last edited by McUsrII (2013-04-01 04:16:00 am)

Offline

 

#8 2013-04-01 05:02:07 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4604

Re: Safari Tabs Window

McUsrII wrote:

It seems appropriate to add to Nigel's excellent project, that you can indeed have javascripts installed on your bookmark bar …


I've just edited my script to use a single JavaScript command instead of the AppleScript three (including an invisible/visible hack) to bring the target window to the front in focus with the required tab displayed. The effect is much more pleasing. Is it possible for JavaScripts triggered by links in one window to affect other windows? That would of course make the whole custom protocol discussion here obsolete.  roll


NG

Offline

 

#9 2013-04-01 05:25:03 am

McUsrII
Member
Registered: 2012-11-21
Posts: 3046
Website

Re: Safari Tabs Window

Nigel Garvey wrote:

Is it possible for JavaScripts triggered by links in one window to affect other windows?


I think nothing is impossible, as you indeed can inject javascript into a page, an evenhandler, and then trigger that javascript from another page. Now, how I would commence to get that javascript injected, by only using javascript, I am unsure of as I don't have overview over to what extent Safari support javascript, as a scripting language.


Maybe this page may give you some answers.

Javascript is difficult to debug when you start out, so I recommend getting a lint function for BBEdit, or a whole Javascript development environment. It may save time, when you have to track that ";" down.

Last edited by McUsrII (2013-04-01 05:41:46 am)


Filed under: javascript, safari

Offline

 

#10 2013-04-01 05:28:51 am

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 5410

Re: Safari Tabs Window

Nigel Garvey wrote:

Is it possible for JavaScripts triggered by links in one window to affect other windows?


I would have thought the sandboxing in recent versions would have ruled that out.


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#11 2013-04-01 06:17:54 am

McUsrII
Member
Registered: 2012-11-21
Posts: 3046
Website

Re: Safari Tabs Window

Nigel Garvey wrote:

In theory, the protocol recognition should be effective from the moment the script's first run, but you may find you need to try a few things first like quitting any other script applets or (according to one theory I read on the Web) move the applet to another folder to get the system to notice it.


I think that maybe updating the plist file of the applet with a new (higher) version number should help. But you must of course quit the old one, and re-register it. Adding a higher number to the end of its name should also work, according to Apples documentation. (Property list key reference?). Here is a script for setting the version number from within Applescript Editor when the main.scpt is the frontmost document.

Last edited by McUsrII (2013-04-01 06:21:11 am)


Filed under: Applet, registering

Offline

 

#12 2013-04-01 04:21:07 pm

Adam Bell
Administrator
From:: Nova Scotia, Canada
Registered: 2005-10-04
Posts: 4663

Re: Safari Tabs Window

McUsrII wrote:

Hello.

It seems appropriate to add to Nigel's excellent project, that you can indeed have javascripts installed on your bookmark bar, that calls such a non-standard protocol, providing another interface for an application that works closely with Safari. in fact giving you the same close interfacing with Safari, as a Safari plugin. ( I am a huge fan of a plugin called Sessions, that present all webpages and tabs in a single window, it has a sidebare, like the read later facility, so you can choose what session, (organized by date), to choose from. )


Pardon this diversion from the main thread, but I have a JavaScript bookmark that I use to get a page in Readability form (which I prefer to Safari's "Reader" button).

Applescript:

javascript:(function()%7BreadStyle='style-novel';readSize='size-large';readMargin='margin-wide';_readability_script=document.createElement('SCRIPT');_readability_script.type='text/javascript';_readability_script.src='http://lab.arc90.com/experiments/readability/js/readability.js?x='+(Math.random());document.getElementsByTagName('head')%5B0%5D.appendChild(_readability_script);_readability_css=document.createElement('LINK');_readability_css.rel='stylesheet';_readability_css.href='http://lab.arc90.com/experiments/readability/css/readability.css';_readability_css.type='text/css';_readability_css.media='screen';document.getElementsByTagName('head')%5B0%5D.appendChild(_readability_css);_readability_print_css=document.createElement('LINK');_readability_print_css.rel='stylesheet';_readability_print_css.href='http://lab.arc90.com/experiments/readability/css/readability-print.css';_readability_print_css.media='print';_readability_print_css.type='text/css';document.getElementsByTagName('head')%5B0%5D.appendChild(_readability_print_css);%7D)();

or, more legibly in full script form (which I use with a hot key):

Applescript:

(*
The following JavaScript from Arc90 "makes reading on the web more enjoyable by removing the clutter around what you're reading" and the Readability site allows you to set Style, Size and Margin in the material. It is normally used by dragging a link from the Readability page to your Bookmarks Bar, and that puts the JavaScript below as the content of the bookmark. The page thus created in your browser has a link on it to return to the original source.

Visit "[url]http://lab.arc90.com/experiments/readability/[/url]" for your own copy.

Because I'm an avid Quicksilver fan (but there are lots of alternatives), I prefer to set up a trigger to run the script below so I can enhance the readability of an article I'm looking at with a simple key combination. Although it cannot render every site I visit, it does remarkably well.
-- Note that the script below has been altered for readability. The original is all one string.
*)


set JS to "readStyle='style-novel';
   readSize='size-large';
   readMargin='margin-wide';
   _readability_script=document.createElement('SCRIPT');
   _readability_script.type='text/javascript';
   _readability_script.src='http://lab.arc90.com/experiments/readability/js/readability.js?x='+(Math.random());
   document.getElementsByTagName('head')[0].appendChild(_readability_script);
   _readability_css=document.createElement('LINK');
   _readability_css.rel='stylesheet';
   _readability_css.href='http://lab.arc90.com/experiments/readability/css/readability.css';
   _readability_css.type='text/css';
   _readability_css.media='screen';
   document.getElementsByTagName('head')[0].appendChild(_readability_css);
   _readability_print_css=document.createElement('LINK');
   _readability_print_css.rel='stylesh eet';
   _readability_print_css.href='http://lab.arc90.com/experiments/readability/css/readability-print.css';
   _readability_print_css.media='print';
   _readability_print_css.type='text/css';
   document.getElementsByTagName('head')[0].appendChild(_readability_print_css);"


tell application "System Events" to set last_app to item 1 of (get name of processes whose frontmost is true)
if last_app is "Safari" then
   tell document 1 of application "Safari" to do JavaScript JS
else if last_app is "NetNewsWire" then
   tell document 1 of application "NetNewsWire" to do JavaScript JS
else
   beep 3
end if


iMac running OS X 10.13.1

Offline

 

#13 2013-04-03 12:27:38 am

murkie
Member
Registered: 2013-03-23
Posts: 4

Re: Safari Tabs Window

Wow, I really appreciate everyone's help here. I'd like to share my most recent implementation. I've based this on the work of Nigel Garvey. I've polished up the resulting window, here's how I like it:

Applescript:


-- This is two scripts in one applet.
-- The 'idle' handler calls the 'updateTabBookmarks()' handler, which creates and/or updates a "Tab Bookmarks" window in Safari.
-- The 'open location' handler receives a URL from the system when one of the custom-protocol links in the window is clicked. It analyses the URL and tells Safari to display the relevant tab.

-- The script should be saved as a stay-open application and then its "Info.plist" file edited as described elsewhere to set up its custom "safaritabchooser:" URL protocol.

-- Based on a script idea by "murkie" <[url]http://macscripter.net/viewtopic.php?pid=161636#p161636[/url]>
------------------------------------------

-- CREATE OR UPDATE A "TAB BOOKMARKS" WINDOW.

on idle
   -- If Safari's open, check the tabs in all its applicable windows and create or update a "Tab Bookmarks" window accordingly. Idle for ten seconds between rounds.
   -- Otherwise idle for two minutes between tests for Safari being open.
   
   tell application "System Events" to set SafariOpen to (application process "Safari" exists)
   
   if (SafariOpen) then
       updateTabBookmarks()
       return 10
   else
       return 2 * minutes
   end if
end idle

on updateTabBookmarks()
   -- The HTML for the "Tab Bookmarks" window can't be inserted directly into Safari and will have to be saved to a temporary file, whose name will set the name of the window.
   set tempFileName to "SafariTabs.html"
   -- We'll use a unique HTML comment for positive identification of the "Tab Bookmarks" tab when updating.
   set bookmarksHTMLComment to "<!--- MURKIE'S TAB BOOKMARKS --->"
   
   try
       -- Get the names and URLs of all Safari's existing tabs and the IDs of its windows. Unsuitable windows without tabs will be ignored below.
       tell application "Safari" to set {{tabNames, tabURLs}, windowIDs} to {{name, URL} of tabs, id} of windows
       
       -- Build a simple HTML page source containing clickable links to the tabs with URLs in our custom protocol. The links are grouped by window and the Tab Bookmark tab itself is not included. The urls are in the form:
       -- safaritabchooser://com.murkie.AppleScript.SafariTabChooser?windowid=<ID>&taburl=<URL>.
       set pageContent to "<html>" & linefeed & bookmarksHTMLComment & linefeed & "<head><style>a {color:#09c; font-size:11px; font-family:verdana, arial, helvetica, sans-serif;
   font-weight:600; text-decoration:none;} a:link {color:#09c;} a:visited {color:#07a;} a:hover {background-color:#eee;}</style></head><body><table>"
& linefeed
       set tabBookmarksExist to false
       set rowCount to 1
       repeat with i from 1 to (count tabNames)
           set theseTabNames to item i of tabNames
           if (theseTabNames is not {}) then
               set theseTabURLs to item i of tabURLs
               set thisWindowID to item i of windowIDs
               repeat with j from 1 to (count theseTabNames)
                   set notBookmarkTab to true
                   set thisTabName to item j of theseTabNames
                   if (thisTabName is tempFileName) then
                       set tabBookmarkTabURL to item j of theseTabURLs
                       set tabBookmarkWindowID to thisWindowID
                       tell application "Safari" to set thisTabSource to (source of first tab of window id tabBookmarkWindowID whose URL is tabBookmarkTabURL)
                       -- set myParagraphs to paragraphs of thisTabSource
                       -- displayError(myParagraphs)
                       set tabBookmarksExist to (paragraph 2 of thisTabSource is bookmarksHTMLComment)
                       set notBookmarkTab to (not tabBookmarksExist)
                   end if
                   if (notBookmarkTab) then
                       if (rowCount mod 2 = 0) then
                           set rowColor to "#aaaaff"
                       else
                           set rowColor to "#aaffaa"
                       end if
                       set linkText to "<tr bgcolor=" & rowColor & "><td><a href=safaritabchooser://com.murkie.AppleScript.SafariTabChooser?windowid=" & thisWindowID & "&taburl=" & item j of theseTabURLs & ">" & thisTabName & "</a></td><tr>"
                       set pageContent to pageContent & linkText & linefeed
                       set rowCount to rowCount + 1
                   end if
               end repeat
               if ((notBookmarkTab) or (j > 1)) then set pageContent to pageContent & "<br>" & linefeed
           end if
       end repeat
       set pageContent to (pageContent & "</table></body></html>")
       
       -- Write the HTML to a temporary file.
       set tempFilePath to (path to temporary items as text) & tempFileName
       set accessRef to (open for access file tempFilePath with write permission)
       try
           set eof accessRef to 0
           write pageContent to accessRef
       end try
       close access accessRef
       
       -- Get the file's URL and open it in Safari — in the existing Tab Bookmarks window if there is one; in a new one if not.
       tell application "System Events" to set u to URL of disk item tempFilePath
       
       tell application "Safari"
           if (tabBookmarksExist) then
               set URL of (first tab of window id tabBookmarkWindowID whose URL is tabBookmarkTabURL) to u
           else
               make new document with properties {URL:u}
               set bounds of window 1 to {900, 280, 1440, 900} -- Adjust as required.
           end if
       end tell
   on error error_message
       displayError(error_message)
   end try
end updateTabBookmarks


-- HANDLE THE URL ISSUED WHEN A TAB BOOKMARK IS CLICKED.

on open location this_url
   -- Handle a URL with our custom protocol, passed to the script by the system.
   -- Parse it for the window ID and tab URL and get Safari to act accordingly.
   -- As a reminder, the form of the URL is:
   -- safaritabchooser://com.murkie.AppleScript.SafariTabChooser?windowid=<ID>&taburl=<URL>.
   
   -- It's assumed the ID will come before the URL, but the code can cope with the URL not being given should it ever be decided to add the facility just to bring a window to the front without going to a particular tab.
   
   try
       set c to (offset of "&taburl=" in this_url)
       if (c > 0) then
           set tabURL to text (c + 8) thru -1 of this_url
       else
           set tabURL to missing value
       end if
       set windowID to (text ((offset of "?windowid=" in this_url) + 10) thru (c - 1) of this_url) as integer
       
       tell application "Safari"
           activate
           tell window id windowID
               if (it exists) then
                   -- JavaScript does a better job than AppleScript here.
                   if ((tabURL is missing value) or (URL of tabs does not contain tabURL)) then
                       do JavaScript "window.focus()" in current tab
                   else
                       do JavaScript "window.focus()" in first tab whose URL is tabURL
                   end if
               end if
           end tell
       end tell
   on error error_message
       displayError(error_message)
   end try
end open location


on displayError(msg)
   tell application (path to frontmost application as text)
       display dialog msg buttons {"OK"} default button 1 with title "Safari Tab Chooser" with icon caution
   end tell
end displayError

And make sure you don't forget the Info.plist mods described in his post.

Offline

 

#14 2013-04-03 05:24:15 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4604

Re: Safari Tabs Window

Hi murkie.

Glad the ideas helped. Thanks for posting your own version.

I've edited my script (post #6 above) a couple of times since posting it, based on my experience with it. Of interest to you may be that the HTML is now written to file and understood as UTF-8 Unicode and the opening of tabs is more reliable. (On my machine, the JavaScript doesn't work with tabs which haven't been focused before, such as when "Open in Tabs" has been selected in a bookmark menu.)

Last edited by Nigel Garvey (2013-04-03 05:26:59 am)


NG

Offline

 

#15 2013-12-26 05:58:13 pm

murkie
Member
Registered: 2013-03-23
Posts: 4

Re: Safari Tabs Window

Hi, folks! I've just updated Safari to 6.1.1 and now I observe my TabsWindow is no longer able to link back to the tab I want when I click. Has anyone studied the documentation updates to learn some new behavior?

Offline

 

#16 2014-03-28 08:43:33 am

Krioni
Member
From:: New York, NY
Registered: 2002-11-20
Posts: 245
Website

Re: Safari Tabs Window

Has anyone else using custom protocols like Nigel described noticed that they stop working in Mavericks? My AppleScript applet has handled the protocol 'htclink' without trouble for several years now, but my system is now reporting:

There is no application set to open the URL htclink://blahblahblah
Search the App Store for an application that can open this document, or choose an existing application on your computer.


Not sure if this is true for everyone, or just some. At least one other person has had this problem: http://veritrope.com/code/outlook-2011-to-evernote/

I'm going to ask him if he found a fix/workaround.

Offline

 

#17 2014-03-29 02:35:02 am

McUsrII
Member
Registered: 2012-11-21
Posts: 3046
Website

Re: Safari Tabs Window

I'm having the same problem, but I have had to stall it at the moment.

I am going to have a serious look into the lauchservices file, and see what is there, or not. This was allways rather clunky, when it got to register the applet, so I deem it possible that it still may work. smile

Edit

I'm not working on this right now, but I have figured out, that the app must have the role of browser specified in the property list file.

It also helps to increase the build version number (short bundle version string), when you reregister the app.

And, it beats me, that maybe they prohibit it, as a security measure along the lines of sandboxing, and like redirecting to other sites for "cross browser attack". But, at least I'll try when I find the time, to make this work again, because it was very useful, and cool.

Last edited by McUsrII (2014-03-29 05:27:29 am)

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)