Working with the Basics

I read the developer documentation and created the Hello World example which ran as expected — excellent!

However, when I tried to use the provided URL example code, it failed to work as indicated. Is this a known issue or am I missing something?

<!DOCTYPE html>
<html>
	<body>
 		<a href="" onclick="craft.editorApi.openUrl('http://craft.do'); return false">CRAFT</a>
	</body>
</html>

Cheers!

Sal Soghoian

I also tried using the Hello World code adapted with the openURL command, but it fails as well:

<!DOCTYPE html>
<html>
  <body>
    <button id="btn-execute">Omni Automation</button>
    <script>
      const button = document.getElementById("btn-execute")

      button.addEventListener("click", async () => {
        await craft.editorApi.openUrl('https://omni-automation.com')
      })
    </script>
  </body>
</html>

I tried adapting the Hello World example to use the SpeechSynthesis JavaScript class and it failed as well. Not sure why.

<!DOCTYPE html>
<html>
	<body>
		<button id="btn-execute">Greet</button>
		<script>
			const button = document.getElementById("btn-execute")

			button.addEventListener("click", async () => {
				const utterance = new SpeechSynthesisUtterance("Hello world!");
				speechSynthesis.speak(utterance);
			})
		</script>
	</body>
</html>

My gut feeling would be that the craft object or speech Synthesis Class aren’t loaded in this case. If you can send over your full code in Zip we can further analyse?

How do I send the zips to you? Can I post here?

Craft-Extensions.zip (139.2 KB)

Thank you! Here are the two examples I posted.

Hey, I fixed the documentation.

It should be: with openURL not openUrl:
<a href="" onclick="craft.editorApi.openURL('http://craft.do'); return false">CRAFT</a>

How about that? Thank you, that works.

Any ideas as to why the Speech classes aren’t part of the loaded JavaScript?

Here is an example of combining the use of Omni Automation with Craft extensions to create a new task instance in OmniFocus:

<!DOCTYPE html>
<html>
  <body>
    <button id="btn-execute">Omni Automation</button>
    <script>
      const button = document.getElementById("btn-execute");

      button.addEventListener("click", async () => {
		// CREATE/SEND OMNI AUTOMATION SCRIPT URL
		// DOCUMENTATION: https://omni-automation.com/script-url/index.html

		// FUNCTION TO BE EXECUTED BY OMNIFOCUS
		function newOmniFocusTask(taskName){
			tsk = new Task(taskName)
			URL.fromString(`omnifocus://task/${tsk.id.primaryKey}`).open()
		}
		
		// CREATE FUNCTION AND CONTENT STRINGS
		contentString = JSON.stringify("My New Task");
		encodedContent = encodeURIComponent(contentString);
		functionString = newOmniFocusTask.toString();
		encodedFunction = encodeURIComponent(functionString);

		// CREATE SCRIPT URL
		url = 'omnifocus://localhost/omnijs-run?script=' +
		'%28' + encodedFunction + '%29' +
		'%28' + 'argument' + '%29' +
		'&arg=' + encodedContent
      
      	// EXECUTE THE URL
        await craft.editorApi.openURL(url);
      });
    </script>
  </body>
</html>
1 Like

Because security is always a primary concern, the first run of an external URL will require explicit approval by the user. If you select the automatic execution checkbox in the security approval dialog, the script will no longer require approval.

Here is the extension file:
of-new-task.craftx.zip (69.5 KB)

1 Like

re: Speech Recognition: I do not know the answer to. Interestingly It works in Safari for me in the Web Editor :thinking:

This might be relevant (though not an answer :confused:)

Suggests there might be a permission issue in MacOSx that is not there in web speech use.

This might be the answer:

https://talkrapp.com/speechSynthesis.html

(read down past the list of voices)

Speech synthesis has to be user initiated and will not autorun.

“The end result is that you can only play text to speech when the user clicked on something to initiate the action.” There’s some suggested code to help deal with this.

Things are never easy!

1 Like

How to get the actual text string from the selection? I’m getting undefined from this code:

