diff --git a/assets/css/app.css b/assets/css/app.css index a5b7750b..84449721 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -693,4 +693,48 @@ table.dataTable { .dataTables_length { display: inline-flex; +} + +/****************************************** +* Typeahead menu +*******************************************/ + +.tt-query { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.tt-hint { + color: #999 +} + +.tt-menu { /* used to be tt-dropdown-menu in older versions */ + width: 422px; + margin-top: 4px; + padding: 4px 0; + background-color: #fff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-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); +} + +.tt-suggestion { + padding: 3px 20px; + line-height: 24px; +} + +.tt-suggestion.tt-cursor,.tt-suggestion:hover { + color: #fff; + background-color: #0097cf; + +} + +.tt-suggestion p { + margin: 0; } \ No newline at end of file diff --git a/assets/js/app.js b/assets/js/app.js index e0946877..b05161be 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -40,6 +40,8 @@ require( 'datatables.net-select-bs4' ); require('datatables.net-colreorder-bs4'); require('bootstrap-select'); require('jquery-form'); +require('corejs-typeahead/dist/typeahead.bundle.min'); +window.Bloodhound = require('corejs-typeahead/dist/bloodhound.js'); //Define jquery globally window.$ = window.jQuery = require("jquery"); diff --git a/assets/ts_src/event_listeners.ts b/assets/ts_src/event_listeners.ts index 805f3db6..55f58fa4 100644 --- a/assets/ts_src/event_listeners.ts +++ b/assets/ts_src/event_listeners.ts @@ -347,6 +347,31 @@ $(document).on("ajaxUI:start", function() { }); +//Register typeaheads +$(document).on("ajaxUI:reload ajaxUI:start", function () { + $('input[data-autocomplete]').each(function() { + //@ts-ignore + var engine = new Bloodhound({ + datumTokenizer: Bloodhound.tokenizers.obj.whitespace(''), + queryTokenizer: Bloodhound.tokenizers.obj.whitespace(''), + remote: { + url: $(this).data('autocomplete'), + wildcard: 'QUERY' + } + }); + + $(this).typeahead({ + hint: true, + highlight: true, + minLength: 1 + }, + { + name: 'states', + source: engine + }); + }) +}); + //Need for proper body padding, with every navbar height $(window).resize(function () { diff --git a/assets/tsconfig.json b/assets/tsconfig.json index 75fb90fd..5f7f0553 100644 --- a/assets/tsconfig.json +++ b/assets/tsconfig.json @@ -4,7 +4,7 @@ "target": "es5", "sourceMap": true, "typeRoots": ["../node_modules"], - "types": ["jquery", "bootstrap", "jquery.form", "bootstrap-treeview", "bootbox"] + "types": ["jquery", "bootstrap", "jquery.form", "bootstrap-treeview", "bootbox", "typeahead"] }, "exclude": [ "node_modules" diff --git a/composer.json b/composer.json index c482a408..93f57c79 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,8 @@ "twig/extra-bundle": "3.x-dev", "twig/intl-extra": "3.x-dev", "webmozart/assert": "^1.4", - "ext-bcmath": "*" + "ext-bcmath": "*", + "ext-json": "*" }, "require-dev": { "roave/security-advisories": "dev-master", diff --git a/package.json b/package.json index eee2ee02..7b36fd95 100644 --- a/package.json +++ b/package.json @@ -22,9 +22,11 @@ "@types/bootstrap-treeview": "^1.20.0", "@types/jquery": "^3.3.29", "@types/jquery.form": "^3.26.30", + "@types/typeahead": "^0.11.32", "bootbox": "^5.1.0", "bootstrap-fileinput": "^5.0.1", "bootstrap-select": "^1.13.8", + "corejs-typeahead": "^1.2.1", "datatables.net-bs4": "^1.10.19", "datatables.net-buttons-bs4": "^1.5.4", "datatables.net-colreorder-bs4": "^1.5.1", diff --git a/src/Controller/TypeaheadController.php b/src/Controller/TypeaheadController.php new file mode 100644 index 00000000..bc63aa26 --- /dev/null +++ b/src/Controller/TypeaheadController.php @@ -0,0 +1,69 @@ +find($query); + + + $normalizers = [ + new ObjectNormalizer() + ]; + $encoders = [ + new JsonEncoder() + ]; + $serializer = new Serializer($normalizers, $encoders); + $data = $serializer->serialize($array, 'json'); + return new JsonResponse($data, 200, [], true); + } +} \ No newline at end of file diff --git a/src/Form/AttachmentFormType.php b/src/Form/AttachmentFormType.php index d3edd9ec..befde37d 100644 --- a/src/Form/AttachmentFormType.php +++ b/src/Form/AttachmentFormType.php @@ -45,6 +45,8 @@ use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\UrlType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use Symfony\Component\Routing\RouterInterface; use Symfony\Component\Validator\Constraints\File; use Symfony\Component\Validator\Constraints\Url; use Symfony\Contracts\Translation\TranslatorInterface; @@ -53,11 +55,13 @@ class AttachmentFormType extends AbstractType { protected $attachment_helper; protected $trans; + protected $urlGenerator; - public function __construct(AttachmentHelper $attachmentHelper, TranslatorInterface $trans) + public function __construct(AttachmentHelper $attachmentHelper, TranslatorInterface $trans, UrlGeneratorInterface $urlGenerator) { $this->attachment_helper = $attachmentHelper; $this->trans = $trans; + $this->urlGenerator = $urlGenerator; } public function buildForm(FormBuilderInterface $builder, array $options) @@ -79,6 +83,8 @@ class AttachmentFormType extends AbstractType $builder->add('url', TextType::class, [ 'label' => $this->trans->trans('attachment.edit.url'), 'required' => false, + 'attr' => ['data-autocomplete' => $this->urlGenerator->generate('typeahead_builtInRessources', ['query' => 'QUERY']) + ], 'constraints' => [ $options['allow_builtins'] ? new UrlOrBuiltin() : new Url() ] diff --git a/src/Services/BuiltinAttachmentsFinder.php b/src/Services/BuiltinAttachmentsFinder.php index 53e2b288..ff298a8b 100644 --- a/src/Services/BuiltinAttachmentsFinder.php +++ b/src/Services/BuiltinAttachmentsFinder.php @@ -59,7 +59,7 @@ class BuiltinAttachmentsFinder ]); } - public function find(string $keyword, array $options) : array + public function find(string $keyword, array $options = []) : array { $finder = new Finder(); @@ -67,9 +67,20 @@ class BuiltinAttachmentsFinder $this->configureOptions($resolver); $options = $resolver->resolve($options); + if (empty($options['placeholders'])) { + return []; + } + //We search only files $finder->files(); - $finder->in($this->pathResolver->getFootprintsPath()); + //Add the folder for each placeholder + foreach ($options['placeholders'] as $placeholder) { + $tmp = $this->pathResolver->placeholderToRealPath($placeholder); + //Ignore invalid/deactivated placeholders: + if ($tmp !== null) { + $finder->in($tmp); + } + } //Apply filter if needed if (!empty($options['filename_filter'])) { diff --git a/yarn.lock b/yarn.lock index 4a364e4d..f8b3ebba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -769,6 +769,13 @@ resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.4.tgz#b4ffc7dc97b498c969b360a41eee247f82616370" integrity sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ== +"@types/typeahead@^0.11.32": + version "0.11.32" + resolved "https://registry.yarnpkg.com/@types/typeahead/-/typeahead-0.11.32.tgz#117693a253a8ad46b3824b47539982c093cc9296" + integrity sha512-5NkqKPwkBh2dGxFEJjc4Vt9/XsaGmx+tfXMfcJxWjPvCvvCFEKRCz+bz7ZfRAiO0e0Hh1foBol3anLzMY1Ea8A== + dependencies: + "@types/jquery" "*" + "@types/uglify-js@*": version "3.0.4" resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082" @@ -1942,6 +1949,13 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= +corejs-typeahead@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/corejs-typeahead/-/corejs-typeahead-1.2.1.tgz#345a8afe664cc494075b59b64777807f0b3f132b" + integrity sha1-NFqK/mZMxJQHW1m2R3eAfws/Eys= + dependencies: + jquery ">=1.11" + cosmiconfig@^5.0.0: version "5.2.1" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" @@ -3995,7 +4009,7 @@ jquery-form@^4.2.2: dependencies: jquery ">=1.7.2" -"jquery@>= 1.9.0", jquery@>=1.12.0, jquery@>=1.7, jquery@>=1.7.2, jquery@^3.3.1, jquery@^3.4.1: +"jquery@>= 1.9.0", jquery@>=1.11, jquery@>=1.12.0, jquery@>=1.7, jquery@>=1.7.2, jquery@^3.3.1, jquery@^3.4.1: version "3.4.1" resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.1.tgz#714f1f8d9dde4bdfa55764ba37ef214630d80ef2" integrity sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw==