JXA To Grab The Title & Link From Safari & Place Those At The Top Of The Links: Project In Taskpaper

Hello all!

I have a script that grabbed the title and link of the active page in Safari and then placed those into a Links: project in TaskPaper. If the Links: project doesn't currently exist, it is created before the data is added as a task.

It was a bit of a Frankenstein script (using AppleScript, JavaScript and a Keyboard Maestro variable). It worked, but my inner coder wanted to improve it. I wanted to rewrite it to make it tighter and to help me learn more JavaScript.

Now, with the help of the amazing @JMichaelTX and the genius Jesse at TaskPaper, it is a tight and pure JavaScript macro. I had many hurdles to get through this, and both J. Michael and Jesse were inspirational throughout. Kudos!

In case this is of interest to any TaskPaper users here, below is the code. Simply place it into a Execute JavaScript For Automation action in your macro

I love this script, and I get a little thrill each time I run it. Enjoy!

'use strict';

var app = Application.currentApplication()
app.includeStandardAdditions = true

var safariApp = Application("Safari");

var SafDoc = safariApp.documents[0];
var varTitle = SafDoc.name();
var varURL = SafDoc.url();

var varTask = "- " + varTitle + " → " + varURL;

function TaskPaperContext(editor, options) {
	let outline = editor.outline
	let project = outline.evaluateItemPath('/project Links')[0]
	if (project == null) {
		project = outline.createItem('Links:')
		outline.root.insertChildrenBefore([project], outline.root.firstChild)
	}
		project.insertChildrenBefore(
			outline.createItem(options.url),
			project.firstChild
	)
}

Application('TaskPaper').documents[0].evaluate({
  script: TaskPaperContext.toString(),
  withOptions: { url: varTask },
});
1 Like

The insightful @ComplexPoint suggested that I stop using "Var" as it is deprecated. I have changed my var's to const (as my variables to not change) and it works well. Here is the updated script:

'use strict';

const app = Application.currentApplication()
app.includeStandardAdditions = true

const safariApp = Application("Safari");

const SafDoc = safariApp.documents[0];
const varTitle = SafDoc.name();
const varURL = SafDoc.url();

const varTask = "- " + varTitle + " → " + varURL;

function TaskPaperContext(editor, options) {
	let outline = editor.outline
	let project = outline.evaluateItemPath('/project Links')[0]
	if (project == null) {
		project = outline.createItem('Links:')
		outline.root.insertChildrenBefore([project], outline.root.firstChild)
	}
		project.insertChildrenBefore(
			outline.createItem(options.url),
			project.firstChild
	)
}

Application('TaskPaper').documents[0].evaluate({
  script: TaskPaperContext.toString(),
  withOptions: { url: varTask },
});
1 Like

I challenge that assertion. I have NOT seen any evidence of this.
@ComplexPoint wants to use const for everything. I also disagree with this.

There is nothing wrong with using var. There are millions and millions of lines of JavaScript code that use it. So I don't see how it would be possible to remove use of var from JavaScript.

See

1 Like

Thank you all! You have given me a lot to think about! Kudos!

: -)

There's a discussion of the scoping complexities of var in Eloquent JavaScript, a widely read introduction to JS, which makes no use of var, and explains why.

New users of JS who who come in through the first 9 chapters of Eloquent JavaScript may be puzzled to see var being used in new code.

There's also a helpful discussion of the difference between let and var on Stack Overflow here:

javascript - What's the difference between using "let" and "var"? - Stack Overflow

and on Software Engineering Stack Exchange here:

javascript - Is there any reason to use the "var" keyword in ES6? - Software Engineering Stack Exchange

Ken Case recently gave a good account (on the OmniGroup Slack channel) of why it works better to use constants by default, and to avoid mutation by using a new name when you create a new value. The Omni-Automation site did initially use var examples, but Sal S has recently announced that they have started working through the site examples to update and fix that problem.

Const makes a good default because while a significant proportion of bugs have their origin in var, an even higher proportion of bugs are rooted in mutation of the reference of names.

const helpfully warns us of any attempt to mutate meaning of a name, providing free protection against redundant complexity.

(const also happens to provide the simplest and fastest binding of a value to a name, in case you ever find yourself having to chase performance, for any reason).

On the rare occasions when mutation is useful, let gives the simplest behaviour and the richest messages.

There is certainly a lot of legacy code from the days when only var was available, but that doesn't make it a good choice for new code.

In the context of desktop scripting, debugging time can be reduced very significantly by reducing the number of states that a piece of code can get into. const provides a very helpful way of locking complexity down.

Ever since the Douglas Crockford 'JS – the good parts' book and talks, it's been widely understood that JS has a complex and uneven history, and that life can be simplified, and code improved, by sticking to a good working subset of what it offers.

var has left that subset now – there are more helpful alternatives.

You can find Crockford's own explanation of why not var, (and why mainly const rather than let) 26:9 minutes into his 'Good Parts' talk

The Better Parts by Douglas Crockford at Silicon Valley Code Camp - YouTube

There's absolutely no reason for JMichaelTX to stop using var in his own code, but there may be reasons if:

  • You want to keep to an idiom that will be familiar to new users coming in through Eloquent JavaScript,
  • or you simply want to minimize script-state complexity and, above all, debugging time.

My statement referred to the deprecation of var, NOT whether or not there are other, and perhaps better, declarations to use.

If you review the reference for var - JavaScript -- Mozilla.org, which is accepted my many has being the standard, JavaScript, reference, it makes NO reference to that statement as being "deprecated".

JavaScript var declaration has been used for decades on millions of web pages, and continues to be used today. The very recent const and let do offer some advantages, but are NOT required.

I would think that all students of JavaScript should be very familiar with var since they will undoubtedly encounter it in lots of existing JavaScript code.

For simple scripts, I think var is fine. For longer, more complicated scripts, then you may want to take advantage of const (JavaScript | MDN) and let (JavaScript | MDN).

In the case of JavaScript, which doesn't have a single unique supplier, you won't see single ex cathedra pronouncements of deprecation – there's no one who could give them.

Deprecrations in a language like JS emerge over time as a consensus among professional users of the various browsers and JS interpreters.

Douglas Crockford's position is far from papal – there is no church hierarchy for JS, and ECMA only defines what is parseable – not what is recommended, though Crockford's authorship of the Good Parts, and the first draft of the JSON standard, do make him an interesting voice to listen to.

More eloquent, and more practically helpful, are the widely used linters.

The linters that people are regularly using provide:

  • a very eloquent index of where the consensus on particular deprecations has got to at any given time,
  • and a practical, low cost-way of learning and keeping to a well-tested and well-curated subset of the language.

If you look at ESlint for example, the no-var rule was introduced in version 0.12.0.

[no-var - ESLint]( https://eslint.org/docs/rules/no-var )