result = await craft.editorApi.getTextSelection()
if (result.status !== "success") {
	throw new Error(result.message)
}
selectedText = result.data

The result of craft.editorApi.getSelection() returns an array of data objects describing the selected blocks, like this:

[{"id":"F3020F5C-8B30-43F0-B679-74C13BDD62DD","hasBlockDecoration":false,"color":"text","indentationLevel":0,"spaceId":"859c432e-33f3-7983-7c20-67a12bd618aa","subblocks":[],"content":[{"isItalic":false,"isStrikethrough":false,"text":"HOW NOW BROWN COW","isCode":false,"isBold":false}],"type":"textBlock","listStyle":{"type":"none"},"documentId":"A189DCF5-E6AC-4ADB-B451-2E666CA6A07F","style":{"fontStyle":"system","alignmentStyle":"left","textStyle":"body"},"hasFocusDecoration":false}]
However, attempts to extract the resulting text fail and return undefined:

result = await craft.editorApi.getSelection()
result.data[0]["text"] <-- fail
result.data[0].text <-- fail

What is the “magic syntax" to get the text of the selected block? Thanks!

Ah. There are two “text” keys:

blockID = passedData[0].id
blockText = passedData[0].content[0].text

Getting closer…

Here’s a fully working Craft extension that creates a new task in OmniFocus using the text of the first selected block. The OmniFocus task note will contain a link-back to the block in the Crafts document.

of-new-task.craftx.zip (70.0 KB)

<!DOCTYPE html>
<html>
	<body>
		<button id="btn-execute">OmniFocus Task with Block</button>
		<p>This Crafts extension will create a new Task in OmniFocus using the text data of the first selected block. The OmniFocus task note will contain a link-back to the block in the Crafts document.</p>

		<script>
			// CREATE/SEND OMNI AUTOMATION SCRIPT URL
			// DOCUMENTATION: https://omni-automation.com/script-url/index.html

			const button = document.getElementById("btn-execute");
			
			button.addEventListener("click", async () => {
				try {
					// GET THE SELECTED TEXT
					result = await craft.editorApi.getSelection()
					if (result.status !== "success") {
						throw new Error(result.message)
					} else {
						var selectedBlockData = result.data
					}

					if(selectedBlockData !== ""){
						// FUNCTION TO BE EXECUTED BY OMNIFOCUS
						function newOmniFocusTask(passedData){
							console.log(passedData)
							blockID = passedData[0].id
							spaceID = passedData[0].spaceId
							documentID = passedData[0].documentId
							blockType = passedData[0].type
							blockText = passedData[0].content[0].text
							if (blockText.length > 24){
								taskTitle = blockText.substring(0, 24) + "..."
							} else {
								taskTitle = blockText
							}
							linkURL = `craftdocs://open?blockId=${blockID}&spaceId=${spaceID}`
							tsk = new Task(taskTitle)
							tsk.note = linkURL + "\n\n" + blockText
							URL.fromString(`omnifocus://task/${tsk.id.primaryKey}`).open()
						}
		
						// CREATE FUNCTION AND CONTENT STRINGS
						contentString = JSON.stringify(selectedBlockData)
						encodedContent = encodeURIComponent(contentString)
						functionString = newOmniFocusTask.toString()
						encodedFunction = encodeURIComponent(functionString)

						// CREATE SCRIPT URL
						url = 'omnifocus://localhost/omnijs-run?script=' +
						'%28' + encodedFunction + '%29' +
						'%28' + 'argument' + '%29' +
						'&arg=' + encodedContent
	  
						// EXECUTE THE URL
						await craft.editorApi.openURL(url)
					} else {
						throw new Error("No text is selected.")
					}
				}
				catch(err){
					throw `${err.name}\n${err.message}`
				}
			});
		</script>
	</body>
</html>
1 Like

And here’s what a new task looks like in OmniFocus:

1 Like

Here’s an updated archive. This version has a formatted description and button:

of-new-task.craftx.zip (70.2 KB)

image

1 Like