AppleScript and Apple Pages.
Is it possible to know if the Toolbar is visible?
What I have tried. I can access to the Menu / View / Show Toolbar or Hide Toolbar. But the problem is that this depends on the language the user uses in the operating system. So, I need a solution that could work in any language.
I'm assuming you were accessing the menu using UI scripting by way of System Events, which, if I recall correctly, contains a class of UI Element called toolbar. You could try and see if the front window in Pages contains a toolbar element. If it does, it's probably within the top-level of the hierarchy.
tell application id "com.apple.systemevents" to ¬
tell the front window of the process "Pages" to ¬
set toolbarIsVisible to toolbar 1 exists
If this snippet is viable, it will assign either true or false to the variable toolbarIsVisible. The way to check whether this snippet is viable is to run it when the toolbar is visible, which should return true.
General Localisation Considerations
Application (and process) names are locale-dependent, so the above snippet needs a little bit of adapting to be fully internationalised, in case Pages goes by a different name in other countries. Here's a rough breakdown of various methods you can use to make this locale-friendly:
Search for the process using the bundle identifier property
Bundle identifiers are another way to identify applications, and these are locale-independent strings that are registered with the system, and therefore will be unique to a single application (whereas multiple applications could share the same name).
The process for your running Pages instance can be referenced by way of its bundle identifier ("com.apple.Pages") like so:
tell application id "com.apple.systemevents" to ¬
tell the first process whose bundle identifier ¬
is "com.apple.Pages" to ...
The keyword whose performs an efficient search through all of the processes, in each case looking up the value of the property named bundle identifier for each process, returning the first matching process object it comes across. In our case, it'll be the process you'd normally reference with process "Pages", but now got in way that doesn't favour any specific language.
Use the bundle identifier of the application object
A slightly more direct method would be to reference application "Pages", again, using the application's bundle identifier, "com.apple.Pages". You do this by inserting the keyword id after application, followed by its bundle identifier:
application id "com.apple.Pages"
--> application "Pages"
Since every application has a name property that AppleScript can retrieve, then:
name of application id "com.apple.Pages"
--> "Pages"
returns the name of the application, which on an English-language system will be "Pages", and on any other system will be the localized version of that. This can then be used to reference the process by name:
tell application id "com.apple.systemevents" to tell the ¬
process named (application id "com.apple.Pages") to ...
String localisation
Probably the best and most recommended way is to lookup the localised string from a .strings file, which application bundles keep in sub-folders of their Resources folder, named by locale. It's a set of key-value pairs that containing translations for labels and messages used by the application, including menu item names, application names, dialog messages, and so on.
AppleScript can read the values for a given key using its localized string command. The particular .strings file we're interested in is called "InfoPlist.strings"(but we leave out the extension when passing it to this command).
So:
get the localized string "CFBundleName" from table "InfoPlist" in bundle application id "com.apple.Preview"
On my system, and I'm guessing yours, this will, of course, just return "Preview". On a German-language system, however, it returns "Vorschau".
Putting this all together, the very first snippet at the top of this script would be internationalised like so:
set CFBundleName to the localized string of "CFBundleName" from table ¬
"InfoPlist" in bundle application id "com.apple.Pages"
tell application id "com.apple.systemevents" to tell ¬
the front window of the process named CFBundleName ¬
to set toolbarIsVisible to toolbar 1 exists
Related
I am newbie with Applescript and Automator. I am trying to build a Quick Actions which will be able to propose different functions according to the type of file for example.
If the file is test.sh quick action will be a and b
If the file is document.pdf action will be c and d
I succeed in creating my actions but not to make them specific to file type. I don't know where to start as I don't see any possibility to make input conditional like if input = .sh do a and b.
Any help on how to proceed will be really appreciated.
Thank you,
After looking at the image of your QuickAction, it is not at all useful for anything other then a selected PDF document in Finder.
The first action should be a Set Value of Variable action so its contents can be retrieved multiple times using Get Value of Variable with however many Filter Finder Items actions needed to process the different file types, followed by the appropriate actions for each file type.
You would also use Ignore this action's input checkbox under Options for this action to detach it from the previous set of actions.
The image below shows a rough outline example of what I'm referring to:
Quick Actions are meant to be type-specific, so in general the best practice is to write one Quick Action for each file type. These quick actions will only appear in the Finder when files of that type are selected.
In many cases you can specify the file type when you create or edit the Quick Action in Automator. For instance, to create a Quick Action that appears only when PDF files are selected, set the pulldown menus at the top of the workflow to say "Workflow receives current PDF files in Finder":
then complete and save the Quick Action.
If you want more fine-tuned control over what types of files the Quick Action 'sees', you can edit its info.plist file and change its file types. After you've saved the Quick Action, navigate to ~/Library/Services in the Finder (that's the Services folder in the Library folder of your Home folder). Find the package with the name of the Quick Action (e.g., "Open in Preview"), control-click on it to get the contextual menu, choose Show Package Contents, and then open the Contents folder. You'll see the following:
Open that info.plist file in a plain-text text editor — I prefer BBEdit, but TextEdit will work fine if you make sure 'rich text' is turned off — and look for the NSSendFileTypes key. It will look something like the following:
<key>NSSendFileTypes</key>
<array>
<string>com.adobe.pdf</string>
</array>
com.adobe.pdf is a Uniform Type Identifier (UTI), and you can add or substitute in any system-recognized UTI. Here is the list of system-declared UTIs, but applications can declare their own UTIs and register them with the system, so this list is not necessarily exhaustive. For instance, if you want your Quick Action to send both PDFs and image files to Preview, you would search on the system-declared UTIs page and find that the base UTI for images is public.image, and then edit the info.plist to read:
<key>NSSendFileTypes</key>
<array>
<string>com.adobe.pdf</string>
<string>public.image</string>
</array>
Save this, and the Quick Action will now appear whenever you selected PDFs or images. Note that if you manually edit the info.plist file it might get overwritten if you edit and save the Quick Action in Automator.
Only the first two relevant Quick Actions will appear in the Finder window; any extras will be collapsed under the more button. To change the ordering so that the Quick Actions you use most are up first, open System Preferences, click the Extensions item, open the Finder section, and drag the items in the right-hand list into the order you prefer.
I have a set of tabs with proper roles and attributes for accessibility support. The content that tab controls gets loaded in via ajax. But each wrapper for the content loaded in also has proper tab pane roles and attributes.
The problem is, when I run an automated audit using Chrome Accessibility Tools, the test fails stating that the corresponding ID of the tab pane is missing for all of the tabs except the one that's currently active (because that wrapper with ID has been loaded). The exact error states: "ARIA attributes which refer to other elements by ID should refer to elements which exist in the DOM."
Since the ID will exist once the tab with the corresponding aria-controls attribute is active, is this really an error? Or is this just a case of a false positive because it's an automated test and they can only do so much.
In summary, What does aria-controls do and does it really need to refer to an ID that currently exists in the DOM?
aria-controls give your assisting technology a way to move to the controlled element.
If this element is not in the DOM or can't be accessed, then yes it's an error.
The two (the element with aria-controls as well the element with the referenced id) must exist at the same time, whether at page render or via JS injection.
The DOM is parsed by the UA/AT combo before the user even gets to the control or your script fires to make it exist. If you use JS injection then you need to make sure the DOM is re-parsed.
This would apply to aria-owns as well.
I don't know whether the following would work in your architecture, but it would solve the error problem:
Design the tabs so they are all in the page at the time it loads. Format those that should not be shown to be outside the viewport using absolute positioning and something like "left: -99em." Use AJAX to reset the positioning when the time has come to display the tabs. The result is that the ARIA ID dependencies will always be valid because the tabs are always part of the DOM.
I've been trying to format my Evernote notes (thousands of them) so that they are readable on any device.
I've accessed evernote storage on my Mac and saw folders of entries -- every folder contains a note.xhtml and a content.enml files, which directly stores note contents.
I can modify the *.xhtml file, and changes are reflected on Evernote client, but they just won't sync over to the server. Additionally, the *.enml file contains corresponding content to xthml file, but the change won't go there.
Is there any way I can neatly edit my notes, on the HTML level?
Thx!
In AppleScript, it's pretty easy to get and set the HTML. To actually manipulate the HTML you might want another language.
Here's how you read and write HTML content to a single selected Evernote note:
tell application "Evernote"
set noteList to selection
set n to item 1 of noteList
set extractedHtml to HTML content of n
set HTML content of n to "<p>Foo Bar</p><p>foo baz</P>"
end tell
Evernote provides some good examples of using AppleScript on their developer site. You can also use xsltproc for some more systematic manipulation. I have a read-only example of using xslt via AppleScript in a recent post of mine. This above little snippet might be enough of an example to tell you how to set the HTML content.
But, to give you a better answer, I'd need to know a little more about how you want to manipulate your notes. The above example just grabs the first item in your current selection and sets the content.
I have an application that can load in third party code. One of the capabilities that the third party code can do is add formats in which the app can export to. I am using saveDocumentTo: as means for implementing export.
I understand that I can customize the menu of available filetypes to save in via overriding writableTypesForSaveOperation: for my document, but what doesn't work is that in the save dialog an appropriate file extension isn't added to the filename when selected from the menu.
I tried overriding fileNameExtensionForType:saveOperation: but that doesn't even get called.
How can I make the Save dialog find the correct file extension (provided it isn't known at compile time)?
I've done this within a custom export accessory view for the Save Panel. The custom export accessory view just changes the NSSavePanel's allowed file types whenever the user changes the format they want to export to.
If you want to set the extension, pass an array with one element containing that extension.
The docs have some important detail for -[NSSavePanel setAllowedFileTypes:]'s behavior in this regard, for supporting more complex cases:
Discussion
A file type can be a common file extension, or a UTI. A nil value indicates that any file type can be used. The default value is nil.
If no extension is given by the user, the first item in the allowedFileTypes will be used as the extension for the save panel. If the user specifies a type not in the array, and allowsOtherFileTypes is YES, they will be presented with another dialog when prompted to save.
NSOpenPanel: In versions of Mac OS X less than v10.6, this property is ignored. For applications that link against v10.6 and higher, this property determines which files should be enabled in the open panel. Using the deprecated methods to show the open panel (the ones that take a types: parameter) will overwrite this value, and should not be used. The allowed file types can be changed while the panel is running (for example, from an accessory view). The file type can be a common file extension, or a UTI. This is also known as the “enabled file types.” A nil value indicates that all files should be enabled.
You may also see dedicated export dialogs in some cases which can reduce the complexity of this if you have several distinct formats. As before, you just update the allowed file types to support this (not necessarily dynamically in this case).
After tinkering and modifying a GUI I have been working on for some time I ended up with a group of EditControllers and Radio Buttons that I do not need any more, so I would like to get rid of them. However, if I simply delete them from the GUI edit, I get assertion errors. How am I supposed to get rid of these elements?
You need to remove all code from your program that refers to the deleted controls. For each control you want to delete, take its ID and search the source for statements that refer to it.
Start like this:
Check the ID of that given control. Copy it. Now remove the control from dialog resource.
Ensure that ID is not used by other dialogs. If not, you can use following.
Delete that ID from resource.h.
When you compile it, you'd get error (around GetDlgItem, DDX_Control etc). Remove or comment them. Remove appropriate CWnd-derived variables (like CEdit, CComboBox etc).
You are done!
If given ID is used by other dialogs (check it from Resource View's context menu Resource Symbols...), then you cannot directly remove it from resource editor. You, however, need to remove it from appropriate implementation file (of CDialog/CPropertyPage-derived class).