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(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
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
else
{
render = html`${this._value}`;
render = html`${this.value}`;
}
return render;
}
@ -185,11 +185,7 @@ export class Et2Description extends Et2Widget(LitElement) implements et2_IDetach
// call super to get the onclick handling running
super._handleClick(_ev);
if(this.expose_view && typeof this.mime != 'undefined' && this.mime_regexp && this.mime.match(this.mime_regexp, 'ig'))
{
this._init_blueimp_gallery(_ev, this.href);
}
else if(this.mime_data || this.href)
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);
}

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
{
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
private _gallery : blueimp.Gallery;
private __mediaContentFunction : Function | null;
constructor(...args : any[])
{
super(...args);
@ -111,7 +128,6 @@ export function ExposeMixin<B extends Constructor<LitElement>>(superclass : B)
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[]
{
let base_url = egw.webserverUrl.match(/^\/ig/) ? egw(window).window.location.origin + egw.webserverUrl + '/' : egw.webserverUrl + '/';
let mediaContent = [];
if(_value)
{
mediaContent = [{
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 + "/*" : "")
}];
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;
}
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
*
@ -173,12 +209,8 @@ export function ExposeMixin<B extends Constructor<LitElement>>(superclass : B)
*/
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(!this.exposeValue || typeof this.exposeValue.mime != 'string' || (!this.exposeValue.mime.match(MIME_REGEX)
&& (!fe || fe.mime && !fe.mime[this.exposeValue.mime])) || typeof this.exposeValue.download_url == 'undefined')
if(!this.isExposable())
{
this.classList.remove("et2_clickable");
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
*
@ -204,8 +249,11 @@ export function ExposeMixin<B extends Constructor<LitElement>>(superclass : B)
*/
_handleClick(_ev : MouseEvent) : boolean
{
this.expose_onclick(_ev)
return true;
if((!this.isExposable() || this.expose_onclick(_ev)) && typeof super._handleClick === "function")
{
return super._handleClick(_ev);
}
return false;
}
get expose_options()
@ -410,7 +458,11 @@ export function ExposeMixin<B extends Constructor<LitElement>>(superclass : B)
let options = this.expose_options;
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
let current_entry = nm.controller.getRowByNode(event.target);
@ -437,8 +489,24 @@ export function ExposeMixin<B extends Constructor<LitElement>>(superclass : B)
}
else
{
// @ts-ignore
mediaContent = this.getMedia(_value);
// Try for all exposable of the same type in the parent widget
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
options.thumbnailIndicators = (mediaContent.length > 1);
if(!options.thumbnailIndicators)
@ -652,23 +720,25 @@ export function ExposeMixin<B extends Constructor<LitElement>>(superclass : B)
protected expose_onclick(event : MouseEvent)
{
event.stopImmediatePropagation();
// Do not trigger expose view if one of the operator keys are held
if(event.altKey || event.ctrlKey || event.shiftKey || event.metaKey)
{
return;
}
event.stopImmediatePropagation();
// @ts-ignore Wants an argument, but does not require it
let fe = egw_get_file_editor_prefered_mimes();
if(this.exposeValue.mime.match(MIME_REGEX) && !this.exposeValue.mime.match(MIME_AUDIO_REGEX))
{
this._init_blueimp_gallery(event, this.exposeValue);
return false;
}
else if(this.exposeValue.mime.match(MIME_AUDIO_REGEX))
{
this._audio_player(this.exposeValue);
return false;
}
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,
cd: 'no' // needed to not reload framework in sharing
}), '', fe.edit_popup);
return false;
}
return true;
}
protected expose_onopen() {}
@ -840,6 +911,5 @@ export function ExposeMixin<B extends Constructor<LitElement>>(superclass : B)
}
protected expose_onclosed() {}
}
}

View File

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