I can’t seem to open a URL from a scrip

Hi, I made a script that helps me to open a url when using the “link” format.

- [Title] (URL)

But when I use the app.openURL(); it reruns false, any advice, or anything I did wrong, here’s my code.

var errorCode = 0;
var error = {
  0:"Ningun error",
  2001:"No se encontro el formato de Link \"- []()\"",
  1001:"Error al abrir el URL"
};

let f = () => {
  var line = editor.getSelectedLineRange();
  let texto = editor.getText();

  line = texto.substr(line[0], line[1]);
  var urlStartPosition = line.search("]");

  if (urlStartPosition == -1){errorCode = 2001; return false;}
  
  let url = line.substr(urlStartPosition + 2, line.length - 3 - urlStartPosition);
  alert(url);
  let success = app.openURL(url);
  if (!success) {errorCode = 1001; return false;}
  
  return true;
}

if (!f()){app.displayErrorMessage("Codigo de error " + errorCode + ": " + error[errorCode]);}

Just tried running the script with my cursor on a line like this:

- [BBC](https://www.bbc.co.uk)

It opened the BBC home page fine with no error.

What draft content are you running this against?

I tried running it against

- [Google](www.google.com)
- [OneNote](onenote://open)

None of them open, even though they do work in safari.

Could the problem be that my iPad is running iOS 12.4.5?

Sorry, but seems like app.openURL(url) needs url to start with:
http:// or https://

Try:

let url = line.substr(urlStartPosition + 2, line.length - 4 - urlStartPosition); 

or

  let url = '';
  // Use RegEx match to extract url from a line instead
  m = line.match(/\[.*?\]\((.+?)\)/)
  if (m) {
    url = m[1];
  }

And here is an action opening all urls in a draft in one go:
https://actions.getdrafts.com/a/15m

1 Like

Without a protocol, something like www.google.com is just a domain not a URL. I imagine logic could be applied like in a browser or even as from link mode, to default something in, but I think Markdown links also strictly require protocols so it would be best to add them in anyway.

I think that the various protocols have to be registered. For example app.openURL("omnifocus://"); works fine for me, opening OmniFocus, but does not begin http(s)://.

1 Like

You are right,
And from testing, it looks like the clue is:

if not http(s):// then someapp:// (colon double slash included) has to be part of the url, and someapp has to be an installed x-callback-url app.

(I deleted the question to @agiletortoise in my post above:)

Also a wrong url in correct format will not trigger an error in app.openURL(), an error will then only be displayed in Safari. (Like: ‘http://www.gogle.con’)

@Zrapata here is a modified code that should work.
It ads http:// to a ‘domain’ where this is missing, like ‘www.google.com

It also extracts the first markdown link anywhere on a line mixed with other text.

// Open URL on Line
// 2020-03-23 at 07:14

let f = () => {
  var line = editor.getSelectedLineRange();
  let texto = editor.getText();

  line = texto.substr(line[0], line[1]);
  
  let url = '';
  m = line.match(/\[.*?\]\((.+?)\)/)
  if (m) {
    url = m[1];
    if (!url.match(/:\/\//)) {
      url = 'http://' + url;
    }
  }
  // alert(url);

  let success = app.openURL(url);
  if (!success) {errorCode = 1001; return false;}
  
  return true;
}

var errorCode = 0;
var error = {
  0:"Ningun error",
  2001:"No se encontro el formato de Link \"- []()\"",
  1001:"Error al abrir el URL"
};

if (!f()) {
  app.displayErrorMessage("Codigo de error " + errorCode + ": " + error[errorCode]);
}

/*
Test data:
- [Google](www.gogle.com) this is famous search engine
- text before [Bear](bear://) and text after
- [text in brackets, no problem] [OneNote](onenote://open)
- [Google](www.gogle.com)
- [BBC](www.bbc.co.uk)
*/

1 Like

Per the docs:

opens URL passed using iOS. Returns true if URL was opened, false if the URL was invalid or no available app can open the URL on the device.

As noted www.google.com is not a valid URL. Other common causes of a false return value would be something errant in the string passed (like line feed or spaces) that make it an invalid URL.

1 Like

Shouldn’t need to be x-callback-url specially for this use case, just match the registered URL scheme.

1 Like

Thanks. Yes, that’s sounds better :sunglasses:

I now can do it, thanks for all your help

1 Like

Inspired by @FlohGro I updated my “Open All URLs” To be more flexible with a list of URLs to chose from. Also realized that open all links at once only works on Mac, so included button “Open All” on Mac only.

Please modify as you please :nerd_face:

does anyone know why this might work on an iPhone but not on Mac? I’m still running Mojave so maybe there’s a Catalina only thing going on? here’s the error I get on Mac:

Script Error: TypeError: text.matchAll is not a function. (In 'text.matchAll(re)', 'text.matchAll' is undefined)
Line number: 17, Column 32

@derekvan What version of Drafts are you running?

PS.
It would also be helpful to see the complete script.
Could you please paste it here?

Drafts 19.1 on Mojave 10.14.6

Script:

// Open URLs in Draft
// RV 2020-04-07 at 10:19

// Opens all URL md-links in a draft

// Alt. 1: If you have Markdown links:
let re = /\[(.*?)\]\((.+?)\)/g;
let pos = 2;

// // Alt. 2: Plain URLs, simplified pattern, `http(s)//` required!:
// let re = /(https?:\/\/)([a-z0-9]{3,40}\.)+[a-z]{2,6}[^ \t\n\(\)'";:]*/gi;
// let pos = 1;

(() => {
  
  let text = draft.content;
  let links = [...text.matchAll(re)]; // convert to array
  
  if (links.length == 0) {
    app.displayInfoMessage('No markdown links found!');
    return;
  } else if (links.length == 1) {
    openURL(links[0][pos]);
  } else {
    selectURLs(links);
  }
})()

function selectURLs(links) {
  let p = Prompt.create();
  p.title = 'URLs in current draft';
  p.message = 'Select URL to open:';
  
  if (device.systemName == 'macOS') {
    // Open all URL's (on Mac only)
    p.addButton('Open All URLs', -1);
  }
  
  let i = 0;
  for (let link of links) {
    let title = link[1];
    if (title == '') {
      title = link[pos];
    }
    p.addButton(title, i);
    i++;
  }
  
  if (!p.show()) {
    context.cancel('canceled by user');
    return;
  }
  
  i = parseInt(p.buttonPressed);
  if (i == -1) {
    for (const link of links) {
      // Open all URL's (on Mac only)
      openURL(link[pos]);
    }
  } else {
    openURL(links[i][pos]);
  }
}

function openURL(url) {
	if (!url.match(/:\/\//)) {
	  url = 'http://' + url;
	}
  // try {
  //   let result = app.openURL(url, false);
  // } catch(err) {
  //   app.displayErrorMessage(err.message + ': ' + url);
  // }
  
  let result = app.openURL(url, false)
  if (result) {
  		return true;
  } else {
    app.displayErrorMessage('Invalid: ' + url);
    return false;
  }
}


Hm,
Works fine on my MBP with Catalina,

so my guess is that Drafts on Mojave runs an older version of JavaScriptCore that maybe does not include matchAll()?

Or the culprit is the three dots ... ‘spread operator’ introduce in ES2018?

What do you think, @agiletortoise ?

JavaScriptCore is a system framework, so, yes, it is updated and changes overtime, and Drafts uses whatever version of it that is available on the system.

Generally, I would recommend sticking to ES6 language constructs for best compatibility.

@RoyRogers - thanks for your Open All URLs action!

When I run it with the markdown option, it works perfectly.

When I run it with the bare url option, I can’t get it to work—it seems to be passing only https:// to the browser, regardless of whether I’m on macOS or iOS. Any ideas?