Copying selected meta data from Safari front page

Following some discussion in another thread here is an illustrative macro, showing one way of using

  1. Execute JavaScript in Safari or Chrome, and then
  2. Execute JavaScript for Automation

To list a subset of metadata from the front page in Safari or Chrome, choosing and copying one or more items to the clipboard:

Safari or Chrome front page meta data - choosing and copying.kmmacros (26.8 KB)

Dependent Cartesian Closed Categories
Yamada, Norihiro
2017/04/16

The North Korea-Trump Nightmare
Nicholas Kristof
April 20, 2017

Some pages have more meta-data than we are likely to be interested in, so this macro shows a way of specifying sub-strings to look for in Meta tag names.

It also shows some basics of post-processing whatever is selected, using JavaScript for Automation.

Safari or Chrome JavaScript:

(() => {
    'use strict';

    // show :: a -> String
    const show = x => JSON.stringify(x, null, 2);

    const strKeys = document.kmvar.metaKeys || 'title author published date';

    return show(
        Array.from(document.querySelectorAll(
            strKeys.split(/\s+/)
            .map(k => 'meta[name*="' + k + '" i]')
            .join(', ')
        ))
        .reduce((a, x) => {
            const
                k = x.name,
                prev = a[k],
                v = x.content;
            return (a[k] = (prev ? prev + ', ' + v : v), a);
        }, {})
    );
})();

JavaScript for Automation:

(function () {
    'use strict';

    // show :: a -> String
    const show = x => JSON.stringify(x, null, 2);

    var kme = Application('Keyboard Maestro Engine'),
        dct = JSON.parse(kme.getvariable('metaJSON')),
        dks = Object.keys(dct),
        // keyValue pairs in the 'metaKeys' KM variable order
        lstKV = kme.getvariable('metaKeys')
        .split(/\s+/)
        .reduce((a, k) => {
            const lk = k.toLowerCase();
            return a.concat(
                dks.reduce((b, x) =>
                    x.toLowerCase()
                    .indexOf(lk) !== -1 ? b.concat(
                        [
                            [x, dct[x]]
                        ]
                    ) : b, [])
            )
        }, []);

    return lstKV.length === 0 ? '' : function () {
        var a = Application.currentApplication(),
            se = Application("System Events"),
            sa = (se.includeStandardAdditions = true, se),
            delim = ' -> ',
            kvs = lstKV.map(function (kv) {
                return kv.join(delim);
            }),
            varChoice = (sa.activate(), se.chooseFromList(kvs, {
                withTitle: kme.getvariable('browserName') +
                    ' page metadata',
                withPrompt: 'Cmd-click for multiple selections',
                defaultItems: [kvs[0]],
                okButtonName: 'OK',
                cancelButtonName: 'Cancel',
                multipleSelectionsAllowed: true,
                emptySelectionAllowed: true
            }));

        return (
            a.activate(),
            varChoice !== false ? varChoice.map(function (s) {
                return s.split(delim)[1];
            })
            .join('\n') : ''
        );
    }();
})();

Added i for case-insensivity to the CSS selector in the Safari JS code above, so that (for example) date will also harvest META names like pubDate

Make like a leaf: How copying photosynthesis can change society | New Scientist
anna azvolinsky
2017-04-11

Worked as advertised. This will be great for the non-typical sources I use, beyond the custom KM macros I’ve created - that to your help and JMichaelTX - for the WSJ, NYT, Bloomberg, etc.

Thanks again.

1 Like

Slightly updated above – better handling for duplicated tag names (now appends additional authors etc) and added hdl to the key patterns, for NYT headlines.

Thanks for sharing, Rob. This could be very useful. :+1:

BTW, I was surprised to find that your macro/scripts ran fine in:
Safari 10.1 (11603.1.30.0.34) on macOS 10.11.6

I was expecting to have to convert the ES6 JavaScript to ES5, but was pleasantly surprised.

I am surprised that you expected that :slight_smile:

(I think we had that conversation before – SF 10 JavaScript is ES6 compliant. The (SF9) scripting JS Context of the macOS 10 on which SF is running there is not connected or relevant to the browser’s own (SF10) JS Context)

I'm sure we did. :wink:

It's been a confusing subject to me, but maybe now it is beginning to clear up:

When running Safari 10.1 (11603.1.30.0.34) on macOS 10.11.6:

  • We can use all features of ES6 when using JavaScript in Safari, because Safari 10 is fully ES6 compliant.
  • However, when running JavaScript for Automation (JXA) in the Script Editor, we are limited to the ES6 features supported by the core macOS JavaScript used in El Capitan (10.11), which is Safari 9.

If I misstated anything, please feel free to correct me.

Do you know if Google Chrome 57.0.2987.133 (2987.133) on macOS 10.11.6 is fully ES6 compliant when running JavaScript in Chrome?

That’s right.

Safari’s JS Context version is not affected by the macOS platform it runs on.

  • Sierra’s JavaScript for Automation uses an SF10 JS Context.
  • Earlier JXAs are embeddings of an SF9 JS Context.

For the specifics of ES6 compliance, the reference is, as ever:
http://kangax.github.io/compat-table/es6/

That table used to have an SF9 column as well as an SF10 column. The former has effectively been relabelled ‘JXA’ now, as JavaScript for Automation on pre-Sierra systems is the main remaining niche of the old SF9 JavaScript Interpreter.

(For the real ES6 compatibility of Sierra JXA, look instead at the SF10 column)

The JS interpreter which will execute code submitted by KM’s Execute JS in Chrome action also depends on the version of Chrome which you are running, and not on the version of macOS, KM etc.

For Chrome version ES6 compatibilities, see, again:

http://kangax.github.io/compat-table/es6/

CH 57-59 haven’t implemented tail recursion optimisation, but otherwise they look syntactically complete for ES6.

Thanks.

If I am understanding this properly the ES6 Tail Position Calls optimization is the only feature not implemented in Chrome 57+.

Worthy of note, is that this is NOT a syntax difference, but simply an interpreter optimization difference. Based on my very limited understanding of ES6 Tail Call Optimization Explained, this seems like a minor issue to me, certainly not likely to come up with my code.

So, from a syntax POV, Chrome 57+ is 100% ES6 compliant.
Thus, any JavaScript in Browser scripts that I write should work well in both Chrome and Safari.

(As long as they don’t go ahead with pulling the rug on JS injection – I haven’t looked recently to see what became of that story)

Chrome has generally been more flexible than Safari. Hopefully if Google does go ahead with restricting JavaScript injection, they will provide a preference setting to allow it (like Safari).

( I've generalised the macro (in the original post) to work with Chrome as well as Safari )


UPDATE
and updated it again to preserve the same field order (in menu and clipboard), as the user-edited metaKeys variable in the macro.

Thanks for the update to include Chrome.

Unfortunately, now I'm getting an error when using either Safari or Chrome:
Safari 10.1 (11603.1.30.0.34) on macOS 10.11.6
Chrome 57.0.2987.133 (2987.133)

script error: Error on line 5: SyntaxError: Unexpected keyword 'const'. Const declarations are not supported in strict mode. (-2700)

I'm not familiar with the const syntax, so I'm not sure how to fix.
Suggestions?


**EDIT:  2017-04-20  1:29 PM CT**

I took the easy way out and used https://babeljs.io/repl/ to convert your JXA script to ES5.  Seems to work OK now.