Show a preview image in builtin attachment select autocomplete.

This commit is contained in:
Jan Böhmer 2020-06-01 14:51:38 +02:00
parent aa95f130db
commit f0d0a78f65
6 changed files with 65 additions and 6 deletions

View file

@ -772,6 +772,9 @@ div.dataTables_wrapper div.dataTables_info {
-webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2); -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2);
-moz-box-shadow: 0 5px 10px rgba(0,0,0,.2); -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2);
box-shadow: 0 5px 10px rgba(0,0,0,.2); box-shadow: 0 5px 10px rgba(0,0,0,.2);
max-height: 200px;
overflow-y: auto;
} }
.tt-suggestion { .tt-suggestion {
@ -875,3 +878,10 @@ div.dataTables_wrapper div.dataTables_info {
.carousel:hover .carousel-control { .carousel:hover .carousel-control {
display: flex; display: flex;
} }
/***********************************************
* Typeahead image
***********************************************/
.typeahead-image {
width: 100%;
}

View file

@ -432,6 +432,7 @@ $(document).on("ajaxUI:reload ajaxUI:start attachment:create", function () {
} }
}); });
//@ts-ignore
$(this).typeahead({ $(this).typeahead({
hint: true, hint: true,
highlight: true, highlight: true,
@ -439,7 +440,18 @@ $(document).on("ajaxUI:reload ajaxUI:start attachment:create", function () {
}, },
{ {
name: 'states', name: 'states',
source: engine source: engine,
limit: 250,
templates: {
suggestion: function(data) {
if (typeof data === "string") {
return "<div>" + data + "</div>";
} else if(typeof data === "object" && typeof data.image === "string") {
return "<div class='row m-0'><div class='col-2 pl-0 pr-1'><img class='typeahead-image' src='" + data.image + "'/></div><div class='col-10'>" + data.name + "</div></div>"
}
},
},
display: 'name',
}); });
//Make the typeahead input fill the container (remove block-inline attr) //Make the typeahead input fill the container (remove block-inline attr)

View file

@ -42,9 +42,11 @@ declare(strict_types=1);
namespace App\Controller; namespace App\Controller;
use App\Services\Attachments\AttachmentURLGenerator;
use App\Services\Attachments\BuiltinAttachmentsFinder; use App\Services\Attachments\BuiltinAttachmentsFinder;
use App\Services\TagFinder; use App\Services\TagFinder;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Asset\Packages;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
@ -59,6 +61,15 @@ use Symfony\Component\Serializer\Serializer;
*/ */
class TypeaheadController extends AbstractController class TypeaheadController extends AbstractController
{ {
protected $urlGenerator;
protected $assets;
public function __construct(AttachmentURLGenerator $URLGenerator, Packages $assets)
{
$this->urlGenerator = $URLGenerator;
$this->assets = $assets;
}
/** /**
* @Route("/builtInResources/search", name="typeahead_builtInRessources") * @Route("/builtInResources/search", name="typeahead_builtInRessources")
* *
@ -69,6 +80,15 @@ class TypeaheadController extends AbstractController
$query = $request->get('query'); $query = $request->get('query');
$array = $finder->find($query); $array = $finder->find($query);
$result = [];
foreach ($array as $path) {
$result[] = [
'name' => $path,
'image' => $this->assets->getUrl($this->urlGenerator->placeholderPathToAssetPath($path)),
];
}
$normalizers = [ $normalizers = [
new ObjectNormalizer(), new ObjectNormalizer(),
]; ];
@ -76,7 +96,7 @@ class TypeaheadController extends AbstractController
new JsonEncoder(), new JsonEncoder(),
]; ];
$serializer = new Serializer($normalizers, $encoders); $serializer = new Serializer($normalizers, $encoders);
$data = $serializer->serialize($array, 'json'); $data = $serializer->serialize($result, 'json');
return new JsonResponse($data, 200, [], true); return new JsonResponse($data, 200, [], true);
} }

View file

@ -101,6 +101,7 @@ class AttachmentPathResolver
/** /**
* Converts a path passed by parameter from services.yaml (which can be an absolute path or relative to project dir) * Converts a path passed by parameter from services.yaml (which can be an absolute path or relative to project dir)
* to an absolute path. When a relative path is passed, the directory must exist or null is returned. * to an absolute path. When a relative path is passed, the directory must exist or null is returned.
* Returns an absolute path with "/" no matter, what system is used.
* *
* @internal * @internal
* *
@ -132,8 +133,8 @@ class AttachmentPathResolver
return null; return null;
} }
//Otherwise return resolved path //Normalize file path (use / instead of \)
return $tmp; return str_replace('\\', '/', $tmp);
} }
/** /**

View file

@ -91,6 +91,8 @@ class AttachmentURLGenerator
$public_path = $this->public_path; $public_path = $this->public_path;
} }
//Our absolute path must begin with public path or we can not use it for asset pathes. //Our absolute path must begin with public path or we can not use it for asset pathes.
if (0 !== strpos($absolute_path, $public_path)) { if (0 !== strpos($absolute_path, $public_path)) {
return null; return null;
@ -100,6 +102,19 @@ class AttachmentURLGenerator
return substr($absolute_path, strlen($public_path) + 1); return substr($absolute_path, strlen($public_path) + 1);
} }
/**
* Converts a placeholder path to a path to a image path.
*
* @param string $placeholder_path the placeholder path that should be converted
*
* @return string|null
*/
public function placeholderPathToAssetPath(string $placeholder_path): ?string
{
$absolute_path = $this->pathResolver->placeholderToRealPath($placeholder_path);
return $this->absolutePathToAssetPath($absolute_path);
}
/** /**
* Returns a URL under which the attachment file can be viewed. * Returns a URL under which the attachment file can be viewed.
*/ */

View file

@ -87,8 +87,9 @@ class AttachmentPathResolverTest extends WebTestCase
$this->assertSame(self::$projectDir_orig, self::$service->parameterToAbsolutePath(self::$projectDir)); $this->assertSame(self::$projectDir_orig, self::$service->parameterToAbsolutePath(self::$projectDir));
//Relative pathes should be resolved //Relative pathes should be resolved
$this->assertSame(self::$projectDir_orig.DIRECTORY_SEPARATOR.'src', self::$service->parameterToAbsolutePath('src')); $expected = str_replace('\\', '/',self::$projectDir_orig.DIRECTORY_SEPARATOR.'src');
$this->assertSame(self::$projectDir_orig.DIRECTORY_SEPARATOR.'src', self::$service->parameterToAbsolutePath('./src')); $this->assertSame($expected, self::$service->parameterToAbsolutePath('src'));
$this->assertSame($expected, self::$service->parameterToAbsolutePath('./src'));
//Invalid pathes should return null //Invalid pathes should return null
$this->assertNull(self::$service->parameterToAbsolutePath('/this/path/does/not/exist')); $this->assertNull(self::$service->parameterToAbsolutePath('/this/path/does/not/exist'));