diff --git a/api/etemplate.php b/api/etemplate.php
index 5d12ce9ced..ddff2cd431 100644
--- a/api/etemplate.php
+++ b/api/etemplate.php
@@ -13,7 +13,8 @@
use EGroupware\Api;
// add et2- prefix to following widgets/tags
-const ADD_ET2_PREFIX_REGEXP = '#<((/?)([vh]?box|textbox|textarea|button|colorpicker|description))(/?|\s[^>]*)>#m';
+const ADD_ET2_PREFIX_REGEXP = '#<((/?)([vh]?box|textbox|textarea|button|colorpicker|description|url(-email|-phone|-fax)?))(/?|\s[^>]*)>#m';
+const ADD_ET2_PREFIX_LAST_GROUP = 5;
// switch evtl. set output-compression off, as we cant calculate a Content-Length header with transparent compression
ini_set('zlib.output_compression', 0);
@@ -152,7 +153,8 @@ function send_template()
{
return '<' . $matches[2] . 'et2-' . $matches[3] .
// web-components must not be self-closing (no "", but "")
- (substr($matches[4], -1) === '/' ? substr($matches[4], 0, -1) . '>';
+ (substr($matches[ADD_ET2_PREFIX_LAST_GROUP], -1) === '/' ? substr($matches[ADD_ET2_PREFIX_LAST_GROUP], 0, -1) .
+ '>';
}, $str);
// handling of date and partially implemented select widget (no search or tags attribute), incl. removing of type attribute
@@ -175,14 +177,6 @@ function send_template()
return $matches[0];
}, $str);
- // add et2- prefix to url widget, as far as it is currently implemented
- $str = preg_replace_callback('##', static function($matches)
- {
- if (strpos($matches[2], 'readonly="true"')) return $matches[0]; // leave readonly alone for now
- return str_replace('';
- }, $str);
-
$processing = microtime(true);
if(isset($cache) && (file_exists($cache_dir = dirname($cache)) || mkdir($cache_dir, 0755, true)))
diff --git a/api/js/etemplate/Et2Url/Et2Url.ts b/api/js/etemplate/Et2Url/Et2Url.ts
new file mode 100644
index 0000000000..3d3fbf6342
--- /dev/null
+++ b/api/js/etemplate/Et2Url/Et2Url.ts
@@ -0,0 +1,64 @@
+/**
+ * EGroupware eTemplate2 - Url input widget
+ *
+ * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
+ * @package api
+ * @link https://www.egroupware.org
+ * @author Ralf Becker
+ */
+
+/* eslint-disable import/no-extraneous-dependencies */
+import {Et2InvokerMixin} from "./Et2InvokerMixin";
+import {IsEmail} from "../Validators/IsEmail";
+import {Et2Textbox} from "../Et2Textbox/Et2Textbox";
+
+/**
+ * @customElement et2-url
+ *
+ * @ToDo: implement allow_path and trailing_slash attributes
+ */
+export class Et2Url extends Et2InvokerMixin(Et2Textbox)
+{
+ /** @type {any} */
+ static get properties()
+ {
+ return {
+ ...super.properties,
+ /**
+ * Allow a path instead of a URL, path must start with /, default false = not allowed
+ */
+ allow_path: {
+ type: Boolean,
+ },
+ /**
+ * Require (or forbid) that the path ends with a /, default not checked
+ */
+ trailing_slash: {
+ type: Boolean,
+ },
+ };
+ }
+
+ constructor()
+ {
+ super();
+ this.defaultValidators.push(new IsEmail());
+ this._invokerLabel = '⎆';
+ this._invokerTitle = 'Open';
+ this._invokerAction = () => {
+ Et2Url.action(this.value);
+ }
+ this.allow_path = false;
+ this.trailing_slash = undefined;
+ }
+
+ static action(value)
+ {
+ if (!value) return;
+ // implicit add http:// if no protocol given
+ if(value.indexOf("://") == -1) value = "http://"+value;
+ egw.open_link(value, '_blank');
+ }
+}
+// @ts-ignore TypeScript is not recognizing that this is a LitElement
+customElements.define("et2-url", Et2Url);
\ No newline at end of file
diff --git a/api/js/etemplate/Et2Url/Et2UrlEmail.ts b/api/js/etemplate/Et2Url/Et2UrlEmail.ts
index fdb87f9b4a..a163a751a0 100644
--- a/api/js/etemplate/Et2Url/Et2UrlEmail.ts
+++ b/api/js/etemplate/Et2Url/Et2UrlEmail.ts
@@ -23,15 +23,20 @@ export class Et2UrlEmail extends Et2InvokerMixin(Et2Textbox)
this.defaultValidators.push(new IsEmail());
this._invokerLabel = '@';
this._invokerTitle = 'Compose mail to';
- this._invokerAction = () => this.__invokerAction();
+ this._invokerAction = () =>
+ {
+ if (!this._isEmpty() && !this.hasFeedbackFor.length)
+ {
+ Et2UrlEmail.action(this.value);
+ }
+ }
}
- __invokerAction()
+ static action(value)
{
- if (!this._isEmpty() && !this.hasFeedbackFor.length &&
- this.egw().user('apps').mail && this.egw().preference('force_mailto','addressbook') != '1' )
+ if (egw.user('apps').mail && egw.preference('force_mailto','addressbook') != '1' )
{
- egw.open_link('mailto:'+this.value);
+ egw.open_link('mailto:'+value);
}
}
}
diff --git a/api/js/etemplate/Et2Url/Et2UrlEmailReadonly.ts b/api/js/etemplate/Et2Url/Et2UrlEmailReadonly.ts
new file mode 100644
index 0000000000..3629bc6a28
--- /dev/null
+++ b/api/js/etemplate/Et2Url/Et2UrlEmailReadonly.ts
@@ -0,0 +1,41 @@
+/**
+ * EGroupware eTemplate2 - Email url/compose widget
+ *
+ * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
+ * @package api
+ * @link https://www.egroupware.org
+ * @author Ralf Becker
+ */
+
+/* eslint-disable import/no-extraneous-dependencies */
+import {IsEmail} from "../Validators/IsEmail";
+import {Et2UrlEmail} from "./Et2UrlEmail";
+import {Et2UrlReadonly} from "./Et2UrlReadonly";
+
+/**
+ * @customElement et2-url-email_ro
+ */
+export class Et2UrlEmailReadonly extends Et2UrlReadonly
+{
+ constructor()
+ {
+ super();
+ }
+
+ transformAttributes(attrs)
+ {
+ if (typeof attrs.onclick === 'undefined')
+ {
+ attrs.onclick = () =>
+ {
+ if (IsEmail.EMAIL_PREG.exec(this.value))
+ {
+ Et2UrlEmail.action(this.value);
+ }
+ }
+ }
+ super.transformAttributes(attrs);
+ }
+}
+// @ts-ignore TypeScript is not recognizing that this is a LitElement
+customElements.define("et2-url-email_ro", Et2UrlEmailReadonly);
\ No newline at end of file
diff --git a/api/js/etemplate/Et2Url/Et2UrlFax.ts b/api/js/etemplate/Et2Url/Et2UrlFax.ts
new file mode 100644
index 0000000000..f6fb675938
--- /dev/null
+++ b/api/js/etemplate/Et2Url/Et2UrlFax.ts
@@ -0,0 +1,46 @@
+/**
+ * EGroupware eTemplate2 - Fax input widget
+ *
+ * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
+ * @package api
+ * @link https://www.egroupware.org
+ * @author Ralf Becker
+ */
+
+/* eslint-disable import/no-extraneous-dependencies */
+import {Et2UrlPhone} from "./Et2UrlPhone";
+import {Et2UrlEmail} from "./Et2UrlEmail";
+
+/**
+ * @customElement et2-url-phone
+ */
+export class Et2UrlFax extends Et2UrlPhone
+{
+ constructor()
+ {
+ super();
+ //this.defaultValidators.push(...);
+ this._invokerLabel = '📠';
+ this._invokerTitle = 'Send';
+ this._invokerAction = () => {
+ Et2UrlFax.action(this.value);
+ }
+ }
+
+ static action(value)
+ {
+ // convert fax numbers to email, if configured
+ if (egw.config('fax_email') && (value = value.replace('♥','').replace('(0)','').replace(/[^0-9+]/g, '')))
+ {
+ value = value.replace(new RegExp(egw.config('fax_email_regexp')||'(.*)'),
+ egw.config('fax_email'));
+ Et2UrlEmail.action(value);
+ }
+ else
+ {
+ Et2UrlPhone.action(value);
+ }
+ }
+}
+// @ts-ignore TypeScript is not recognizing that this is a LitElement
+customElements.define("et2-url-fax", Et2UrlFax);
\ No newline at end of file
diff --git a/api/js/etemplate/Et2Url/Et2UrlFaxReadonly.ts b/api/js/etemplate/Et2Url/Et2UrlFaxReadonly.ts
new file mode 100644
index 0000000000..b238c2c13e
--- /dev/null
+++ b/api/js/etemplate/Et2Url/Et2UrlFaxReadonly.ts
@@ -0,0 +1,37 @@
+/**
+ * EGroupware eTemplate2 - Fax url/send widget
+ *
+ * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
+ * @package api
+ * @link https://www.egroupware.org
+ * @author Ralf Becker
+ */
+
+/* eslint-disable import/no-extraneous-dependencies */
+import {Et2UrlFax} from "./Et2UrlFax";
+import {Et2UrlReadonly} from "./Et2UrlReadonly";
+
+/**
+ * @customElement et2-url-fax_ro
+ */
+export class Et2UrlFaxReadonly extends Et2UrlReadonly
+{
+ constructor()
+ {
+ super();
+ }
+
+ transformAttributes(attrs)
+ {
+ if (typeof attrs.onclick === 'undefined')
+ {
+ attrs.onclick = () =>
+ {
+ Et2UrlFax.action(this.value);
+ }
+ }
+ super.transformAttributes(attrs);
+ }
+}
+// @ts-ignore TypeScript is not recognizing that this is a LitElement
+customElements.define("et2-url-fax_ro", Et2UrlFaxReadonly);
\ No newline at end of file
diff --git a/api/js/etemplate/Et2Url/Et2UrlPhone.ts b/api/js/etemplate/Et2Url/Et2UrlPhone.ts
index b78bff37be..7e3809f1d8 100644
--- a/api/js/etemplate/Et2Url/Et2UrlPhone.ts
+++ b/api/js/etemplate/Et2Url/Et2UrlPhone.ts
@@ -22,12 +22,13 @@ export class Et2UrlPhone extends Et2InvokerMixin(Et2Textbox)
//this.defaultValidators.push(...);
this._invokerLabel = '✆';
this._invokerTitle = 'Call';
- this._invokerAction = () => this.__invokerAction();
+ this._invokerAction = () => {
+ Et2UrlPhone.action(this.value);
+ }
}
- __invokerAction()
+ static action(value)
{
- let value = this.value;
// Clean number
value = value.replace('♥','').replace('(0)','');
value = value.replace(/[abc]/gi,2).replace(/[def]/gi,3).replace(/[ghi]/gi,4).replace(/[jkl]/gi,5).replace(/[mno]/gi,6);
@@ -41,15 +42,15 @@ export class Et2UrlPhone extends Et2InvokerMixin(Et2Textbox)
{
window.open("tel:"+value);
}
- else if (this.egw().config("call_link"))
+ else if (egw.config("call_link"))
{
- var link = this.egw().config("call_link")
+ var link = egw.config("call_link")
// tel: links use no URL encoding according to rfc3966 section-5.1.4
- .replace("%1", this.egw().config("call_link").substr(0, 4) == 'tel:' ?
+ .replace("%1", egw.config("call_link").substr(0, 4) == 'tel:' ?
value : encodeURIComponent(value))
- .replace("%u",this.egw().user('account_lid'))
- .replace("%t",this.egw().user('account_phone'));
- var popup = this.egw().config("call_popup");
+ .replace("%u",egw.user('account_lid'))
+ .replace("%t",egw.user('account_phone'));
+ var popup = egw.config("call_popup");
if (popup && popup !== '_self' || !link.match(/^https?:/)) // execute non-http(s) links eg. tel: like before
{
egw.open_link(link, '_phonecall', popup);
diff --git a/api/js/etemplate/Et2Url/Et2UrlPhoneReadonly.ts b/api/js/etemplate/Et2Url/Et2UrlPhoneReadonly.ts
new file mode 100644
index 0000000000..131c511865
--- /dev/null
+++ b/api/js/etemplate/Et2Url/Et2UrlPhoneReadonly.ts
@@ -0,0 +1,37 @@
+/**
+ * EGroupware eTemplate2 - Phone url/call widget
+ *
+ * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
+ * @package api
+ * @link https://www.egroupware.org
+ * @author Ralf Becker
+ */
+
+/* eslint-disable import/no-extraneous-dependencies */
+import {Et2UrlPhone} from "./Et2UrlPhone";
+import {Et2UrlReadonly} from "./Et2UrlReadonly";
+
+/**
+ * @customElement et2-url-phone_ro
+ */
+export class Et2UrlPhoneReadonly extends Et2UrlReadonly
+{
+ constructor()
+ {
+ super();
+ }
+
+ transformAttributes(attrs)
+ {
+ if (typeof attrs.onclick === 'undefined')
+ {
+ attrs.onclick = () =>
+ {
+ Et2UrlPhone.action(this.value);
+ }
+ }
+ super.transformAttributes(attrs);
+ }
+}
+// @ts-ignore TypeScript is not recognizing that this is a LitElement
+customElements.define("et2-url-phone_ro", Et2UrlPhoneReadonly);
\ No newline at end of file
diff --git a/api/js/etemplate/Et2Url/Et2UrlReadonly.ts b/api/js/etemplate/Et2Url/Et2UrlReadonly.ts
new file mode 100644
index 0000000000..e9c19dd60f
--- /dev/null
+++ b/api/js/etemplate/Et2Url/Et2UrlReadonly.ts
@@ -0,0 +1,55 @@
+/**
+ * EGroupware eTemplate2 - Url r/o widget
+ *
+ * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
+ * @package api
+ * @link https://www.egroupware.org
+ * @author Ralf Becker
+ */
+
+/* eslint-disable import/no-extraneous-dependencies */
+import {IsEmail} from "../Validators/IsEmail";
+import {Et2Description} from "../Et2Description/Et2Description";
+import {Et2UrlEmail} from "./Et2UrlEmail";
+import {css} from "@lion/core";
+import {Et2Url} from "./Et2Url";
+
+/**
+ * @customElement et2-url_ro
+ */
+export class Et2UrlReadonly extends Et2Description
+{
+ constructor()
+ {
+ super();
+ }
+
+ static get styles()
+ {
+ return [
+ ...super.styles,
+ css`
+ :host {
+ cursor: pointer;
+ color: #26537c;
+ }`
+ ];
+ }
+
+ transformAttributes(attrs)
+ {
+ if (typeof attrs.onclick === 'undefined')
+ {
+ attrs.onclick = () =>
+ {
+ if (this.value)
+ {
+ Et2Url.action(this.value);
+ }
+ }
+ }
+ super.transformAttributes(attrs);
+ }
+}
+// @ts-ignore TypeScript is not recognizing that this is a LitElement
+customElements.define("et2-url_ro", Et2UrlReadonly);
\ No newline at end of file
diff --git a/api/js/etemplate/etemplate2.ts b/api/js/etemplate/etemplate2.ts
index a70d0c852d..4c73a979b1 100644
--- a/api/js/etemplate/etemplate2.ts
+++ b/api/js/etemplate/etemplate2.ts
@@ -46,8 +46,14 @@ import './Et2Textbox/Et2Number';
import './Et2Textbox/Et2NumberReadonly';
import './Et2Colorpicker/Et2Colorpicker';
import './Et2Taglist/Et2Taglist';
+import './Et2Url/Et2Url';
+import './Et2Url/Et2UrlReadonly';
import './Et2Url/Et2UrlEmail';
+import './Et2Url/Et2UrlEmailReadonly';
import './Et2Url/Et2UrlPhone';
+import './Et2Url/Et2UrlPhoneReadonly';
+import './Et2Url/Et2UrlFax';
+import './Et2Url/Et2UrlFaxReadonly';
/* Include all widget classes here, we only care about them registering, not importing anything*/
import './et2_widget_vfs'; // Vfs must be first (before et2_widget_file) due to import cycle