Jump to content

CJK

Member
  • Posts

    79
  • Joined

  • Last visited

  • Days Won

    7

Posts posted by CJK

  1. For the benefit of the OP, @kodiak, «event ASTgetlo» is the raw syntax code for AST mouse point location.  The error reported by @vitor relates to the commands from your scripting addition, which the script doesn't understand.  If you're trying to export a workflow, it won't be able to run on any system without the scripting addition included as part of the exported package.


    That's one reason why using scripting additions is disadvantageous.


    I can see you're trying to access the Dropbox menubar pop-up menu, which requires a modifier key to be depressed whilst clicking - something that can't be done conventionally with System Events.  However, if you consider which functions you want to access from that pop-up menu, I believe all of them are accessible through other means, namely the standard left-click pop-up pane, which has a preferences (cogwheel) button and a few other buttons that provide those options.  That will be regularly scriptable using System Events, if you really must go down that avenue.

  2. @zuchmir The JXA code is correct.  I think you have a problem elsewhere.  It appears, for one, as if you might have multiple Google Chromes.


    What's the result if you run this code:


    Application('com.google.Chrome').properties()


    Here's the output you should expect:

     

    {"bookmarksBar":Application("Google Chrome").bookmarkFolders.byId(1), "frontmost":false, "otherBookmarks":Application("Google Chrome").bookmarkFolders.byId(2), "pcls":"application", "title":"Google Chrome", "version":"68.0.3440.106"}

     

  3. 2 hours ago, rodrigobdz said:

    @CJK What is the purpose of declaring www as local variable in the method?

     

    In that script as it is, it serves no specific purpose.  But, whenever I write an AppleScript handler, I tend to declare all of its parameters immediately on the opening few lines as local, really as more of a "good coding practice" ethos than anything else.  The only time is necessary to do this is when you have a global property or variable declared elsewhere in your script with the same name.  If, then, you declare a handler that takes a parameter also by that name and you don't declare your parameter as local, you'll end up retrieving or overwriting the global value instead of the value passed to your handler.

     

  4. 2 hours ago, deanishe said:

    Quick question: What does this line do? set [W] to _W

     

    If _W is a list, then it sets W to item 1 of that list.

     

    It follows from the way one can assign multiple values to multiple variables in one go:

        set [a, b, c, d] to [1, 2, 3, 4]

    which, as you might expect, assigns 1 to a, 2 to b, 3 to c, and 4 to d.

     

    If the number of variables supplied is fewer than the number of data objects to store, the variables are filled in order, and the remaining (excess) data values are discarded.  So,

        set [a, b] to [1, 2, 3, 4]

    assigns 1 to a, 2 to b, whilst the and the are ignored.

     

    Therefore,

        set [T] to every tab in the front window 

    will get a list of every tab, and assign the first one to T.  It works with nesting as well, so something like:

        set [T] to every tab of every window

    assigns a list of tabs to T, but if you just want the first item from that list:

        set [[T]] to every tab of every window

    will get you a single tab assigned to T.

     

    P.S.  Or perhaps your confusion was because I utilise the square brackets for lists much more than other people, who typically favour braces.  For the most part, they're interchangeable as long as opening and closing sets match.  However, when coercing a list to a string, square brackets ignore text item delimiters completely, which can be very useful.  Square brackets can't be used for records objects, although list items in a record can use them freely.

  5. 1 hour ago, deanishe said:

     

    Could you post the complete, working code? It would be clearer than prose and individual lines, and more useful.

     

    Yes, of course.

     

    (30 minutes later of frustrating edits...)

    to lookupTabWithURL(www)
    	local www
    
    	tell application "Google Chrome"
    		set _W to a reference to (every window whose URL of tabs contains www)
    		
    		if (count _W) = 0 then return null
    		set [W] to _W
    		
    		set T to the first tab of W whose URL is www
    		
    		return {wID:id of W, tID:id of T}
    	end tell
    end lookupTabWithURL

    This one above returns both window and tab id numbers, should you need to target them in that manner, for example, to bring a window to the front, then switch the active tab.

    to lookupTabWithURL(www)
    	local www
    	
    	tell application "Google Chrome"
    		set _T to a reference to (every tab of every window whose URL is www)
    		
    		if (count _T) = 0 then return null
    		return item 1 of item 1 of _T
    	end tell
    end lookupTabWithURL

    This one just returns the reference to the tab object, e.g. tab id 45 of window id 2088.  This can be used to target the identified tab and manipulate its properties or close it, for example.  It currently only returns the first matched tab, as that was the objective of the original script upon which this handler was based, largely as a demonstration on the different scripting methods.

  6. 13 hours ago, rodrigobdz said:

    Thanks for the lesson @CJK. I think there is a small error in getting the result's count by doing:

    
    if (count T) = 0 then return null
    -- Logging (count T) always returns (*2*)
    -- Logging T returns (*,*) when no empty tabs are open.

    Thus, throwing an error by accessing item 1 of item 1 when no empty tab is open.

     

    My apologies.  If you compare my two versions, you can see an omission in the second (unintentional) that is the cause of the error you're experiencing.  The line in question is

    set T to every tab of every window whose URL is www

    which should be, as per the script above it:

    set _T to a reference to (every tab of every window whose URL is www)

    and then change T to _T as it occurs in the subsequent lines; I like to mark my variables that are stored by reference with an underscore, so I don't lose track of it.  Once an AppleScript filtered list reference gets dereferenced to a standard list object, the way it gets handled changes at a fundamental level.

     

    My basic rule-of-thumb, in these cases where one is building up clauses of filtered lists, is to try and store them as references until you the moment you need to evaluate a property collection or do something with an item in that list.  Doing so will probably dereference it implicitly, or you can explicitly deference it by writing

    contents of _T

    The rest should work as it is now, including when no empty tabs are open (which is where count _T = 0 and null is returned).

     

    As you stated, @rodrigobdz, filter-whose clauses are much more elegant, and ought to be a lot faster too than a repeat loop.  I, personally, would go so far as to say I loathe repeat loops, and do my best to avoid them (at least in AppleScript; they're fine in other languages).  Of course, there's no rational basis for my feelings on this whatsoever, and it's largely a stylistic choice (except in cases where the speed benefits are dramatic, and those cases do exist).

  7. @rodrigobdz, you could try inserting a modest delay before that line, i.e.

    delay 0.2
    close (every tab of every window whose URL contains "chrome://newtab/"

    but I'm unable to recreate the problem on my machine, which probably indicates the delay might help other machines.

     

    P.S. Thanks for including the GitHub link.  That was very considerate and it's helpful when people share their research in this manner.  I actually don't like the way he wrote his lookupTabWithUrl() handler because of it's unnecessary use of repeat loops; I can't think of a specific reason to do it that way.  He's basically iterating through every window, and then iterating through every tab in each window, and testing whether each tab's URL matches the argument passed to the handler (he exits on first match).  So, this is identical in result to (but slower to execute than) this:

    to lookupTabWithURL(www)
    	local www
    
    	tell application "Google Chrome"
    		set _W to a reference to (every window whose URL of tabs contains www)
    		
    		if (count _W) = 0 then return null
    		set [W] to _W
    		
    		set T to the first tab of W whose URL is www
    		
    		return {wID:id of W, tID:id of T}
    	end tell
    end lookupTabWithURL

    which could be condensed somewhat further if you only need a reference to the tab (more likely) and not the individual tab and window IDs:

    to lookupTabWithURL(www)
    	local www
    	
    	tell application "Google Chrome"
    		set T to every tab of every window whose URL is www
    		
    		if (count T) = 0 then return null
    		return item 1 of item 1 of T
    	end tell
    end lookupTabWithURL

     

  8. My favourite thing about the Alfred forum is that there’s precisely two modes of syntax highlighting that seemingly cater for about 12 different programming languages: and those two choices are either Courier New all in black, or Courier New in black and green (but only quoted strings are in green).

     

    My second favourite thing is that once you commit to the block of code you just wrote, you can’t edit it.  Or highlight it to copy it.  I love typing things out twice.

     

    I love typing things out twice.

  9. Looking at the source code, I can see why these users are experiencing these issues.  I downloaded the workflow and had a look at the AppleScript, which has quite a few issues with it.  @rodrigobdz, I note from your original post that Assistive Access is required to run this workflow.  Writing an AppleScript to achieve what you want here—namely opening a Chrome window/tab—shouldn't need to employ any accessibility features via System Events.

     

    Here's your code that I copied from the workflow:

    tell application "System Events"
    	set myList to (name of every process)
    end tell
    if (myList contains "Google Chrome") is false then
    	do shell script "open -a Google\\ Chrome --new --args -incognito"
    	open location "https://google.com/search?q={query}"
    else
    	tell application "Google Chrome"
    		activate
    		tell application "System Events" to keystroke "n" using {command down, shift down}
    		open location "https://google.com/search?q={query}"
    	end tell
    end if

    Google Chrome is scriptable, therefore you don't need to access System Events processes to determine whether or not Chrome is running.  Scriptable applications have a property called running that returns true or false depending on whether or not Chrome is running.  You can access it as with any other property, like so:

    set isOpen to the running of application "Google Chrome"
    if isOpen then ...

    But, for this particular property (and a couple of others that return boolean values for the state of an application, another one being the property frontmost), you can use this very natural-language syntax:

    if the application "Google Chrome" is running then ...

     Following this, the reason the users are reporting two windows opening up—one of which might even be Safari instead of Chrome—is because you have one command telling a shell script to open Chrome in incognito mode (bearing in mind that launching a web browser usually opens a blank window); and you have a second command telling AppleScript to open location and this will always happen in a new window (that makes two windows), and it won't necessarily be Chrome. I believe it uses the system's default browser, which explains why there's a user reporting that your workflow opened Safari and Chrome for him (it did with me as well).

     

    Basically, don't use open location when you want to target a specific web browser.  You could have used the same shell command that launches Chrome to get it opening a desired URL in the first window:

    do shell script "open -a 'Google Chrome' 'https://imdb.com' --args -incognito"

    And, finally, for the last part of your script, you've once again elected to use System Events to issue a keypress that activates a shortcut to a menu item as a means to open an incognito window.  That's a bad method.  But, immediately afterwards, you use open location again, intending for the URL to open in the window you've just created.  For some users, it might do just that; but for others, it won't.

     

    Basically, don't use open location, and don't use System Events for its accessibility hooks when you don't need to.  It's always a method of last resort, because it's very unreliable, and poor coding practice.  Do, however, use System Events for things like file and folder handling.

     

    Anyway, here's how you first check to see if an incognito window is already open, then open a URL in a new tab in the existing window instead of creating a new window altogether, or, if an incognito window doesn't yet exist, opening a new URL in a new incognito window:

    tell application "Google Chrome"
    	set W to every window whose mode is "incognito"
    	if W = {} then set W to {make new window with properties {mode:"incognito"}}
    	
    	set [W] to W
    	
    	tell W to set T to make new tab with properties {URL:"{query}"}
    	close (every tab of every window whose URL is "chrome://newtab/")
    	
    	set index of W to 1
    	
    	activate
    end tell

    In fact, on my system, that works regardless of whether or not Chrome is running, negating the need for all the bits that came before.  Thus, that ends up being the entire script.

     

    I hope this helps you out, and helps resolve the issues your users were having.

     

     

  10. 3 hours ago, Chamend said:

    Thanks @CJK! That works great.

     

    You're welcome, @Chamend.  On the surface, it functions identically to yours.  But under the hood, it targets the Safari application and its window(s)/tab(s) directly, so it won't even matter whether or not Safari is in focus, or even if the window were minimised (provided it is still the front window).

     

    One of the reason using System Events in that manner is (should) be a last resort (but is done all too commonly to appear to be "the right way"), is because menu items are generally referenced by name, and these can change (by language and region), so is especially less portable if you plan to share workflows with others.  Keypresses to activate a shortcut is worse still, as these are customisable by design on macOS.  Both also require  Safari to be in focus, and application focus can shift unexpectedly, which would disrupt the script.

     

    Just thought it might be useful for you to know all this if you're planning on venturing more into the AppleScripting world (which I encourage!).  I actually drafted out a much more complex script to open tabs in any specific Safari window or a new window, and provide the option of deciding whether to open it in the background or bring it to the front.  It benefited from being more robust and feature-worthy, but seemed a bit overly involved in this situation.  Nevertheless, if you want to take a look at it, I've posted it here for the time-being.

  11. Basically, your script from this post reply here:

    if you incorporate my suggested modifications, would now look like this:

    on alfred_script(q)
    	tell application "Safari"
    		activate
    		make new document with properties {URL:"https://www.apple.com"}
    		my new_tab("https://www.google.com")
    		my new_tab("https://stackoverflow.com")
    	end tell
    end alfred_script
    
    
    on new_tab(www)
    	tell application "Safari" to tell the front window to ¬
    		set the current tab to make new tab ¬
    			with properties {URL:www}
    end new_tab

     

     

  12. 4 hours ago, deanishe said:

     

    Which is exactly what the Kitten Image workflow appears to be. You literally just need to change the URL.

     

    In what way is that workflow unsuited to your purpose?

     

    @deanishe, @heyJoeCampbell was responding to the workflow that I posted given that the original was not available at the link at the time.  However, I misinterpreted the objective of the OP, so my workflow does something entirely different than what was needed, whereas the Kitten Image workflow actually solves the problem and has now been reposted.

     

    I've now deleted my workflow as it's not relevant this post.

  13. Hi @Chamend

     

    This slight adjustment to the script negates the need to use System Events to issue menu clicks (which is an unreliable method):

     

    on new_tab(www)

            tell application "Safari" to tell the front window to ¬

                    make new tab with properties { URL:www }

    end new_tab

     

    Then you call the handler, specifying the URL at the same time, e.g.:

     

            my new_tab("https://stackoverflow.com")

  14. Hi @JDG,

     

    Having had a look on the Logos website, I can't see any references to AppleScript in their Mac support pages.  My guess is that the app is not scriptable.  You can determine this definitively by opening Script Editor and executing this single line of code:

    tell application "Finder" to get has scripting terminology of (path to application "Logos 7")

    replacing "Logos 7" if the name of the application is different to this (go by either the application filename, or the name that sits in the menu bar in the top-left of the screen when you use the application).  Script Editor will either return true or false.

     

    Working for now on the assumption that it's going to return false, I believe you have two options:

     

    ①  As @deanishe suggested, UI scripting could possibly (probably) achieve what you need, but it's a real sledgehammer of a technique that isn't always going to work seamlessly (but it's better than nothing).  The barrier I see to this option is that—I assume—you don't have much AppleScripting knowledge, and UI scripting is virtually impossible to do unless one has the application to work with on one's own system (which makes someone else's help dependent on them both knowing AppleScript and having the Logos software).

     

    ②  Their web app might be a more accessible way of retrieving data that you would otherwise get from the desktop application, especially if you use Safari or Chrome.  As both Safari and Chrome are scriptable, this presents some possibilities for automation, either by way of http queries or by way of JavaScript.  But, again, one needs an account with FaithLife to access the web app.

     

    I'll let you contemplate on this.

  15. *facepalm*

     

    You'll want to take another look at the workflow I uploaded for you.  Yes, it so happens that I (randomly) chose the workflow's action to open up a folder in Terminal, but No, the workflow itself does not employ any scripts or the use of *Terminal* in order to search through folders within Alfred.

     

    You're asking:

     

    3 hours ago, jipnet said:

    Is there no built-in way to search for folders rather than files? (ie to specify to exclude files and just look for folders)?

     

    and that's exactly what a File Filter does, and what my workflow demonstrates.

  16. Unfortunately, you didn't post a screenshot of the workflow in action, perhaps just after you had typed in the search bar, and began to enter the first few letters of a folder name.

     

    Did you set a search scope for this filter ?  I've uploaded a workflow here that uses the File Filter to allow you to select a folder, the location of which will be the working directory of a new Terminal window that opens up.

     

    To use, open the Alfred search bar, type cd <space> then the start of a folder name, e.g.

    cd vol

    which, on my system, brings up /Volumes, Kill Bill Volume 1. soundtrack folder, etc.

     

    If this workflow doesn't work for you, then this might be a symptom of a bigger problem.

×
×
  • Create New...