allow to use and automatic find bootstrap icons via egw.image('<bootstrap-name>') or Image::find() on server-side

This commit is contained in:
ralf 2024-08-07 18:28:28 +02:00
parent c4e674d177
commit 1ee4d91ea2
4 changed files with 118 additions and 14 deletions

View File

@ -90,7 +90,7 @@ export const ButtonMixin = <T extends Constructor>(superclass : T) => class exte
width: 16px !important; width: 16px !important;
} }
::slotted(et2-image) { ::slotted(et2-image) {
width: 20px; height: 20px;
max-width: 20px; max-width: 20px;
display: flex; display: flex;
} }
@ -193,7 +193,7 @@ export const ButtonMixin = <T extends Constructor>(superclass : T) => class exte
set image(new_image : string) set image(new_image : string)
{ {
let oldValue = this.__image; let oldValue = this.__image;
if(new_image.indexOf("http") >= 0 || new_image.indexOf(this.egw().webserverUrl) >= 0) if(new_image.startsWith("http") || new_image.startsWith(this.egw().webserverUrl))
{ {
this.__image = new_image this.__image = new_image
} }

View File

@ -87,7 +87,7 @@ egw.extend('images', egw.MODULE_GLOBAL, function()
} }
} }
// own instance specific images in vfs have highest precedence // own instance specific images in vfs have the highest precedence
tries['vfs']=_name; tries['vfs']=_name;
if (typeof images['vfs'] != 'undefined' && typeof images['vfs'][_name] == 'string') if (typeof images['vfs'] != 'undefined' && typeof images['vfs'][_name] == 'string')
{ {
@ -98,6 +98,16 @@ egw.extend('images', egw.MODULE_GLOBAL, function()
{ {
return this.webserverUrl+images[_app][_name]; return this.webserverUrl+images[_app][_name];
} }
tries['global'] = _name;
if (typeof images['global'] !== 'undefined' && typeof images['global'][_name] === 'string')
{
return this.image(images['global'][_name], _app);
}
tries['bootstrap'] = _name;
if (typeof images['bootstrap'] !== 'undefined' && typeof images['bootstrap'][_name] == 'string')
{
return this.webserverUrl+images['bootstrap'][_name];
}
tries['api'] = _name; tries['api'] = _name;
if (typeof images['api'] != 'undefined' && typeof images['api'][_name] == 'string') if (typeof images['api'] != 'undefined' && typeof images['api'][_name] == 'string')
{ {
@ -190,4 +200,3 @@ egw.extend('images', egw.MODULE_GLOBAL, function()
} }
}; };
}); });

View File

