diff --git a/api/etemplate.php b/api/etemplate.php index 0453393cd8..e015d7f633 100644 --- a/api/etemplate.php +++ b/api/etemplate.php @@ -269,15 +269,21 @@ function send_template() $str = preg_replace('#]+)(/|>#', '', $str); - // fix --> - $str = preg_replace_callback('##s', function ($matches) use ($name) + // fix <(button|buttononly|timestamper).../> --> + $str = preg_replace_callback('#<(button|buttononly|timestamper|button-timestamp)\s(.*?)(/|>#s', function ($matches) use ($name) { $tag = 'et2-button'; $attrs = parseAttrs($matches[2]); - // replace buttononly tag with noSubmit="true" attribute - if (!empty($matches[1])) + switch ($matches[1]) { + case 'buttononly': // replace buttononly tag with noSubmit="true" attribute $attrs['noSubmit'] = 'true'; + break; + case 'timestamper': + case 'button-timestamp': + $tag .= '-timestamp'; + $attrs['background_image'] = 'true'; + break; } // novalidation --> noValidation if (!empty($attrs['novalidation']) && in_array($attrs['novalidation'], ['true', '1'], true)) diff --git a/api/js/etemplate/Et2Button/Et2Button.ts b/api/js/etemplate/Et2Button/Et2Button.ts index 2c08ca2e7b..12b97b40c7 100644 --- a/api/js/etemplate/Et2Button/Et2Button.ts +++ b/api/js/etemplate/Et2Button/Et2Button.ts @@ -136,9 +136,9 @@ export class Et2Button extends Et2InputWidget(SlButton) } } - constructor() + constructor(...args : any[]) { - super(); + super(...args); // Property default values this.__image = ''; @@ -259,7 +259,7 @@ export class Et2Button extends Et2InputWidget(SlButton) if(!this.image) { let image = this._get_default_image(this._widget_id); - if(image && image != this._image) + if(image && image != this.__image) { this.image = image; } diff --git a/api/js/etemplate/et2_widget_timestamper.ts b/api/js/etemplate/Et2Button/Et2ButtonTimestamper.ts similarity index 51% rename from api/js/etemplate/et2_widget_timestamper.ts rename to api/js/etemplate/Et2Button/Et2ButtonTimestamper.ts index f14ac67d1a..d07b2ecc7a 100644 --- a/api/js/etemplate/et2_widget_timestamper.ts +++ b/api/js/etemplate/Et2Button/Et2ButtonTimestamper.ts @@ -9,63 +9,59 @@ * @copyright Nathan Gray 2017 */ -/*egw:uses - et2_button; -*/ +import {et2_IInput} from "../et2_core_interfaces"; +import {date} from "../lib/date.js"; +import {Et2Button} from "./Et2Button"; +import {Et2Tabs} from "../Layout/Et2Tabs/Et2Tabs"; -import {et2_register_widget, WidgetConfig} from "./et2_core_widget"; -import {et2_button} from "./et2_widget_button"; -import {ClassWithAttributes} from "./et2_core_inheritance"; -import {et2_no_init} from "./et2_core_common"; -import {egw} from "../jsapi/egw_global"; -import {et2_IInput} from "./et2_core_interfaces"; -import {date} from "./lib/date.js"; /** - * Class which implements the "button-timestamper" XET-Tag + * Class which implements the "et2-button-timestamp" tag * * Clicking the button puts the current time and current user at the end of * the provided field. - * - * @augments et2_button */ -export class et2_timestamper extends et2_button +export class Et2ButtonTimestamper extends Et2Button { - static readonly _attributes : any = { - target: { - name: "Target field", - type: "string", - default: et2_no_init, - description: "Which field to place the timestamp in" - }, - format: { - name: "Time format", - type: "string", - default: et2_no_init, - description: "Format for the timestamp. User is always after." - }, - timezone: { - name: "Timezone", - type: "string", - default: et2_no_init, - description: "Timezone. Default is user time." - }, - statustext: { - default: "Insert timestamp into description field" - }, - image: { - default: "timestamp" - }, - background_image: { - default: true - } - }; - target : string; - - constructor(_parent, _attrs? : WidgetConfig, _child? : object) + static get properties() { - // Call the inherited constructor - super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_timestamper._attributes, _child || {})); - jQuery(this.getDOMNode()).addClass('et2_timestamper'); + return { + ...super.properties, + /** + * Which field to place the timestamp in + */ + target: { + type: String + }, + /** + * Format for the timestamp. User is always after. + */ + format: { + type: String + }, + /** + * Timezone. Default is user time. + */ + timezone: { + type: String + }, + /** + * Icon to use, default "timestamp" + */ + image: { + type: String + } + } + } + + constructor(...args : any[]) + { + super(...args); + + // Property default values + this.image = 'timestamp'; + this.noSubmit = true; + + this.onclick = this.stamp.bind(this); } /** @@ -74,40 +70,21 @@ export class et2_timestamper extends et2_button * @param _ev * @returns {Boolean} */ - click(_ev) { - // ignore click on readonly button - if (this.options.readonly) return false; - - this._insert_text(); - - return false; - } - - private _insert_text() { - let text = ""; - let now = new Date(new Date().toLocaleString('en-US', { - timeZone: this.options.timezone ? this.options.timezone : egw.preference('tz') + stamp(event: MouseEvent): boolean + { + const now = new Date(new Date().toLocaleString('en-US', { + timeZone: this.timezone || egw.preference('tz') })); - let format = (this.options.format ? - this.options.format : - egw.preference('dateformat') + ' ' + (egw.preference("timeformat") === "12" ? "h:ia" : "H:i"))+' '; + const format = this.format || egw.preference('dateformat') + ' ' + (egw.preference("timeformat") === "12" ? "h:ia" : "H:i")+' '; - text += date(format, now); + let text = date(format, now); // Get properly formatted user name - let user = parseInt(egw.user('account_id')); - let accounts = egw.accounts('accounts'); - for(let j = 0; j < accounts.length; j++) - { - if(accounts[j]["value"] === user) - { - text += accounts[j]["label"]; - break; - } - } - text += ': '; + const user = parseInt(egw.user('account_id')); + const account = egw.accounts('accounts').filter(option => option.value == user)[0]; + text += account.label + ': '; - let widget = this._get_input(this.target); + const widget = this._get_input(this.target); let input = widget.input ? widget.input : widget.getDOMNode(); if(input.context) { @@ -134,6 +111,14 @@ export class et2_timestamper extends et2_button pos = input.selectionStart; } + // If on a tab, switch to that tab so user can see it + let tabbox = widget; + while(tabbox._parent && tabbox.nodeName !== 'ET2-TABBOX') + { + tabbox = tabbox._parent; + } + if (tabbox.nodeName === 'ET2-TABBOX') (tabbox).activateTab(widget); + // If tinymce, update it if(tinymce) { @@ -144,6 +129,11 @@ export class et2_timestamper extends et2_button // Insert the text let front = (input.value).substring(0, pos); let back = (input.value).substring(pos, input.value.length); + // for webComponent, we need to set the component value too, otherwise the change is lost! + if (typeof widget.tagName !== 'undefined') + { + widget.value = front+text+back; + } input.value = front+text+back; // Clean up a little @@ -164,13 +154,6 @@ export class et2_timestamper extends et2_button input.scrollTop = scrollPos; input.focus(); } - // If on a tab, switch to that tab so user can see it - let tab = widget; - while(tab._parent && tab._type != 'tabbox') - { - tab = tab._parent; - } - if (tab._type == 'tabbox') tab.activateTab(widget); } private _get_input(target) @@ -201,4 +184,6 @@ export class et2_timestamper extends et2_button return input; } } -et2_register_widget(et2_timestamper, ["button-timestamp", "timestamper"]); + +// @ts-ignore TypeScript is not recognizing that Et2Button is a LitElement +customElements.define("et2-button-timestamp", Et2ButtonTimestamper); \ No newline at end of file diff --git a/api/js/etemplate/Layout/Et2Tabs/Et2Tabs.ts b/api/js/etemplate/Layout/Et2Tabs/Et2Tabs.ts index 7c24decc04..e126e9ba3e 100644 --- a/api/js/etemplate/Layout/Et2Tabs/Et2Tabs.ts +++ b/api/js/etemplate/Layout/Et2Tabs/Et2Tabs.ts @@ -393,6 +393,51 @@ export class Et2Tabs extends Et2Widget(SlTabGroup) { this.setActiveTab(this._selectedIndex); } + + /** + * Activate the tab containing the given widget + * + * @param {et2_widget} widget + * @return {bool} widget was found in a tab + */ + activateTab(widget) + { + let tab = widget; + while(tab._parent && tab._parent.nodeName !== 'ET2-TABBOX') + { + tab = tab._parent; + } + if (tab.nodeName === 'ET2-TAB-PANEL') + { + this.show(tab.name); + return true; + } + return false; + } + + /** + * Reimplement to allow our existing function signatures too + * + * @deprecated use this.show(name : string) + * @param tab number or name of tab (Sl uses that internally with a SlTab!) + * @param options + */ + setActiveTab(tab: SlTab|String|Number, options?: { + emitEvents?: boolean; + scrollBehavior?: 'auto' | 'smooth'; + }) + { + if (typeof tab === 'number') + { + tab = this.getAllTabs()[tab]; + return this.show(tab.panel); + } + if (typeof tab === 'string') + { + return this.show(tab); + } + return super.setActiveTab(tab, options); + } } customElements.define("et2-tabbox", Et2Tabs); \ No newline at end of file diff --git a/api/js/etemplate/etemplate2.ts b/api/js/etemplate/etemplate2.ts index eba49d10ec..df2357f420 100644 --- a/api/js/etemplate/etemplate2.ts +++ b/api/js/etemplate/etemplate2.ts @@ -30,6 +30,7 @@ import './Layout/Et2Tabs/Et2Tabs'; import './Layout/Et2Tabs/Et2TabPanel'; import './Et2Avatar/Et2Avatar'; import './Et2Button/Et2Button'; +import './Et2Button/Et2ButtonTimestamper'; import './Et2Checkbox/Et2Checkbox'; import './Et2Checkbox/Et2CheckboxReadonly'; import './Et2Date/Et2Date'; @@ -121,7 +122,6 @@ import './et2_widget_html'; import './et2_widget_htmlarea'; import './et2_widget_tabs'; import './et2_widget_taglist'; -import './et2_widget_timestamper'; import './et2_widget_toolbar'; import './et2_widget_tree'; import './et2_widget_historylog'; diff --git a/infolog/templates/default/app.css b/infolog/templates/default/app.css index 518840f1fb..e2d102905a 100644 --- a/infolog/templates/default/app.css +++ b/infolog/templates/default/app.css @@ -69,7 +69,9 @@ button.infologExtraButton:hover { .tab_toolbar { position: absolute; - top: 8px; + top: 6px; + right: 0; + z-index: 10000; /* otherwise et2-tabs gets our clicks! */ } .tab_toolbar > button, .tab_toolbar > et2-button { diff --git a/infolog/templates/pixelegg/app.css b/infolog/templates/pixelegg/app.css index 8b5828d88b..e626620658 100755 --- a/infolog/templates/pixelegg/app.css +++ b/infolog/templates/pixelegg/app.css @@ -125,7 +125,10 @@ button.infologExtraButton:hover { } .tab_toolbar { position: absolute; - top: 8px; + top: 6px; + right: 0; + z-index: 10000; + /* otherwise et2-tabs gets our clicks! */ } .tab_toolbar > button, .tab_toolbar > et2-button {