Et2DescriptionExpose, used in Mail app

This commit is contained in:
nathan 2022-05-05 13:48:39 -06:00
parent 7dc959c223
commit 063c772fbb
4 changed files with 223 additions and 27 deletions

View File

@ -144,19 +144,19 @@ export class Et2Description extends Et2Widget(LitElement) implements et2_IDetach
// If there's a link, wrap that // If there's a link, wrap that
if(this.href && this._value) if(this.href && this.value)
{ {
render = this.wrapLink(this.href, this._value); render = this.wrapLink(this.href, this.value);
} }
// If we want to activate links inside, do that // If we want to activate links inside, do that
else if(this.activate_links && this._value) else if(this.activate_links && this.value)
{ {
render = this.getActivatedValue(this._value, this.href ? this.extra_link_target : '_blank'); render = this.getActivatedValue(this.value, this.href ? this.extra_link_target : '_blank');
} }
// Just do the value // Just do the value
else else
{ {
render = html`${this._value}`; render = html`${this.value}`;
} }
return render; return render;
} }
@ -185,11 +185,7 @@ export class Et2Description extends Et2Widget(LitElement) implements et2_IDetach
// call super to get the onclick handling running // call super to get the onclick handling running
super._handleClick(_ev); super._handleClick(_ev);
if(this.expose_view && typeof this.mime != 'undefined' && this.mime_regexp && this.mime.match(this.mime_regexp, 'ig')) if(this.mime_data || this.href)
{
this._init_blueimp_gallery(_ev, this.href);
}
else if(this.mime_data || this.href)
{ {
egw(window).open_link(this.mime_data || this.href, this.extra_link_target, this.extra_link_popup, null, null, this.mime); egw(window).open_link(this.mime_data || this.href, this.extra_link_target, this.extra_link_popup, null, null, this.mime);
} }

View File

@ -0,0 +1,129 @@
/**
* EGroupware eTemplate2 - Description that can expose
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package etemplate
* @subpackage api
* @link https://www.egroupware.org
* @author Nathan Gray
* @copyright 2022 Nathan Gray
*/
import {ExposeMixin, ExposeValue, MediaValue} from "./ExposeMixin";
import {Et2Description} from "../Et2Description/Et2Description";
import {et2_IDetachedDOM} from "../et2_core_interfaces";
import {html} from "@lion/core";
/**
* Shows a description and if you click on it, it shows the file specified by href in gallery.
*
* If the gallery cannot handle the file type (specified by mime) then href is handled as
* a normal description, and clicking follows the link.
*/
//@ts-ignore Something not right with types & inheritance according to TypeScript
export class Et2DescriptionExpose extends ExposeMixin(Et2Description) implements et2_IDetachedDOM
{
static get properties()
{
return {
...super.properties,
/**
* Mime type
* Used to determine this widget can be exposed. If not one of the OK mime types, will be treated
* as a normal description
*/
mime: {
type: String,
reflect: true
},
/**
* hash for data stored on service-side with egw_link::(get|set)_data()
*/
mime_data: {type: String},
}
}
constructor() {super();}
connectedCallback()
{
super.connectedCallback();
}
disconnectedCallback()
{
super.disconnectedCallback();
}
/** These guys needed to get value where it needs to be */
set value(new_value)
{
return super.value = new_value;
}
get value()
{
return super.value;
}
/**
* Needed to for transformAttributes() to set the value.
* Not sure why Et2Description.set_value() isn't enough.
*/
set_value(value)
{
super.set_value(value);
}
/**
* Override the wrap link, since clicking on a link would work and do both
* @param href
* @param value
* @returns {TemplateResult<1>}
* @protected
*/
protected wrapLink(href, value)
{
if(this.isExposable())
{
return html`${value}`;
}
else
{
// Expose cannot handle this particular file / link, wrap it as normal
return super.wrapLink(href, value);
}
}
/**
* Used to determine if this widget is exposable. Images always are, even if we don't actually
* know the mime type.
*
* @returns {ExposeValue}
*/
get exposeValue() : ExposeValue
{
return {
mime: this.mime,
path: this.href,
download_url: this.href,
};
}
/**
* Get the info needed to show this image as slide(s)
*/
getMedia(_value) : MediaValue[]
{
let media = super.getMedia(_value);
if(media)
{
media[0].title = this.value;
}
return media;
}
}
customElements.define("et2-description-expose", Et2DescriptionExpose as any);

View File

