'use strict';
const GLib = imports.gi.GLib;
/**
* The same regular expression used in GNOME Shell
*
* http://daringfireball.net/2010/07/improved_regex_for_matching_urls
*/
const _balancedParens = '\\((?:[^\\s()<>]+|(?:\\(?:[^\\s()<>]+\\)))*\\)';
const _leadingJunk = '[\\s`(\\[{\'\\"<\u00AB\u201C\u2018]';
const _notTrailingJunk = '[^\\s`!()\\[\\]{};:\'\\".,<>?\u00AB\u00BB\u201C\u201D\u2018\u2019]';
const _urlRegexp = new RegExp(
'(^|' + _leadingJunk + ')' +
'(' +
'(?:' +
'(?:http|https)://' + // scheme://
'|' +
'www\\d{0,3}[.]' + // www.
'|' +
'[a-z0-9.\\-]+[.][a-z]{2,4}/' + // foo.xx/
')' +
'(?:' + // one or more:
'[^\\s()<>]+' + // run of non-space non-()
'|' + // or
_balancedParens + // balanced parens
')+' +
'(?:' + // end with:
_balancedParens + // balanced parens
'|' + // or
_notTrailingJunk + // last non-junk char
')' +
')', 'gi');
/**
* sms/tel URI RegExp (https://tools.ietf.org/html/rfc5724)
*
* A fairly lenient regexp for sms: URIs that allows tel: numbers with chars
* from global-number, local-number (without phone-context) and single spaces.
* This allows passing numbers directly from libfolks or GData without
* pre-processing. It also makes an allowance for URIs passed from Gio.File
* that always come in the form "sms:///".
*/
let _smsParam = "[\\w.!~*'()-]+=(?:[\\w.!~*'()-]|%[0-9A-F]{2})*";
let _telParam = ";[a-zA-Z0-9-]+=(?:[\\w\\[\\]/:&+$.!~*'()-]|%[0-9A-F]{2})+";
let _lenientDigits = '[+]?(?:[0-9A-F*#().-]| (?! )|%20(?!%20))+';
let _lenientNumber = _lenientDigits + '(?:' + _telParam + ')*';
var _smsRegex = new RegExp(
'^' +
'sms:' + // scheme
'(?:[/]{2,3})?' + // Gio.File returns ":///"
'(' + // one or more...
_lenientNumber + // phone numbers
'(?:,' + _lenientNumber + ')*' + // separated by commas
')' +
'(?:\\?(' + // followed by optional...
_smsParam + // parameters...
'(?:&' + _smsParam + ')*' + // separated by "&" (unescaped)
'))?' +
'$', 'g'); // fragments (#foo) not allowed
var _numberRegex = new RegExp(
'^' +
'(' + _lenientDigits + ')' + // phone number digits
'((?:' + _telParam + ')*)' + // followed by optional parameters
'$', 'g');
/**
* Searches @str for URLs and returns an array of objects with %url
* properties showing the matched URL string, and %pos properties indicating
* the position within @str where the URL was found.
*
* @param {string} str - the string to search
* @returns {object[]} - the list of match objects, as described above
*/
function findUrls(str) {
_urlRegexp.lastIndex = 0;
let res = [], match;
while ((match = _urlRegexp.exec(str))) {
let name = match[2];
let url = GLib.uri_parse_scheme(name) ? name : `http://${name}`;
res.push({name, url, pos: match.index + match[1].length});
}
return res;
}
/**
* Return a string with URLs couched in tags, parseable by Pango and
* using the same RegExp as GNOME Shell.
*
* @param {string} str - The string to be modified
* @param {string} [title] - An optional title (eg. alt text, tooltip)
* @return {string} - the modified text
*/
function linkify(str, title = null) {
let text = GLib.markup_escape_text(str, -1);
_urlRegexp.lastIndex = 0;
if (title) {
return text.replace(
_urlRegexp,
`$1$2`
);
} else {
return text.replace(_urlRegexp, '$1$2');
}
}
/**
* A simple parsing class for sms: URI's (https://tools.ietf.org/html/rfc5724)
*/
var SmsURI = class URI {
constructor(uri) {
_smsRegex.lastIndex = 0;
let [, recipients, query] = _smsRegex.exec(uri);
this.recipients = recipients.split(',').map(recipient => {
_numberRegex.lastIndex = 0;
let [, number, params] = _numberRegex.exec(recipient);
if (params) {
for (let param of params.substr(1).split(';')) {
let [key, value] = param.split('=');
// add phone-context to beginning of
if (key === 'phone-context' && value.startsWith('+')) {
return value + unescape(number);
}
}
}
return unescape(number);
});
if (query) {
for (let field of query.split('&')) {
let [key, value] = field.split('=');
if (key === 'body') {
if (this.body) {
throw URIError('duplicate "body" field');
}
this.body = (value) ? decodeURIComponent(value) : undefined;
}
}
}
}
toString() {
let uri = 'sms:' + this.recipients.join(',');
return (this.body) ? uri + '?body=' + escape(this.body) : uri;
}
};