diff --git a/api/js/etemplate/et2_core_interfaces.ts b/api/js/etemplate/et2_core_interfaces.ts index 3f8ebf5928..b9c3e3a546 100644 --- a/api/js/etemplate/et2_core_interfaces.ts +++ b/api/js/etemplate/et2_core_interfaces.ts @@ -155,7 +155,6 @@ function implements_et2_ISubmitListener(obj : et2_widget) */ interface et2_IDetachedDOM { - /** * Creates a list of attributes which can be set when working in the * "detached" mode. The result is stored in the _attrs array which is provided @@ -181,8 +180,7 @@ interface et2_IDetachedDOM * returned by the "getDetachedAttributes" function and sets them to the * given values. */ - setDetachedAttributes(_nodes : HTMLElement[], _values : object) : void - + setDetachedAttributes(_nodes : HTMLElement[], _values : object, _data?) : void } var et2_IDetachedDOM = "et2_IDetachedDOM"; function implements_et2_IDetachedDOM(obj : et2_widget) diff --git a/api/js/etemplate/et2_widget_box.js b/api/js/etemplate/et2_widget_box.js index f065b634d2..038e8cdcc3 100644 --- a/api/js/etemplate/et2_widget_box.js +++ b/api/js/etemplate/et2_widget_box.js @@ -30,7 +30,6 @@ Object.defineProperty(exports, "__esModule", { value: true }); */ var et2_core_widget_1 = require("./et2_core_widget"); var et2_core_baseWidget_1 = require("./et2_core_baseWidget"); -var jQuery = require("jquery"); var et2_core_xml_1 = require("./et2_core_xml"); /** * Class which implements box and vbox tag diff --git a/api/js/etemplate/et2_widget_box.ts b/api/js/etemplate/et2_widget_box.ts index 7fdc9bd70c..3c49d9d47a 100644 --- a/api/js/etemplate/et2_widget_box.ts +++ b/api/js/etemplate/et2_widget_box.ts @@ -18,7 +18,6 @@ import {et2_register_widget, WidgetConfig} from "./et2_core_widget"; import {et2_baseWidget} from "./et2_core_baseWidget"; -import * as jQuery from "jquery"; import {et2_readAttrWithDefault} from './et2_core_xml' /** diff --git a/api/js/etemplate/et2_widget_description.ts b/api/js/etemplate/et2_widget_description.ts new file mode 100644 index 0000000000..3375abc673 --- /dev/null +++ b/api/js/etemplate/et2_widget_description.ts @@ -0,0 +1,429 @@ +/** + * EGroupware eTemplate2 - JS Description object + * + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @package etemplate + * @subpackage api + * @link http://www.egroupware.org + * @author Andreas Stöckel + */ + +/*egw:uses + /vendor/bower-asset/jquery/dist/jquery.js; + et2_core_baseWidget; + expose; +*/ + +import './et2_core_common'; +import { ClassWithAttributes } from "./et2_core_inheritance"; +import { et2_widget, et2_createWidget, et2_register_widget, WidgetConfig } from "./et2_core_widget"; +import { et2_DOMWidget } from './et2_core_DOMWidget' +import { et2_baseWidget } from './et2_core_baseWidget' +import './et2_types'; + +/** + * Class which implements the "description" XET-Tag + */ +class et2_description extends et2_baseWidget implements et2_IDetachedDOM +{ + static readonly _attributes : any = { + "label": { + "name": "Label", + "default": "", + "type": "string", + "description": "The label is displayed by default in front (for radiobuttons behind) each widget (if not empty). If you want to specify a different position, use a '%s' in the label, which gets replaced by the widget itself. Eg. '%s Name' to have the label Name behind a checkbox. The label can contain variables, as descript for name. If the label starts with a '@' it is replaced by the value of the content-array at this index (with the '@'-removed and after expanding the variables).", + "translate": true + }, + "value": { + "name": "Value", + "type": "string", + "description": "Displayed text", + "translate": "!no_lang", + "default": "" + }, + + /** + * Options converted from the "options"-attribute. + */ + "font_style": { + "name": "Font Style", + "type": "string", + "description": "Style may be a compositum of \"b\" and \"i\" which " + + " renders the text bold and/or italic." + }, + "href": { + "name": "Link URL", + "type": "string", + "description": "Link URL, empty if you don't wan't to display a link." + }, + "activate_links": { + "name": "Replace URLs", + "type": "boolean", + "default": false, + "description": "If set, URLs in the text are automatically replaced " + + "by links" + }, + "for": { + "name": "Label for widget", + "type": "string", + "description": "Marks the text as label for the given widget." + }, + "extra_link_target": { + "name": "Link target", + "type": "string", + "default": "_browser", + "description": "Link target for href attribute" + }, + "extra_link_popup": { + "name": "Popup", + "type": "string", + "description": "widthxheight, if popup should be used, eg. 640x480" + }, + "expose_view":{ + name: "Expose view", + type: "boolean", + default: false, + description: "Clicking on description with href value would popup an expose view, and will show content referenced by href." + }, + mime:{ + name: "Mime type", + type: "string", + default: '', + description: "Mime type of the registered link" + }, + mime_data:{ + name: "Mime data", + type: "string", + default: '', + description: "hash for data stored on service-side with egw_link::(get|set)_data()" + }, + hover_action: { + "name": "hover action", + "type": "js", + "default": et2_no_init, + "description": "JS code which is executed when clicking on action button. This action is explicitly for attached nodes, like in nm." + }, + hover_action_title: { + "name": "hover action title", + "type": "string", + "default": "Edit", + "description": "Text to show as tooltip of defined action" + } + + } + + legacyOptions: string[] = ["font_style", "href", "activate_links", "for", + "extra_link_target", "extra_link_popup", "statustext"]; + + span: JQuery; + label: string; + private _labelContainer: JQuery = null; + font_style: string; + mime_regexp: any; + + /** + * Constructor + */ + constructor(_parent, _attrs? : WidgetConfig, _child? : object) + { + // Call the inherited constructor + super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_DOMWidget._attributes, _child || {})); + + // Create the span/label tag which contains the label text + this.span = jQuery(document.createElement(this.options["for"] ? "label" : "span")) + .addClass("et2_label"); + + et2_insertLinkText(this._parseText(this.options.value), this.span[0], + this.options.href ? this.options.extra_link_target : '_blank'); + + this.setDOMNode(this.span[0]); + } + + transformAttributes(_attrs) + { + super.transformAttributes(_attrs); + + if (this.id) + { + var val = this.getArrayMgr("content").getEntry(this.id); + + if (val) + { + _attrs["value"] = val; + } + } + } + + doLoadingFinished() + { + super.doLoadingFinished(); + + // Get the real id of the 'for' widget + var for_widget = null; + if (this.options["for"] && ( + (for_widget = this.getParent().getWidgetById(this.options.for)) || + (for_widget = this.getRoot().getWidgetById(this.options.for)) + ) && for_widget && for_widget.id) + { + if(for_widget.dom_id) + { + this.span.attr("for", for_widget.dom_id); + } + else + { + // Target widget is not done yet, need to wait + var tab_deferred = jQuery.Deferred(); + window.setTimeout(function() { + this.span.attr("for", for_widget.dom_id); + tab_deferred.resolve(); + }.bind(this),0); + + return tab_deferred.promise(); + } + } + return true; + } + + set_label(_value) + { + // Abort if ther was no change in the label + if (_value == this.label) + { + return; + } + + if (_value) + { + // Create the label container if it didn't exist yet + if (this._labelContainer == null) + { + this._labelContainer = jQuery(document.createElement("label")) + .addClass("et2_label"); + this.getSurroundings().insertDOMNode(this._labelContainer[0]); + } + + // Clear the label container. + this._labelContainer.empty(); + + // Create the placeholder element and set it + var ph = document.createElement("span"); + this.getSurroundings().setWidgetPlaceholder(ph); + + // Split the label at the "%s" + var parts = et2_csvSplit(_value, 2, "%s"); + + // Update the content of the label container + for (var i = 0; i < parts.length; i++) + { + if (parts[i]) + { + this._labelContainer.append(document.createTextNode(parts[i])); + } + if (i == 0) + { + this._labelContainer.append(ph); + } + } + + // add class if label is empty + this._labelContainer.toggleClass('et2_label_empty', !_value || !parts[0]); + } + else + { + // Delete the labelContainer from the surroundings object + if (this._labelContainer) + { + this.getSurroundings().removeDOMNode(this._labelContainer[0]); + } + this._labelContainer = null; + } + + // Update the surroundings in order to reflect the change in the label + this.getSurroundings().update(); + + // Copy the given value + this.label = _value; + } + + /** + * Function to get media content to feed the expose + * @param {type} _value + * @returns {Array|Array.getMedia.mediaContent} + */ + getMedia(_value) + { + var base_url = egw.webserverUrl.match(/^\//,'ig')?egw(window).window.location.origin :''; + var mediaContent = []; + if (_value) + { + mediaContent = [{ + title: this.options.label, + href: base_url + _value, + type: this.options.type + "/*", + thumbnail: base_url + _value + }]; + if (_value.match(/\/webdav.php/,'ig')) mediaContent[0]["download_href"] = base_url + _value + '?download'; + } + return mediaContent; + } + + set_value(_value) + { + if (!_value) _value = ""; + if (!this.options.no_lang) _value = this.egw().lang(_value); + if (this.options.value && (this.options.value+"").indexOf('%s') != -1) + { + _value = this.options.value.replace(/%s/g, _value); + } + et2_insertLinkText(this._parseText(_value), + this.span[0], + this.options.href ? this.options.extra_link_target : '_blank' + ); + // Add hover action button (Edit) + if (this.options.hover_action) + { + this._build_hover_action(); + } + if(this.options.extra_link_popup || this.options.mime) + { + var href = this.options.href; + var mime_data = this.options.mime_data; + var self= this; + var $span = this.options.mime_data? jQuery(this.span): jQuery('a',this.span); + $span.click(function(e) { + if (self.options.expose_view && typeof self.options.mime !='undefined' && self.options.mime.match(self.mime_regexp,'ig')) + { + // ToDoExpose: self._init_blueimp_gallery(e, href); + } + else + { + egw(window).open_link(mime_data || href, self.options.extra_link_target, self.options.extra_link_popup, null, null, self.options.mime); + } + e.preventDefault(); + return false; + }); + } + } + + _parseText(_value) + { + if (this.options.href) + { + var href = this.options.href; + if (href.indexOf('/')==-1 && href.split('.').length >= 3 && + !(href.indexOf('mailto:')!=-1 || href.indexOf('://') != -1 || href.indexOf('javascript:') != -1) + ) + { + href = "/index.php?menuaction="+href; + } + if (href.charAt(0) == '/') // link relative to eGW + { + href = egw.link(href); + } + return [{ + "href": href, + "text": _value + }]; + } + else if (this.options.activate_links) + { + return et2_activateLinks(_value); + } + else + { + return [_value]; + } + } + + set_font_style(_value) + { + this.font_style = _value; + + this.span.toggleClass("et2_bold", _value.indexOf("b") >= 0); + this.span.toggleClass("et2_italic", _value.indexOf("i") >= 0); + } + + /** + * Code for implementing et2_IDetachedDOM + * + * @param {array} _attrs + */ + getDetachedAttributes(_attrs) + { + _attrs.push("value", "class", "href"); + } + + getDetachedNodes() + { + return [this.span[0]]; + } + + setDetachedAttributes(_nodes, _values, _data?) + { + // Update the properties + var updateLink = false; + if (typeof _values["href"] != "undefined") + { + updateLink = true; + this.options.href = _values["href"]; + } + + if (typeof _values["value"] != "undefined" || (updateLink && (_values["value"] || this.options.value))) + { + this.span = jQuery(_nodes[0]); + this.set_value(_values["value"]); + } + + if (typeof _values["class"] != "undefined") + { + _nodes[0].setAttribute("class", _values["class"]); + } + + // Add hover action button (Edit), _data is nm's row data + if (this.options.hover_action) + { + this._build_hover_action(_data); + } + } + + /** + * Builds button for hover action + * @param {object} _data + */ + _build_hover_action(_data?) + { + var content = _data && _data.content ? _data.content: undefined; + var widget = this; + this.span.off().on('mouseenter', jQuery.proxy(function(event) { + event.stopImmediatePropagation(); + var self = this; + this.span.tooltip({ + items: 'span.et2_label', + position: {my:"right top", at:"left top", collision:"flipfit"}, + tooltipClass: "et2_email_popup", + content() + { + return jQuery('') + .on('click', function() { + widget.options.hover_action.call(self, self.widget, content); + }); + }, + close( event, ui ) + { + ui.tooltip.hover( + function () { + jQuery(this).stop(true).fadeTo(400, 1); + }, + function () { + jQuery(this).fadeOut("400", function(){ jQuery(this).remove();}); + } + ); + } + }) + .tooltip("open"); + }, {widget: this, span: this.span})); + } +} +et2_register_widget(et2_description, ["description", "label"]); +