@ -19,6 +19,20 @@ namespace EGroupware\Api;
*/ */
class Image class Image
{ {
/**
* Global lookup table mapping logic image-names to selected bootstrap icons or existing icons:
* - edit --> pencil-fill
* - save --> api/save as bootstrap's save does not match, but shadows api/save, if not remapped here
*
* @var string[]
*/
static $global2bootstrap = [
'edit' => 'pencil-fill',
'save' => 'api/save', // as bootstrap's save would shadow api/save and is not fitting
'apply' => 'floppy',
'cancel' => 'x-square',
'delete' => 'trash3',
];
/** /**
* Searches a appname, template and maybe language and type-specific image * Searches a appname, template and maybe language and type-specific image
* *
@ -49,7 +63,7 @@ class Image
$webserver_url = $GLOBALS['egw_info']['server']['webserver_url']; $webserver_url = $GLOBALS['egw_info']['server']['webserver_url'];
// instance specific images have highest precedence // instance specific images have the highest precedence
if (isset($image_map['vfs'][$image.$extension])) if (isset($image_map['vfs'][$image.$extension]))
{ {
$url = $webserver_url.$image_map['vfs'][$image.$extension]; $url = $webserver_url.$image_map['vfs'][$image.$extension];
@ -59,6 +73,20 @@ class Image
{ {
$url = $webserver_url.$image_map[$app][$image.$extension]; $url = $webserver_url.$image_map[$app][$image.$extension];
} }
// then our globals lookup table $img2bootstrap
elseif(isset($image_map['global'][$image]))
{
$image = $image_map['global'][$image];
}
if (isset($url))
{
// keep it
}
// then bootstrap icons
elseif(isset($image_map['bootstrap'][$image]))
{
$url = $webserver_url.$image_map['bootstrap'][$image];
}
// then api // then api
elseif(isset($image_map['api'][$image.$extension])) elseif(isset($image_map['api'][$image.$extension]))
{ {
@ -78,7 +106,7 @@ class Image
return $url; return $url;
} }
// if image not found, check if it has an extension and try withoug // if image not found, check if it has an extension and try without
if (strpos($image, '.') !== false) if (strpos($image, '.') !== false)
{ {
$name = null; $name = null;
@ -133,15 +161,18 @@ class Image
// priority: : SVG->PNG->JPG->GIF->ICO // priority: : SVG->PNG->JPG->GIF->ICO
$img_types = array('svg','png','jpg','gif','ico'); $img_types = array('svg','png','jpg','gif','ico');
$map = array(); $map = ['global' => self::$global2bootstrap];
foreach(scandir(EGW_SERVER_ROOT) as $app) foreach(scandir(EGW_SERVER_ROOT) as $app)
{ {
if ($app[0] == '.' || !is_dir(EGW_SERVER_ROOT.'/'.$app) || !file_exists(EGW_SERVER_ROOT.'/'.$app.'/templates')) continue; if ($app[0] === '.' || !is_dir(EGW_SERVER_ROOT.'/'.$app) ||
!file_exists(EGW_SERVER_ROOT.'/'.$app.'/templates') && $app !== 'node_modules')
{
continue;
}
$app_map =& $map[$app]; $app_map =& $map[$app];
if (true) $app_map = array(); if (true) $app_map = array();
$imagedirs = array(); $imagedirs = array();
if (Header\UserAgent::mobile()) if (Header\UserAgent::mobile() && $app !== 'node_modules')
{ {
$imagedirs[] = '/'.$app.'/templates/mobile/images'; $imagedirs[] = '/'.$app.'/templates/mobile/images';
} }
@ -149,12 +180,21 @@ class Image
{ {
$imagedirs[] = $GLOBALS['egw']->framework->template_dir.'/images'; $imagedirs[] = $GLOBALS['egw']->framework->template_dir.'/images';
} }
elseif ($app === 'node_modules')
{
unset($map[$app]);
$app_map =& $map[$app='bootstrap'];
$imagedirs[] = '/node_modules/bootstrap-icons/icons';
}
else else
{ {
$imagedirs[] = '/'.$app.'/templates/'.$template_set.'/images'; $imagedirs[] = '/'.$app.'/templates/'.$template_set.'/images';
} }
if ($app !== 'bootstrap')
{
if ($template_set != 'idots') $imagedirs[] = '/'.$app.'/templates/idots/images'; if ($template_set != 'idots') $imagedirs[] = '/'.$app.'/templates/idots/images';
$imagedirs[] = '/'.$app.'/templates/default/images'; $imagedirs[] = '/'.$app.'/templates/default/images';
}
foreach($imagedirs as $imagedir) foreach($imagedirs as $imagedir)
{ {

55
icons-new.html Normal file
View File

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>New Bootstrap Icons</title>
<base href="https://boulder.egroupware.org/egroupware/">
</head>
<body>
<table>
<h1>New <a href="https://icons.getbootstrap.com/" target="_blank">Bootstrap</a> Icons</h1>
<tr>
<th>Name</th>
<th>Old</th>
<th>New</th>
<th>Alternatives / Notes</th>
</tr>
<tr>
<td>save</td>
<td><img src="api/templates/default/images/save.svg"/></td>
<td><img src="node_modules/bootstrap-icons/icons/floppy.svg" title="floppy"/></td>
<td>braucht neues Icon, evtl. Kombi aus apply & cancel (im unteren rechten Viertel)</td>
</tr>
<tr>
<td>apply</td>
<td><img src="api/templates/default/images/apply.svg"/></td>
<td><img src="node_modules/bootstrap-icons/icons/floppy.svg" title="floppy"/></td>
<td></td>
</tr>
<tr>
<td>cancel</td>
<td><img src="api/templates/default/images/cancel.svg"/></td>
<td><img src="node_modules/bootstrap-icons/icons/x-square.svg" title="x-square"/></td>
<td></td>
</tr>
<tr>
<td>apply</td>
<td><img src="api/templates/default/images/delete.svg"/></td>
<td><img src="node_modules/bootstrap-icons/icons/trash.svg" title="trash"/></td>
<td></td>
</tr>
</table>
<style>
td > img {
text-align: center;
height: 40px;
}
th {
text-align: left;
}
td, th {
padding: 5px;
}
</style>
</body>
</html>