Translating Illustrations: JXA or OmniJS, or something else entirely?


#21

Thanks for testing this, that sounds like an entirely reasonable explanation. Since exporting and closing worked flawlessly in my old Python/OSA code, I would assume that either this bug has been introduced recently, or Python is just so much slower that it never closed the document before it was fully exported.

I will test if simply delaying closing the document will resolve this until the bug is fixed.

Also I wish I had known this earlier, it would have saved me a lot of time in the last month I spent manually exporting stuff. Why did it take 5 weeks from the time I reported this bug as [OG #2166190], complete with the code and the test document, for a developer to look at this?

There’s another thing that needs to be addressed: if you want to get feedback from your customers, allow them to send you files: I tried to sent an email to support, complete with code, test documents and other files to follow up on my tests, but it bounced saying “For security reasons, Gmail does not allow you to use this type of file as it violates Google policy for executables and archives.” The forum also does not allow me to upload those files.


#22

Returning to the problem statement for OmniJS:

This is solved in the current test builds of OmniGraffle 7.11.

When I build a local debugging build of OmniGraffle, I’m able to connect to its JSContext from Safari and use its debugger. However, this doesn’t work for release builds. (This isn’t unique to OmniGraffle: I see the same behavior in other sandboxed apps like https://github.com/kasper/phoenix.git. If someone knows of a solution, I’d be happy to explore it.)

OmniGraffle autodetects changes to plugins.

It might be simpler to invoke your JavaScript directly from JXA, like this:

You might not need plugins at all, but if you do want to work with plugins it’s easiest if you can structure things to let you edit them in place without having to do some sort of publish cycle.

Symlinks can work for this, but because of sandboxing they won’t grant OmniGraffle access to any locations which it can’t already access. You can grant OmniGraffle access to additional locations by going into the Resource Browser and clicking on “Add an External Linked Folder” button at the bottom:

image

I don’t know that I agree with every one of Douglas Crockford’s recommendations, but I think the recommendations made by JSLint are a good starting point. But do listen to his warning:

JSLint will hurt your feelings. Side effects may include headache, irritability, dizziness, snarkiness, stomach pain, defensiveness, dry mouth, cleaner code, and a reduced error rate.

This is a big limitation which has not yet been solved in OmniJS for OmniGraffle. (It has been solved for OmniOutliner, but we made some compromises there which I don’t think we can make in the general case for OmniGraffle. But then again, those compromises are probably better than not being able to work with formatted text at all!)

If you need to work with formatted text from a script, your best bet for now would be to use AppleScript or JXA.


#23

I’m very sorry for the long delay in getting back to you on this bug. I’ve talked with our support team about this, and these sorts of issues should get escalated to engineering much more quickly in the future.

It sounds like you’re sending from Gmail and they’re blocking it? Gmail has nothing to do with our incoming email, and customers email file attachments to omnigraffle@omnigroup.com all the time (including zip files, OmniGraffle documents, scripts, etc.).

Sorry, that must a default setting on this forum software. I’ll investigate and see if we can get that sorted out.


#24

… or delay closing the file ;-)

  1. Some objects in the document can’t be accessed through JXA, again it’s all items in shared layers, but also some groups, tables and subgraphs

This problem is solved in the current v7.11 test builds.

Ok, I tested this already for OmniJS, will have to test for JXA.

  1. Sandboxing sometimes gets in the way of scripting, because OmniGraffle is not allowed to access documents. So I needs to manually open all files before running a script, which is really annoying.

The issue you’re running into here is that you’re passing OmniGraffle a string rather than a Path object. You need to use a Path so that the sandboxing system knows that your script has granted OmniGraffle access to the file in question. (Pre-opening the file is a workaround because opening the file also lets the sandboxing system know that it should grant OmniGraffle access to that file.)

If you use OmniGraffle.open(Path(file)) (much like you’re already doing in the to parameter to your export command), you’ll find it solves this issue.

Ah, that’s really good to know. Its there any documentation that mentions this?


#25

[quote=“kcase, post:23, topic:46128, full:true”]
I’m very sorry for the long delay in getting back to you on this bug. I’ve talked with our support team about this, and these sorts of issues should get escalated to engineering much more quickly in the future.

[quote]

cool

There’s another thing that needs to be addressed: if you want to get feedback from your customers, allow them to send you files: I tried to sent an email to support, complete with code, test documents and other files to follow up on my tests, but it bounced saying “For security reasons, Gmail does not allow you to use this type of file as it violates Google policy for executables and archives.”

It sounds like you’re sending from Gmail and they’re blocking it? Gmail has nothing to do with our incoming email, and customers email file attachments to omnigraffle@omnigroup.com all the time (including zip files, OmniGraffle documents, scripts, etc.).

It was indeed my google account that blocked this. I tested a bit, here’s what I found, because Omni will most likely run into this again:

Google appears to block any ZIP file with a JavaScript file in it. I tested a couple of Plugins, and also some other JavaScript files (e.g. reveal.js)

I guess that means nobody with a google account would be able to send you Omni-Plugins. Your support staff should be aware of that.

BTW, while testing this, I found that my email client (Airmail) automatically zips a plugin when I drag it into the client, so some people might even send a zip without their knowledge.

The forum also does not allow me to upload those files.

Sorry, that must a default setting on this forum software. I’ll investigate and see if we can get that sorted out.

Thanks.


#26

Apple’s documentation for JXA is a bit thin, but the release notes which introduce JXA do briefly mention this (though they just say “you will need”, they don’t describe why):

https://developer.apple.com/library/archive/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/Articles/OSX10-10.html#//apple_ref/doc/uid/TP40014508-CH109-SW31

Paths

When you need to interact with files, such as a document in TextEdit, you will need a path object, not just a string with a path in it. You can use the Path constructor to instantiate paths.

To get to the “why” background, you’d probably have to go back to the release notes for Lion (which introduced sandboxing) or Mountain Lion (which fixed a bunch of the scripting issues introduced by sandboxing).


#27

Thanks, that’s good to know! I’ll remind our support team that whenever customers have trouble emailing us a file (of any type or size), they can use https://upload.omnigroup.com/ to get those attachments to us instead.

I’ve updated our forum configuration to allow more file types. We’ll watch to see if that results in an increase in uploaded spam (which is, I believe, the reason for the default limits).


#28

This export bug should be fixed in r330884 or later. Thank you for alerting us to the problem! (A test build with this fix should be posted within the next hour or so.)


#29

Oh, until now I thought that was pretty much a standard feature of JavaScript Core. For details I can only refer you to some people who made it work: the guys at Bohemian Coding, who explain how to attach the Web Inspector to Sketch for debugging plugins, or maybe Jesse Grosjean of Hogbay Software, because I can use the Web Inspector for debugging Taskpaper Plugins (he even forgot a debugger statement in the code one time, which annoyed some users).

  1. Would I need to open/close omnigraffle whenever I change code in a plugin, or would it autodetect new or changed actions ?

OmniGraffle autodetects changes to plugins.

When I write the OmniJs API test plugin I tried that, it appeared to me this might not work entirely reliably. After a while I switched to manually reinstalling the plugin after each change. That helped.

  1. For my toolkit to process a number of OmniGraffle documents, it appears I would require a plugin, and trigger actions inside the plugin through Script Links (from a command line script or through a service), is that correct?

It might be simpler to invoke your JavaScript directly from JXA, like this:

A hello world document – testing omniJS code from JXA + text editor

Am I totally confused now, because I think that is exactly what the official documentation calls a Script Link?

  1. What is the best setup for developing and testing plugins? I can imagine a symlink inside the OmniGraffle plugins folder that points to a working copy, I could also clone the repo directly to the plugins folder (which would impose a certain structure on the repo), or I could “publish” to the plugins folder (e.g. with a makefile) whenever I change some code.

You might not need plugins at all, but if you do want to work with plugins it’s easiest if you can structure things to let you edit them in place without having to do some sort of publish cycle.

Symlinks can work for this, but because of sandboxing they won’t grant OmniGraffle access to any locations which it can’t already access. You can grant OmniGraffle access to additional locations by going into the Resource Browser and clicking on “Add an External Linked Folder” button at the bottom:

image

Oh, that is really helpful information. There’s still the bit where OmniGraffle appears to not reliably reload the plugin code (mentioned above), but I’ll test that again when I find the time to figure out what I did wrong.

  1. is there a specific coding style encouraged for plugins (the example code is a bit inconclusive here)?

I don’t know that I agree with every one of Douglas Crockford’s recommendations, but I think the recommendations made by JSLint are a good starting point. But do listen to his warning:

JSLint will hurt your feelings. Side effects may include headache, irritability, dizziness, snarkiness, stomach pain, defensiveness, dry mouth, cleaner code, and a reduced error rate.

Actually, the first thing I did when I started playing with JXA and OmniJS was set up ESLint. You can see the linter config in each of my repos (.eslintrc). I find linters an essential tool for any project, at least in the CI system. Don’t you use linters at Omni?

Also, when I get some text that is formatted, this formatting is lost.

This is a big limitation which has not yet been solved in OmniJS for OmniGraffle. (It has been solved for OmniOutliner, but we made some compromises there which I don’t think we can make in the general case for OmniGraffle. But then again, those compromises are probably better than not being able to work with formatted text at all!)

If you need to work with formatted text from a script, your best bet for now would be to use AppleScript or JXA.

I’m currently playing with extracting text from the XML directly.

I do understand that people want fine grained control over style of their text, but there is also a usecase for semantic markup, so I think in the long run OmniGraffle should support Markdown, (and maybe even HTML) for text, in addition to RTF, which is a pain for post processing, because there’s zero semantic information in it.

I know that RTF was simple to implement, but proper text (and object) styles would go a long way for working effectively with large collections in OmniGraffle. I would imagine a checkbox in the text inspector that activates Markdown/HTML instead of RTF, and a place to keep a document wide stylesheet. For my usecase - or indeed any translation usecase - that would be a tremendous step forward. Also would solve the problem you mentioned without any compromise.


#30

It appears that those apps are not sandboxed. I can trivially make it work in a non-sandboxed app, too—by simply doing nothing!—but it appears that this is automatically disabled when sandboxed apps are packaged for distribution.

Detecting changes to those files relies on the system’s file coordination APIs. Any well-behaved Mac text editor or synchronization service (e.g. iCloud, OmniPresence) will support this—but it won’t detect files which are updated behind the scenes without using file coordination.

If you keep that file open in Apple’s TextEdit app, does it automatically update with the changes you’re making? If so, that’s an indication that file coordination is happening properly.

Oh, sorry, did I link to the wrong thread? I guess I must have, because that thread has nothing to do with the .evaluateJavascript() call I was meaning to point you towards!

Here’s the post I meant to link:


#31

Will have to check that with the Appstore version of Taskpaper, I just use the regular non-appstore version.

Well, can’t you make a non-sandboxed app available to OmniJS developers? Probably deactivate the plugin update dialog, too?

When I write the OmniJs API test plugin I tried that, it appeared to me this might not work entirely reliably. After a while I switched to manually reinstalling the plugin after each change. That helped.
Detecting changes to those files relies on the system’s file coordination APIs. Any well-behaved Mac text editor or synchronization service (e.g. iCloud, OmniPresence) will support this—but it won’t detect files which are updated behind the scenes without using file coordination.

If you keep that file open in Apple’s TextEdit app, does it automatically update with the changes you’re making? If so, that’s an indication that file coordination is happening properly.

I use Sublime Text, so I think that’s not the problem, but I will test with TextEdit.

Am I totally confused now, because I think that is exactly what the official documentation calls a Script Link ?

Oh, sorry, did I link to the wrong thread? I guess I must have, because that thread has nothing to do with the .evaluateJavascript() call I was meaning to point you towards!

Here’s the post I meant to link:

Using Omnigraffle.evaluateJavascript()

Ah, that makes a lot more sense. Is it just my imagination that it’s interesting to debug OmniJS code that is more than a couple of lines, because the line number for errors in the console would carry an offset, if there’s line numbers at all.

Does .evaluateJavasScript() allow for call an action, or any other code that lives inside an OmniPlugin or Library?