@ -72,9 +72,26 @@ export function ExposeMixin<B extends Constructor<LitElement>>(superclass : B)
{ {
return class extends superclass return class extends superclass
{ {
static get properties()
{
return {
...super.properties,
/**
* Function to extract an image list
*
* "Normally" we'll try to pull a list of images from the nextmatch or show just the current widget,
* but if you know better you can provide a method to get the list.
*/
mediaContentFunction: {type: Function},
}
}
// @ts-ignore // @ts-ignore
private _gallery : blueimp.Gallery; private _gallery : blueimp.Gallery;
private __mediaContentFunction : Function | null;
constructor(...args : any[]) constructor(...args : any[])
{ {
super(...args); super(...args);
@ -111,7 +128,6 @@ export function ExposeMixin<B extends Constructor<LitElement>>(superclass : B)
disconnectedCallback() disconnectedCallback()
{ {
super.disconnectedCallback(); super.disconnectedCallback();
this.removeEventListener("click", this.expose_onclick);
} }
/** /**
@ -137,20 +153,40 @@ export function ExposeMixin<B extends Constructor<LitElement>>(superclass : B)
*/ */
getMedia(_value) : MediaValue[] getMedia(_value) : MediaValue[]
{ {
let base_url = egw.webserverUrl.match(/^\/ig/) ? egw(window).window.location.origin + egw.webserverUrl + '/' : egw.webserverUrl + '/';
let mediaContent = []; let mediaContent = [];
if(_value) if(_value)
{ {
mediaContent = [{ mediaContent = [{
title: _value.label, title: _value.label,
href: _value.download_url ? base_url + _value.download_url : base_url + _value.path, href: _value.download_url ? this._processUrl(_value.download_url) : this._processUrl(_value.path),
type: _value.mime || (_value.type ? _value.type + "/*" : "") type: _value.mime || (_value.type ? _value.type + "/*" : "")
}]; }];
mediaContent[0].thumbnail = _value.thumbnail ? (base_url + _value.thumbnail) : mediaContent[0].href; if(this.isExposable())
{
mediaContent[0].thumbnail = _value.thumbnail ? this._processUrl(_value.thumbnail) : mediaContent[0].href;
}
else
{
let fe = egw_get_file_editor_prefered_mimes(_value.mime);
if(fe && fe.mime[_value.mime] && fe.mime[_value.mime].favIconUrl)
{
mediaContent[0].thumbnail = fe.mime[_value.mime].favIconUrl;
}
}
} }
return mediaContent; return mediaContent;
} }
protected _processUrl(url)
{
let base_url = egw.webserverUrl.match(/^\/ig/) ? egw(window).window.location.origin + egw.webserverUrl + '/' : egw.webserverUrl + '/';
if(base_url && base_url != '/' && url.indexOf(base_url) != 0)
{
url = base_url + url;
}
return url;
}
/** /**
* Handle changes that have to happen based on changes to properties * Handle changes that have to happen based on changes to properties
* *
@ -173,12 +209,8 @@ export function ExposeMixin<B extends Constructor<LitElement>>(superclass : B)
*/ */
protected _bindGallery() protected _bindGallery()
{ {
//@ts-ignore Expects a parameter, but not actually required
let fe = egw_get_file_editor_prefered_mimes();
// If the media type is not supported do not bind the click handler // If the media type is not supported do not bind the click handler
if(!this.exposeValue || typeof this.exposeValue.mime != 'string' || (!this.exposeValue.mime.match(MIME_REGEX) if(!this.isExposable())
&& (!fe || fe.mime && !fe.mime[this.exposeValue.mime])) || typeof this.exposeValue.download_url == 'undefined')
{ {
this.classList.remove("et2_clickable"); this.classList.remove("et2_clickable");
if(this._gallery) if(this._gallery)
@ -196,6 +228,19 @@ export function ExposeMixin<B extends Constructor<LitElement>>(superclass : B)
} }
} }
public isExposable() : boolean
{
if(!this.exposeValue || typeof this.exposeValue.mime !== "string")
{
return false
}
if(this.exposeValue.mime.match(MIME_REGEX) || this.exposeValue.mime.match(MIME_AUDIO_REGEX))
{
return true;
}
return false;
}
/** /**
* Just override the normal click handler * Just override the normal click handler
* *
@ -204,8 +249,11 @@ export function ExposeMixin<B extends Constructor<LitElement>>(superclass : B)
*/ */
_handleClick(_ev : MouseEvent) : boolean _handleClick(_ev : MouseEvent) : boolean
{ {
this.expose_onclick(_ev) if((!this.isExposable() || this.expose_onclick(_ev)) && typeof super._handleClick === "function")
return true; {
return super._handleClick(_ev);
}
return false;
} }
get expose_options() get expose_options()
@ -410,7 +458,11 @@ export function ExposeMixin<B extends Constructor<LitElement>>(superclass : B)
let options = this.expose_options; let options = this.expose_options;
let nm = this.find_nextmatch(this); let nm = this.find_nextmatch(this);
if(nm && !this._is_target_indepth(nm, event.target)) if(typeof this.__mediaContentFunction == "function")
{
this.__mediaContentFunction(this);
}
else if(nm && !this._is_target_indepth(nm, event.target))
{ {
// Get the row that was clicked, find its index in the list // Get the row that was clicked, find its index in the list
let current_entry = nm.controller.getRowByNode(event.target); let current_entry = nm.controller.getRowByNode(event.target);
@ -437,8 +489,24 @@ export function ExposeMixin<B extends Constructor<LitElement>>(superclass : B)
} }
else else
{ {
// @ts-ignore // Try for all exposable of the same type in the parent widget
mediaContent = this.getMedia(_value); try
{
this.getParent().getDOMNode().querySelectorAll(this.localName).forEach((exposable, index) =>
{
if(exposable === this)
{
options.index = index;
}
mediaContent.push(...exposable.getMedia(Object.assign({}, IMAGE_DEFAULT, exposable.exposeValue)));
});
}
catch(e)
{
// Well, that didn't work. Just the one then.
// @ts-ignore
mediaContent = this.getMedia(_value);
}
// Do not show thumbnail indicator on single expose view // Do not show thumbnail indicator on single expose view
options.thumbnailIndicators = (mediaContent.length > 1); options.thumbnailIndicators = (mediaContent.length > 1);
if(!options.thumbnailIndicators) if(!options.thumbnailIndicators)
@ -652,23 +720,25 @@ export function ExposeMixin<B extends Constructor<LitElement>>(superclass : B)
protected expose_onclick(event : MouseEvent) protected expose_onclick(event : MouseEvent)
{ {
event.stopImmediatePropagation();
// Do not trigger expose view if one of the operator keys are held // Do not trigger expose view if one of the operator keys are held
if(event.altKey || event.ctrlKey || event.shiftKey || event.metaKey) if(event.altKey || event.ctrlKey || event.shiftKey || event.metaKey)
{ {
return; return;
} }
event.stopImmediatePropagation();
// @ts-ignore Wants an argument, but does not require it // @ts-ignore Wants an argument, but does not require it
let fe = egw_get_file_editor_prefered_mimes(); let fe = egw_get_file_editor_prefered_mimes();
if(this.exposeValue.mime.match(MIME_REGEX) && !this.exposeValue.mime.match(MIME_AUDIO_REGEX)) if(this.exposeValue.mime.match(MIME_REGEX) && !this.exposeValue.mime.match(MIME_AUDIO_REGEX))
{ {
this._init_blueimp_gallery(event, this.exposeValue); this._init_blueimp_gallery(event, this.exposeValue);
return false;
} }
else if(this.exposeValue.mime.match(MIME_AUDIO_REGEX)) else if(this.exposeValue.mime.match(MIME_AUDIO_REGEX))
{ {
this._audio_player(this.exposeValue); this._audio_player(this.exposeValue);
return false;
} }
else if(fe && fe.mime && fe.edit && fe.mime[this.exposeValue.mime]) else if(fe && fe.mime && fe.edit && fe.mime[this.exposeValue.mime])
{ {
@ -677,8 +747,9 @@ export function ExposeMixin<B extends Constructor<LitElement>>(superclass : B)
path: this.exposeValue.path, path: this.exposeValue.path,
cd: 'no' // needed to not reload framework in sharing cd: 'no' // needed to not reload framework in sharing
}), '', fe.edit_popup); }), '', fe.edit_popup);
return false;
} }
return true;
} }
protected expose_onopen() {} protected expose_onopen() {}
@ -840,6 +911,5 @@ export function ExposeMixin<B extends Constructor<LitElement>>(superclass : B)
} }
protected expose_onclosed() {} protected expose_onclosed() {}
} }
} }

View File

@ -38,6 +38,7 @@ import './Et2Date/Et2DateTimeToday';
import './Et2Description/Et2Description'; import './Et2Description/Et2Description';
import './Et2Dialog/Et2Dialog'; import './Et2Dialog/Et2Dialog';
import './Expose/Et2ImageExpose'; import './Expose/Et2ImageExpose';
import './Expose/Et2DescriptionExpose';
import './Et2Image/Et2Image'; import './Et2Image/Et2Image';
import './Et2Select/Et2Select'; import './Et2Select/Et2Select';
import './Et2Select/Et2SelectAccount'; import './Et2Select/Et2SelectAccount';