From 3bd65ee2f0bec8bbcef67e4edb5a28d0a06e8206 Mon Sep 17 00:00:00 2001 From: Olivier Legat Date: Fri, 9 Apr 2021 15:09:36 +0200 Subject: [PATCH] tags an search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit d72af19ac7c028c514ee9055386c65bf4fcc0ffc Author: Olivier Legat Date: Fri Apr 9 15:08:30 2021 +0200 recherche - filtrage basique commit 926efbe97826d6ab8168ccb93f329283c11fd4ec Author: Olivier Legat Date: Fri Apr 9 14:15:17 2021 +0200 placeholder add tag commit a93d542a6a294bf214a952236bc3cd708b019241 Author: Olivier Legat Date: Fri Apr 9 14:11:39 2021 +0200 résistance de l'ajour de tags au accents, majuscules, etc.. commit c5eb6296e9ae2fff2fb7e15a93349bfc965cac53 Author: Olivier Legat Date: Fri Apr 9 13:34:59 2021 +0200 BO tags sur produits --- .../Controllers/Bo/ProductsController.php | 34 +- app/Http/Controllers/ProductsController.php | 22 +- app/Models/Product.php | 6 + app/Models/Tag.php | 18 + .../2021_04_09_081311_create_tags_table.php | 37 + ..._04_09_081345_create_product_tag_table.php | 31 + database/seeders/TagsSeeder.php | 58 + package-lock.json | 6 + package.json | 1 + public/b-o/js/app.js | 1534 ++++++++++++++++- resources/js/app.js | 3 + resources/js/components/AutocompleteTags.vue | 43 + resources/views/bo/products/edit.blade.php | 4 + resources/views/front/canard/search.blade.php | 16 +- resources/views/layouts/bo-layout.blade.php | 44 +- 15 files changed, 1840 insertions(+), 17 deletions(-) create mode 100644 app/Models/Tag.php create mode 100644 database/migrations/2021_04_09_081311_create_tags_table.php create mode 100644 database/migrations/2021_04_09_081345_create_product_tag_table.php create mode 100644 database/seeders/TagsSeeder.php create mode 100644 resources/js/components/AutocompleteTags.vue diff --git a/app/Http/Controllers/Bo/ProductsController.php b/app/Http/Controllers/Bo/ProductsController.php index 87ab026..fb0a20a 100644 --- a/app/Http/Controllers/Bo/ProductsController.php +++ b/app/Http/Controllers/Bo/ProductsController.php @@ -7,6 +7,7 @@ use App\Models\OldSlug; use App\Models\FoodProduct; use App\Models\Product; use App\Models\Range; +use App\Models\Tag; use Illuminate\Http\Request; use Illuminate\Support\Str; @@ -141,7 +142,9 @@ class ProductsController extends Controller $ranges = Range::all(); - return view('bo.products.edit', compact('product', 'ranges')); + $existingTags = Tag::all(); + $selectedtags = $product->tags; + return view('bo.products.edit', compact('product', 'ranges','existingTags','selectedtags')); } public function update(Request $request, $id) @@ -161,6 +164,7 @@ class ProductsController extends Controller $star = $request->star === null ? 0 : 1; $slug = Str::slug($name); $rangeId = $request->range_id; + $tags = $request->tags; $request->validate([ 'name' => 'required|string|max:255', @@ -246,9 +250,37 @@ class ProductsController extends Controller $this->$methodName($request, $product->id); } + $arTagIds = array(); + foreach($tags as $tag) { + $oTag = json_decode($tag); + if(empty($oTag->id)) { + //we need a new tag + $arTagIds[] = $this->storeTag($oTag); + } else { + $arTagIds[] = $oTag->id; + } + + } + //prise en charge de la liaison avec les produits + $product->tags()->sync($arTagIds); + return redirect()->route('bo.products.edit', $product->id)->with('success', 'Modifications enregistrés !'); } + public function storeTag($oTag) + { + $slug = Str::slug($oTag->label); + $tag = Tag::where('slug', $slug)->first(); + if($tag === null) { + //si on pas encore ce tag on le crée + $tag = new Tag(); + $tag->label = $oTag->label; + $tag->slug = Str::slug($oTag->label); + $tag->save(); + } + return $tag->id; + } + public function destroy($id) { $product = Product::findOrFail($id); diff --git a/app/Http/Controllers/ProductsController.php b/app/Http/Controllers/ProductsController.php index b849a70..94e898d 100644 --- a/app/Http/Controllers/ProductsController.php +++ b/app/Http/Controllers/ProductsController.php @@ -5,6 +5,7 @@ namespace App\Http\Controllers; use App\Models\Product; use App\Models\Range; use Illuminate\Http\Request; +use Illuminate\Support\Str; class ProductsController extends Controller { @@ -40,7 +41,24 @@ class ProductsController extends Controller public function allProducts(Request $request) { //do better - $products = Product::where('status', 1)->paginate(12); - return view ('search', compact('products')); + + $filter = $request->query('filter'); + $filtertag = $request->query('tag'); + if (!empty($filter)) { + $products = Product::where('status', 1) + ->where('name', 'like', '%'.$filter.'%') + ->paginate(12); + } elseif (!empty($filtertag)) { + $products = Product::where('status', 1) + ->whereHas('tags', function($q) use($filtertag) + { + $q->where('slug', '=', Str::slug($filtertag)); + }) + ->paginate(12); + } else { + $products = Product::where('status', 1)->paginate(12); + } + + return view ('search', compact('products', 'filter', 'filtertag')); } } diff --git a/app/Models/Product.php b/app/Models/Product.php index f026e1f..98d84dc 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -264,4 +264,10 @@ class Product extends Model implements Buyable { return $this->belongsTo(TaxRate::class, 'tax_rate_id'); } + + //tags + public function tags() + { + return $this->belongsToMany(Tag::class); + } } diff --git a/app/Models/Tag.php b/app/Models/Tag.php new file mode 100644 index 0000000..b86f19d --- /dev/null +++ b/app/Models/Tag.php @@ -0,0 +1,18 @@ +belongsToMany(Product::class); + } +} diff --git a/database/migrations/2021_04_09_081311_create_tags_table.php b/database/migrations/2021_04_09_081311_create_tags_table.php new file mode 100644 index 0000000..512c665 --- /dev/null +++ b/database/migrations/2021_04_09_081311_create_tags_table.php @@ -0,0 +1,37 @@ +id(); + $table->string('label'); + $table->string('slug'); + $table->collation = 'utf8mb4_unicode_ci'; + }); + + $seeder = new TagsSeeder(); + $seeder->run(); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('tags'); + } +} diff --git a/database/migrations/2021_04_09_081345_create_product_tag_table.php b/database/migrations/2021_04_09_081345_create_product_tag_table.php new file mode 100644 index 0000000..cd589f4 --- /dev/null +++ b/database/migrations/2021_04_09_081345_create_product_tag_table.php @@ -0,0 +1,31 @@ +foreignId('product_id')->constrained('products'); //produit considéré + $table->foreignId('tag_id')->constrained('tags'); //tag associée + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('product_tag'); + } +} diff --git a/database/seeders/TagsSeeder.php b/database/seeders/TagsSeeder.php new file mode 100644 index 0000000..9d3b63b --- /dev/null +++ b/database/seeders/TagsSeeder.php @@ -0,0 +1,58 @@ +label = "Canard"; + $canard->slug = Str::slug($canard->label); + $canard->save(); + + $poulet = new Tag(); + $poulet->label = "Poulet"; + $poulet->slug = Str::slug($poulet->label); + $poulet->save(); + + $dinde = new Tag(); + $dinde->label = "Dinde"; + $dinde->slug = Str::slug($dinde->label); + $dinde->save(); + + $charcuterie = new Tag(); + $charcuterie->label = "Charcuteries"; + $charcuterie->slug = Str::slug($charcuterie->label); + $charcuterie->save(); + + $panes = new Tag(); + $panes->label = "Panés"; + $panes->slug = Str::slug($panes->label); + $panes->save(); + + $dinde = new Tag(); + $dinde->label = "Dinde"; + $dinde->slug = Str::slug($dinde->label); + $dinde->save(); + + $produits_surgeles = new Tag(); + $produits_surgeles->label = "Produits surgelés"; + $produits_surgeles->slug = Str::slug($produits_surgeles->label); + $produits_surgeles->save(); + + $paniers = new Tag(); + $paniers->label = "Paniers garnis"; + $paniers->slug = Str::slug($paniers->label); + $paniers->save(); + } +} diff --git a/package-lock.json b/package-lock.json index e639032..48ba013 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1124,6 +1124,12 @@ "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==", "dev": true }, + "@voerro/vue-tagsinput": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@voerro/vue-tagsinput/-/vue-tagsinput-2.7.1.tgz", + "integrity": "sha512-G7ClILHgtc/D1vEw9qp6dlsAstlhwLDkPvEp6w1iY/dmSzu4hhxaMk8jyahjxQRDgiLlrAikESOsfkVhy18YwQ==", + "dev": true + }, "@vue/component-compiler-utils": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.2.0.tgz", diff --git a/package.json b/package.json index 0fcf9c0..820c1c0 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --config=node_modules/laravel-mix/setup/webpack.config.js" }, "devDependencies": { + "@voerro/vue-tagsinput": "^2.7.1", "axios": "^0.21.1", "bootstrap": "^4.6.0", "cross-env": "^7.0", diff --git a/public/b-o/js/app.js b/public/b-o/js/app.js index e8cb0e8..f813833 100644 --- a/public/b-o/js/app.js +++ b/public/b-o/js/app.js @@ -86,6 +86,93 @@ /************************************************************************/ /******/ ({ +/***/ "./node_modules/@voerro/vue-tagsinput/src/VoerroTagsInput.vue": +/*!********************************************************************!*\ + !*** ./node_modules/@voerro/vue-tagsinput/src/VoerroTagsInput.vue ***! + \********************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _VoerroTagsInput_vue_vue_type_template_id_d29272ca___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./VoerroTagsInput.vue?vue&type=template&id=d29272ca& */ "./node_modules/@voerro/vue-tagsinput/src/VoerroTagsInput.vue?vue&type=template&id=d29272ca&"); +/* harmony import */ var _VoerroTagsInput_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./VoerroTagsInput.vue?vue&type=script&lang=js& */ "./node_modules/@voerro/vue-tagsinput/src/VoerroTagsInput.vue?vue&type=script&lang=js&"); +/* empty/unused harmony star reexport *//* harmony import */ var _vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../vue-loader/lib/runtime/componentNormalizer.js */ "./node_modules/vue-loader/lib/runtime/componentNormalizer.js"); + + + + + +/* normalize component */ + +var component = Object(_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__["default"])( + _VoerroTagsInput_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__["default"], + _VoerroTagsInput_vue_vue_type_template_id_d29272ca___WEBPACK_IMPORTED_MODULE_0__["render"], + _VoerroTagsInput_vue_vue_type_template_id_d29272ca___WEBPACK_IMPORTED_MODULE_0__["staticRenderFns"], + false, + null, + null, + null + +) + +/* hot reload */ +if (false) { var api; } +component.options.__file = "node_modules/@voerro/vue-tagsinput/src/VoerroTagsInput.vue" +/* harmony default export */ __webpack_exports__["default"] = (component.exports); + +/***/ }), + +/***/ "./node_modules/@voerro/vue-tagsinput/src/VoerroTagsInput.vue?vue&type=script&lang=js&": +/*!*********************************************************************************************!*\ + !*** ./node_modules/@voerro/vue-tagsinput/src/VoerroTagsInput.vue?vue&type=script&lang=js& ***! + \*********************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _vue_loader_lib_index_js_vue_loader_options_VoerroTagsInput_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../vue-loader/lib??vue-loader-options!./VoerroTagsInput.vue?vue&type=script&lang=js& */ "./node_modules/vue-loader/lib/index.js?!./node_modules/@voerro/vue-tagsinput/src/VoerroTagsInput.vue?vue&type=script&lang=js&"); +/* empty/unused harmony star reexport */ /* harmony default export */ __webpack_exports__["default"] = (_vue_loader_lib_index_js_vue_loader_options_VoerroTagsInput_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__["default"]); + +/***/ }), + +/***/ "./node_modules/@voerro/vue-tagsinput/src/VoerroTagsInput.vue?vue&type=template&id=d29272ca&": +/*!***************************************************************************************************!*\ + !*** ./node_modules/@voerro/vue-tagsinput/src/VoerroTagsInput.vue?vue&type=template&id=d29272ca& ***! + \***************************************************************************************************/ +/*! exports provided: render, staticRenderFns */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _vue_loader_lib_loaders_templateLoader_js_vue_loader_options_vue_loader_lib_index_js_vue_loader_options_VoerroTagsInput_vue_vue_type_template_id_d29272ca___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../vue-loader/lib/loaders/templateLoader.js??vue-loader-options!../../../vue-loader/lib??vue-loader-options!./VoerroTagsInput.vue?vue&type=template&id=d29272ca& */ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./node_modules/@voerro/vue-tagsinput/src/VoerroTagsInput.vue?vue&type=template&id=d29272ca&"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "render", function() { return _vue_loader_lib_loaders_templateLoader_js_vue_loader_options_vue_loader_lib_index_js_vue_loader_options_VoerroTagsInput_vue_vue_type_template_id_d29272ca___WEBPACK_IMPORTED_MODULE_0__["render"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "staticRenderFns", function() { return _vue_loader_lib_loaders_templateLoader_js_vue_loader_options_vue_loader_lib_index_js_vue_loader_options_VoerroTagsInput_vue_vue_type_template_id_d29272ca___WEBPACK_IMPORTED_MODULE_0__["staticRenderFns"]; }); + + + +/***/ }), + +/***/ "./node_modules/@voerro/vue-tagsinput/src/main.js": +/*!********************************************************!*\ + !*** ./node_modules/@voerro/vue-tagsinput/src/main.js ***! + \********************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _VoerroTagsInput_vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./VoerroTagsInput.vue */ "./node_modules/@voerro/vue-tagsinput/src/VoerroTagsInput.vue"); + + +window.VoerroTagsInput = _VoerroTagsInput_vue__WEBPACK_IMPORTED_MODULE_0__["default"]; + +/* harmony default export */ __webpack_exports__["default"] = (_VoerroTagsInput_vue__WEBPACK_IMPORTED_MODULE_0__["default"]); + +/***/ }), + /***/ "./node_modules/axios/index.js": /*!*************************************!*\ !*** ./node_modules/axios/index.js ***! @@ -1944,6 +2031,55 @@ module.exports = { }; +/***/ }), + +/***/ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/AutoCompleteTags.vue?vue&type=script&lang=js&": +/*!***************************************************************************************************************************************************************************!*\ + !*** ./node_modules/babel-loader/lib??ref--4-0!./node_modules/vue-loader/lib??vue-loader-options!./resources/js/components/AutoCompleteTags.vue?vue&type=script&lang=js& ***! + \***************************************************************************************************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +// +// +// +// +// +// +// +// +// +// +// +// +/* harmony default export */ __webpack_exports__["default"] = ({ + components: { + VoerroTagsInput: VoerroTagsInput + }, + props: { + dbexistingtags: { + type: String + }, + dbselectedtags: { + type: String + } + }, + data: function data() { + return { + selectedTags: [], + existingtags: [] + }; + }, + mounted: function mounted() { + console.log('Autocomplete Tags Component mounted.'); + this.existingtags = JSON.parse(this.dbexistingtags); + this.selectedTags = JSON.parse(this.dbselectedtags); + }, + methods: {} +}); + /***/ }), /***/ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/Faq.vue?vue&type=script&lang=js&": @@ -6688,6 +6824,25 @@ function generate(num) { //# sourceMappingURL=bootstrap.js.map +/***/ }), + +/***/ "./node_modules/css-loader/index.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/AutoCompleteTags.vue?vue&type=style&index=0&id=ce297ba8&scoped=true&lang=css&": +/*!**********************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/css-loader??ref--7-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--7-2!./node_modules/vue-loader/lib??vue-loader-options!./resources/js/components/AutoCompleteTags.vue?vue&type=style&index=0&id=ce297ba8&scoped=true&lang=css& ***! + \**********************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +exports = module.exports = __webpack_require__(/*! ../../../node_modules/css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false); +// imports +exports.push([module.i, "@import url(https://cdn.jsdelivr.net/npm/@voerro/vue-tagsinput@2.7.1/dist/style.css);", ""]); + +// module +exports.push([module.i, "\n", ""]); + +// exports + + /***/ }), /***/ "./node_modules/css-loader/index.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/Faq.vue?vue&type=style&index=0&id=5546b00a&scoped=true&lang=css&": @@ -37954,6 +38109,36 @@ process.umask = function() { return 0; }; !function(e,t){ true?t(exports):undefined}(this,function(e){"use strict";var l,t,r="smooth-dnd-container-instance",f="smooth-dnd-draggable-wrapper",o="animated",p="__smooth_dnd_draggable_translation_value",u="__smooth_dnd_draggable_visibility_value",v="smooth-dnd-ghost",g="smooth-dnd-container",d="smooth-dnd-extra-size-for-insertion",h="smooth-dnd-stretcher-element",y="smooth-dnd-stretcher-instance",s="smooth-dnd-disable-touch-action",c="smooth-dnd-no-user-select",i="smooth-dnd-prevent-auto-scroll-class",b="smooth-dnd-drop-preview-default-class",w="smooth-dnd-drop-preview-inner-class",x="smooth-dnd-drop-preview-constant-class",E="smooth-dnd-drop-preview-flex-container-class",n=Object.freeze({containerInstance:r,defaultGroupName:"@@smooth-dnd-default-group@@",wrapperClass:f,defaultGrabHandleClass:"smooth-dnd-default-grap-handle",animationClass:o,translationValue:p,visibilityValue:u,ghostClass:v,containerClass:g,extraSizeForInsertion:d,stretcherElementClass:h,stretcherElementInstance:y,isDraggableDetached:"smoth-dnd-is-draggable-detached",disbaleTouchActions:s,noUserSelectClass:c,preventAutoScrollClass:i,dropPlaceholderDefaultClass:b,dropPlaceholderInnerClass:w,dropPlaceholderWrapperClass:x,dropPlaceholderFlexContainerClass:E}),C={groupName:void 0,behaviour:"move",orientation:"vertical",getChildPayload:void 0,animationDuration:250,autoScrollEnabled:!0,shouldAcceptDrop:void 0,shouldAnimateDrop:void 0};function a(e){return(a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function m(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function D(e){return function(e){if(Array.isArray(e)){for(var t=0,n=new Array(e.length);te.clientWidth:e.scrollHeight>e.clientHeight},T=function(e,t){var n=e,o=t||I(e);for(n=e.parentElement;n;)P(n,"x")&&B(n,"x")&&(o=S(o,n.getBoundingClientRect(),"x")),P(n,"y")&&B(n,"y")&&(o=S(o,n.getBoundingClientRect(),"y")),n=n.parentElement;return o},z=function(e,n){for(var o=e;o;){if(o[r]){var t=function(){var t=o[r];if(n.some(function(e){return e===t}))return{v:t}}();if("object"===a(t))return t.v}o=o.parentElement}return null},N=function(e,t){for(var n=e;n;){if(n.matches(t))return n;n=n.parentElement}return null},L=function(e,t){return-1=e.children.length?e.appendChild(t):e.insertBefore(t,e.children[n])},V=function(){window.getSelection?window.getSelection().empty?window.getSelection().empty():window.getSelection().removeAllRanges&&window.getSelection().removeAllRanges():window.document.selection&&window.document.selection.empty()},X=function(e){if(e){var t=window.getComputedStyle(e);if(t)return t.cursor}return null};function H(e){return!(e.bottom<=e.top||e.right<=e.left)}function Y(e){var s=e.element,c=e.draggables;return function(e,t){var n=e,o=n.removedIndex,r=n.addedIndex,i=n.droppedElement,a=null;if(null!==o&&(a=_(s,o),c.splice(o,1)),null!==r){var l=window.document.createElement("div");l.className="".concat(f),l.appendChild(a&&a.firstElementChild?a.firstElementChild:i),F(s,l,r),r>=c.length?c.push(l):c.splice(r,0,l)}t&&t(e)}}var k=Object.freeze({domDropHandler:Y,reactDropHandler:function(){return{handler:function(){return function(e,t){t&&t(e)}}}}}),G={size:"offsetWidth",distanceToParent:"offsetLeft",translate:"transform",begin:"left",end:"right",dragPosition:"x",scrollSize:"scrollWidth",offsetSize:"offsetWidth",scrollValue:"scrollLeft",scale:"scaleX",setSize:"width",setters:{translate:function(e){return"translate3d(".concat(e,"px, 0, 0)")}}},W={size:"offsetHeight",distanceToParent:"offsetTop",translate:"transform",begin:"top",end:"bottom",dragPosition:"y",scrollSize:"scrollHeight",offsetSize:"offsetHeight",scrollValue:"scrollTop",scale:"scaleY",setSize:"height",setters:{translate:function(e){return"translate3d(0,".concat(e,"px, 0)")}}};function q(n,s,e){n[d]=0;var o=function(o){return{get:function(e,t){return e[o[t]||t]},set:function(e,t,n){e[o[t]]=o.setters[t]?o.setters[t](n):n}}}("horizontal"===s?G:W),c={translation:0};function t(){r(n),function(e){var t=e.getBoundingClientRect();c.scaleX=e.offsetWidth?(t.right-t.left)/e.offsetWidth:1,c.scaleY=e.offsetHeight?(t.bottom-t.top)/e.offsetHeight:1}(n)}function r(e){c.rect=I(e);var t=T(e,c.rect);H(t)&&(c.lastVisibleRect=c.visibleRect),c.visibleRect=t}function i(e){var t=e;if(t.tagName){var n=t.getBoundingClientRect();return"vertical"===s?n.bottom-n.top:n.right-n.left}return o.get(e,"size")*o.get(c,"scale")}function a(e){return o.get(e,"dragPosition")}return window.addEventListener("resize",function(){r(n)}),setTimeout(function(){t()},10),{getSize:i,getContainerRectangles:function(){return{rect:c.rect,visibleRect:c.visibleRect,lastVisibleRect:c.lastVisibleRect}},getBeginEndOfDOMRect:function(e){return{begin:o.get(e,"begin"),end:o.get(e,"end")}},getBeginEndOfContainer:function(){return{begin:o.get(c.rect,"begin")+c.translation,end:o.get(c.rect,"end")+c.translation}},getBeginEndOfContainerVisibleRect:function(){return{begin:o.get(c.visibleRect,"begin")+c.translation,end:o.get(c.visibleRect,"end")+c.translation}},getBeginEnd:function(e){var t=function(e){return(o.get(e,"distanceToParent")+(e[p]||0))*o.get(c,"scale")}(e)+(o.get(c.rect,"begin")+c.translation)-o.get(n,"scrollValue");return{begin:t,end:t+i(e)*o.get(c,"scale")}},getAxisValue:a,setTranslation:function(e,t){t?o.set(e.style,"translate",t):e.style.removeProperty("transform"),e[p]=t},getTranslation:function(e){return e[p]},setVisibility:function(e,t){void 0!==e[u]&&e[u]===t||(t?e.style.removeProperty("visibility"):e.style.visibility="hidden",e[u]=t)},isVisible:function(e){return void 0===e[u]||e[u]},isInVisibleRect:function(e,t){var n=c.visibleRect,o=n.left,r=n.top,i=n.right,a=n.bottom;a-r<2&&(a=r+30);var l=c.rect;return"vertical"===s?e>l.left&&el.top&&t>>0,o=2<=arguments.length?arguments[1]:void 0,r=0;r .").concat(h),{display:"inline-block"}),m($,".".concat(g,".horizontal > .").concat(f),ne),m($,".".concat(g,".vertical > .").concat(f),te),m($,".".concat(f),{"box-sizing":"border-box"}),m($,".".concat(f,".horizontal"),ne),m($,".".concat(f,".vertical"),te),m($,".".concat(f,".animated"),{transition:"transform ease"}),m($,".".concat(v),{"box-sizing":"border-box"}),m($,".".concat(v,".animated"),{transition:"all ease-in-out"}),m($,".".concat(v," *"),{"pointer-events":"none"}),m($,".".concat(s," *"),{"touch-action":"none","-ms-touch-action":"none"}),m($,".".concat(c),{"-webkit-touch-callout":"none","-webkit-user-select":"none","-khtml-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none"}),m($,".".concat(w),{flex:"1"}),m($,".".concat(g,".horizontal > .").concat(x),{height:"100%",overflow:"hidden",display:"table-cell","vertical-align":"top"}),m($,".".concat(g,".vertical > .").concat(x),{overflow:"hidden",display:"block",width:"100%"}),m($,".".concat(E),{width:"100%",height:"100%",display:"flex","justify-content":"stretch","align-items":"stretch"}),m($,".".concat(b),{"background-color":"rgba(150, 150, 150, 0.1)",border:"1px solid #ccc"}),$);function re(o){return Object.keys(o).reduce(function(e,t){var n=o[t];return"object"===a(n)?"".concat(e).concat(t,"{").concat(re(n),"}"):"".concat(e).concat(t,":").concat(n,";")},"")}function ie(e){if(e&&"undefined"!=typeof window){var t=window.document.head||window.document.getElementsByTagName("head")[0],n=window.document.createElement("style"),o=re({"body *":{cursor:"".concat(e," !important")}});return n.type="text/css",n.styleSheet?n.styleSheet.cssText=o:n.appendChild(window.document.createTextNode(o)),t.appendChild(n),n}return null}var ae,le,se=["mousedown","touchstart"],ce=["mousemove","touchmove"],ue=["mouseup","touchend"],de=null,fe=null,ge=null,me=null,pe=[],ve=!1,he=!1,ye=!1,be=!1,we=null,xe=null,Ee=null,Ce=null,De=(ae=null,le=!1,{start:function(){le||(le=!0,function e(){ae=requestAnimationFrame(function(){de.forEach(function(e){return e.layout.invalidateRects()}),setTimeout(function(){null!==ae&&e()},50)})}())},stop:function(){null!==ae&&(cancelAnimationFrame(ae),ae=null),le=!1}}),Se="undefined"!=typeof window&&!!(window.navigator.userAgent.match(/Android/i)||window.navigator.userAgent.match(/webOS/i)||window.navigator.userAgent.match(/iPhone/i)||window.navigator.userAgent.match(/iPad/i)||window.navigator.userAgent.match(/iPod/i)||window.navigator.userAgent.match(/BlackBerry/i)||window.navigator.userAgent.match(/Windows Phone/i));function Oe(){"undefined"!=typeof window&&se.forEach(function(e){window.document.addEventListener(e,Ve,{passive:!1})})}function Re(){return me&&me.ghostParent?me.ghostParent:fe&&fe.parentElement||window.document.body}var Ae,Ie,Be,Pe,Te,ze,Ne=(Pe=null,Te=1,ze=5,function(e,t,n){Ae=Je(e),Be=n,(Ie="number"==typeof t?t:Se?200:0)&&(Pe=setTimeout(Fe,Ie)),ce.forEach(function(e){return window.document.addEventListener(e,Le)},{passive:!1}),ue.forEach(function(e){return window.document.addEventListener(e,Me)},{passive:!1}),window.document.addEventListener("drag",je,{passive:!1})});function Le(e){var t=Je(e),n=t.clientX,o=t.clientY;if(Ie)(Math.abs(Ae.clientX-n)>ze||Math.abs(Ae.clientY-o)>ze)&&_e();else if(Math.abs(Ae.clientX-n)>Te||Math.abs(Ae.clientY-o)>Te)return Fe()}function Me(){_e()}function je(){_e()}function _e(){clearTimeout(Pe),ce.forEach(function(e){return window.document.removeEventListener(e,Le)},{passive:!1}),ue.forEach(function(e){return window.document.removeEventListener(e,Me)},{passive:!1}),window.document.removeEventListener("drag",je,{passive:!1})}function Fe(){clearTimeout(Pe),_e(),Be()}function Ve(e){var t=Je(e);if(!ve&&(void 0===t.button||0===t.button)&&(fe=N(t.target,"."+f))){var n=N(fe,"."+g),o=pe.filter(function(e){return e.element===n})[0],r=o.getOptions().dragHandleSelector,i=o.getOptions().nonDragAreaSelector,a=!0;if(r&&!N(t.target,r)&&(a=!1),i&&N(t.target,i)&&(a=!1),a){o.layout.invalidate(),M(window.document.body,s),M(window.document.body,c);window.document.addEventListener("mouseup",function e(){j(window.document.body,s),j(window.document.body,c),window.document.removeEventListener("mouseup",e)})}a&&Ne(t,o.getOptions().dragBeginDelay,function(){V(),et(t,X(e.target)),ce.forEach(function(e){window.document.addEventListener(e,Xe,{passive:!1})}),ue.forEach(function(e){window.document.addEventListener(e,Ue,{passive:!1})})})}}function Xe(e){e.preventDefault();var t=Je(e);if(me){var n=me.container.getOptions();"contain"===n.behaviour?function(e){var t,n,o,r,i=e.clientX,a=e.clientY,l=1s.end-r/2&&(me.position[n]=s.end-2)}(t,n.orientation):Ee?"y"===Ee?(ge.topLeft.y=t.clientY+ge.positionDelta.top,me.position.y=t.clientY+ge.centerDelta.y,me.mousePosition.y=t.clientY):"x"===Ee&&(ge.topLeft.x=t.clientX+ge.positionDelta.left,me.position.x=t.clientX+ge.centerDelta.x,me.mousePosition.x=t.clientX):(ge.topLeft.x=t.clientX+ge.positionDelta.left,ge.topLeft.y=t.clientY+ge.positionDelta.top,me.position.x=t.clientX+ge.centerDelta.x,me.position.y=t.clientY+ge.centerDelta.y,me.mousePosition.x=t.clientX,me.mousePosition.y=t.clientY),nt(),(be=!we(me))&&We()}else et(t,X(e.target))}var He,Ye,ke,Ge,We=(He=qe,ke=!(Ye=20),Ge=null,function(){for(var e=arguments.length,t=new Array(e),n=0;n=o?null:on.end?a(i,o)+1:i.length;var r=a(i,o,!0);return null!==r?r:i.length}}(e);return function(e){var t=e.dragResult,n=null;return null!==t.pos&&null===(n=o({dragResult:t}))&&(n=t.addedIndex),{addedIndex:n}}}function bt(){var r=null;return function(e){var t=e.dragResult,n=t.addedIndex,o=t.shadowBeginEnd;n!==r&&null!==r&&o&&(o.beginAdjustment=0),r=n}}function wt(e){var u=e.element,d=e.draggables,f=e.layout,g=e.getOptions,m=null;return function(e){var t=e.dragResult,n=t.addedIndex,o=t.removedIndex,r=t.elementSize;if(null===o)if(null!==n){if(!m){var i=f.getBeginEndOfContainer();i.end=i.begin+f.getSize(u);var a=f.getScrollSize(u)>f.getSize(u)?i.begin+f.getScrollSize(u)-f.getScrollValue(u):i.end,l=0 { + return []; + } + }, + + value: { + type: Array, + default: () => { + return []; + } + }, + + idField: { + type: String, + default: 'key', + }, + + textField: { + type: String, + default: 'value', + }, + + displayField: { + type: String, + default: null, + }, + + valueFields: { + type: String, + default: null, + }, + + disabled: { + type: Boolean, + default: false + }, + + typeahead: { + type: Boolean, + default: false + }, + + typeaheadStyle: { + type: String, + default: 'badges' + }, + + typeaheadActivationThreshold: { + type: Number, + default: 1 + }, + + typeaheadMaxResults: { + type: Number, + default: 0 + }, + + typeaheadAlwaysShow: { + type: Boolean, + default: false + }, + + typeaheadShowOnFocus: { + type: Boolean, + default: true + }, + + typeaheadHideDiscard: { + type: Boolean, + default: false + }, + + typeaheadUrl: { + type: String, + default: '' + }, + + typeaheadCallback: { + type: Function, + default: null + }, + + placeholder: { + type: String, + default: 'Add a tag' + }, + + discardSearchText: { + type: String, + default: 'Discard Search Results' + }, + + limit: { + type: Number, + default: 0 + }, + + hideInputOnLimit: { + type: Boolean, + default: false + }, + + onlyExistingTags: { + type: Boolean, + default: false + }, + + deleteOnBackspace: { + type: Boolean, + default: true + }, + + allowDuplicates: { + type: Boolean, + default: false + }, + + validate: { + type: Function, + default: () => true + }, + + addTagsOnComma: { + type: Boolean, + default: false + }, + + addTagsOnSpace: { + type: Boolean, + default: false + }, + + addTagsOnBlur: { + type: Boolean, + default: false + }, + + wrapperClass: { + type: String, + default: 'tags-input-wrapper-default' + }, + + sortSearchResults: { + type: Boolean, + default: true + }, + + caseSensitiveTags: { + type: Boolean, + default: false + }, + + beforeAddingTag: { + type: Function, + default: () => true + }, + + beforeRemovingTag: { + type: Function, + default: () => true + }, + }, + + data() { + return { + badgeId: 0, + tags: [], + + input: '', + oldInput: '', + hiddenInput: '', + + searchResults: [], + searchSelection: 0, + + selectedTag: -1, + + isActive: false, + composing: false, + }; + }, + + created () { + this.typeaheadTags = this.cloneArray(this.existingTags); + + this.tagsFromValue(); + + if (this.typeaheadAlwaysShow) { + this.searchTag(false); + } + }, + + mounted () { + // Emit an event + this.$emit('initialized'); + + document.addEventListener('click', (e) => { + if (e.target !== this.$refs['taginput']) { + this.clearSearchResults(); + } + }); + }, + + computed: { + hideInputField() { + return (this.hideInputOnLimit && this.limit > 0 && this.tags.length >= this.limit) || this.disabled; + } + }, + + watch: { + input(newVal, oldVal) { + this.searchTag(false); + + if (newVal.length && newVal != oldVal) { + const diff = newVal.substring(oldVal.length, newVal.length); + + if (this.addTagsOnSpace) { + if (newVal.endsWith(' ')) { + // The space shouldn't actually be inserted + this.input = newVal.trim(); + + // Add the inputed tag + this.tagFromInput(true); + } + } + + if (this.addTagsOnComma) { + newVal = newVal.trim(); + + if (newVal.endsWith(',')) { + // The comma shouldn't actually be inserted + this.input = newVal.substring(0, newVal.length - 1); + + // Add the inputed tag + this.tagFromInput(true); + } + } + + this.$emit('change', newVal); + } + }, + + existingTags(newVal) { + this.typeaheadTags.splice(0); + + this.typeaheadTags = this.cloneArray(newVal); + + this.searchTag(); + }, + + tags() { + // Updating the hidden input + this.hiddenInput = JSON.stringify(this.tags); + + // Update the bound v-model value + this.$emit('input', this.tags); + }, + + value() { + this.tagsFromValue(); + }, + + typeaheadAlwaysShow(newValue) { + if (newValue) { + this.searchTag(false); + } else { + this.clearSearchResults(); + } + }, + }, + + methods: { + /** + * Remove reserved regex characters from a string so that they don't + * affect search results + * + * @param string + * @returns String + */ + escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + }, + + /** + * Add a tag whether from user input or from search results (typeahead) + * + * @param ignoreSearchResults + * @returns void + */ + tagFromInput(ignoreSearchResults = false) { + if (this.composing) return; + + // If we're choosing a tag from the search results + if (this.searchResults.length && this.searchSelection >= 0 && !ignoreSearchResults) { + this.tagFromSearch(this.searchResults[this.searchSelection]); + + this.input = ''; + } else { + // If we're adding an unexisting tag + let text = this.input.trim(); + + // If the new tag is not an empty string and passes validation + if (!this.onlyExistingTags && text.length && this.validate(text)) { + this.input = ''; + + // Determine if the inputted tag exists in the typeagedTags + // array + let newTag = { + [this.idField]: '', + [this.textField]: text + }; + + const searchQuery = this.escapeRegExp( + this.caseSensitiveTags + ? newTag[this.textField] + : newTag[this.textField].toLowerCase() + ); + + for (let tag of this.typeaheadTags) { + const compareable = this.escapeRegExp( + this.caseSensitiveTags + ? tag[this.textField] + : tag[this.textField].toLowerCase() + ); + + if (searchQuery === compareable) { + newTag = Object.assign({}, tag); + + break; + } + } + + this.addTag(newTag); + } + } + }, + + /** + * Add a tag from search results when a user clicks on it + * + * @param tag + * @returns void + */ + tagFromSearchOnClick(tag) { + this.tagFromSearch(tag); + + this.$refs['taginput'].blur(); + }, + + /** + * Add the selected tag from the search results. + * Clear search results. + * Clear user input. + * + * @param tag + * @return void + */ + tagFromSearch(tag) { + this.clearSearchResults(); + this.addTag(tag); + + this.$nextTick(() => { + this.input = ''; + this.oldInput = ''; + }); + }, + + /** + * Add/Select a tag + * + * @param tag + * @param force + * @returns void | Boolean + */ + addTag(tag, force = false) { + if (this.disabled && !force) { + return; + } + + if (!this.beforeAddingTag(tag)) { + return false; + } + + // Check if the limit has been reached + if (this.limit > 0 && this.tags.length >= this.limit) { + this.$emit('limit-reached'); + + return false; + } + + // Attach the tag if it hasn't been attached yet + if (!this.tagSelected(tag)) { + this.tags.push(tag); + + // Emit events + this.$nextTick(() => { + this.$emit('tag-added', tag); + this.$emit('tags-updated'); + }); + } + }, + + /** + * Remove the last tag in the tags array. + * + * @returns void + */ + removeLastTag() { + if (!this.input.length && this.deleteOnBackspace && this.tags.length) { + this.removeTag(this.tags.length - 1); + } + }, + + /** + * Remove the selected tag at the specified index. + * + * @param index + * @returns void + */ + removeTag(index) { + if (this.disabled) { + return; + } + + let tag = this.tags[index]; + + if (!this.beforeRemovingTag(tag)) { + return false; + } + + this.tags.splice(index, 1); + + // Emit events + this.$nextTick(() => { + this.$emit('tag-removed', tag); + this.$emit('tags-updated'); + + if (this.typeaheadAlwaysShow) { + this.searchTag(); + } + }); + }, + + /** + * Search the currently entered text in the list of existing tags + * + * @returns void | Boolean + */ + searchTag() { + if (this.typeahead !== true) { + return false; + } + + if (this.oldInput != this.input || (!this.searchResults.length && this.typeaheadActivationThreshold == 0) || this.typeaheadAlwaysShow || this.typeaheadShowOnFocus) { + if (!this.typeaheadUrl.length && !this.typeaheadCallback) { + this.searchResults = []; + } + + this.searchSelection = 0; + let input = this.input.trim(); + + if ((input.length && input.length >= this.typeaheadActivationThreshold) || this.typeaheadActivationThreshold == 0 || this.typeaheadAlwaysShow) { + // Find all the existing tags which include the search text + const searchQuery = this.escapeRegExp( + this.caseSensitiveTags ? input : input.toLowerCase() + ); + + // AJAX search + if (this.typeaheadCallback) { + this.typeaheadCallback(searchQuery) + .then((results) => { + this.typeaheadTags = results; + }); + } else if (this.typeaheadUrl.length > 0) { + this.typeaheadTags.splice(0); + const xhttp = new XMLHttpRequest(); + const that = this; + + xhttp.onreadystatechange = function () { + if (this.readyState == 4 && this.status == 200) { + that.typeaheadTags = JSON.parse(xhttp.responseText); + + that.doSearch(searchQuery); + } + } + + const endpoint = this.typeaheadUrl.replace(':search', searchQuery); + xhttp.open('GET', endpoint, true); + xhttp.send(); + } else { + // Search the existing collection + this.doSearch(searchQuery); + } + } + + this.oldInput = this.input; + } + }, + + /** + * Perform the actual search + * + * @param string searchQuery + * @return void + */ + doSearch(searchQuery) { + this.searchResults = []; + + for (let tag of this.typeaheadTags) { + const compareable = this.caseSensitiveTags + ? tag[this.textField] + : tag[this.textField].toLowerCase(); + const ids = this.searchResults.map((res) => (res[this.idField])); + + if (compareable.search(searchQuery) > -1 && ! this.tagSelected(tag) && ! ids.includes(tag[this.idField])) { + this.searchResults.push(tag); + } + } + + // Sort the search results alphabetically + if (this.sortSearchResults) { + this.searchResults.sort((a, b) => { + if (a[this.textField] < b[this.textField]) return -1; + if (a[this.textField] > b[this.textField]) return 1; + + return 0; + }); + } + + // Shorten Search results to desired length + if (this.typeaheadMaxResults > 0) { + this.searchResults = this.searchResults.slice( + 0, + this.typeaheadMaxResults + ); + } + }, + + /** + * Hide the typeahead if there's nothing intered into the input field. + * + * @returns void + */ + hideTypeahead() { + if (! this.input.length) { + this.$nextTick(() => { + this.clearSearchResults(); + }); + } + }, + + /** + * Select the next search result in typeahead. + * + * @returns void + */ + nextSearchResult() { + if (this.searchSelection + 1 <= this.searchResults.length - 1) { + this.searchSelection++; + } + }, + + /** + * Select the previous search result in typeahead. + * + * @returns void + */ + prevSearchResult() { + if (this.searchSelection > 0) { + this.searchSelection--; + } + }, + + /** + * Clear/Empty the search results. + * + * @reutrns void + */ + clearSearchResults(returnFocus = false) { + this.searchResults = []; + this.searchSelection = 0; + + if (this.typeaheadAlwaysShow) { + this.$nextTick(() => { + this.searchTag(); + }); + } + + if (returnFocus) { + this.$refs['taginput'].focus(); + } + }, + + /** + * Clear the list of selected tags. + * + * @returns void + */ + clearTags() { + this.tags.splice(0, this.tags.length); + }, + + /** + * Replace the currently selected tags with the tags from the value. + * + * @returns void + */ + tagsFromValue() { + if (this.value && this.value.length) { + if (!Array.isArray(this.value)) { + console.error('Voerro Tags Input: the v-model value must be an array!'); + + return; + } + + let tags = this.value; + + // Don't update if nothing has changed + if (this.tags == tags) { + return; + } + + this.clearTags(); + + for (let tag of tags) { + this.addTag(tag, true); + } + } else { + if (this.tags.length == 0) { + return; + } + + this.clearTags(); + } + }, + + /** + * Check if a tag is already selected. + * + * @param tag + * @returns Boolean + */ + tagSelected(tag) { + if (this.allowDuplicates) { + return false; + } + + if (! tag) { + return false; + } + + const searchQuery = this.escapeRegExp( + this.caseSensitiveTags ? tag[this.textField] : tag[this.textField].toLowerCase() + ); + + for (let selectedTag of this.tags) { + const compareable = this.caseSensitiveTags + ? selectedTag[this.textField] + : selectedTag[this.textField].toLowerCase(); + + if (selectedTag[this.idField] === tag[this.idField] && this.escapeRegExp(compareable).length == searchQuery.length && compareable.search(searchQuery) > -1) { + return true; + } + } + + return false; + }, + + /** + * Clear the input. + * + * @returns void + */ + clearInput() { + this.input = ''; + }, + + /** + * Process all the keyup events. + * + * @param e + * @returns void + */ + onKeyUp(e) { + this.$emit('keyup', e); + }, + + /** + * Process all the keydown events. + * + * @param e + * @returns void + */ + onKeyDown(e) { + this.$emit('keydown', e); + }, + + /** + * Process the onfocus event. + * + * @param e + * @returns void + */ + onFocus(e) { + this.$emit('focus', e); + + this.isActive = true; + }, + + /** + * Process the onClick event. + * + * @param e + * @returns void + */ + onClick(e) { + this.$emit('click', e); + + this.isActive = true; + + this.searchTag(); + }, + + /** + * Process the onblur event. + * + * @param e + * @returns void + */ + onBlur(e) { + this.$emit('blur', e) + + if (this.addTagsOnBlur) { + // Add the inputed tag + this.tagFromInput(true); + } + + if (!this.typeaheadAlwaysShow) { + this.hideTypeahead(); + } else { + this.searchTag(); + } + + this.isActive = false; + }, + + hiddenInputValue(tag) { + // Return all fields + if (!this.valueFields) { + return JSON.stringify(tag); + } + + const fields = this.valueFields.replace(/\s/, '').split(','); + + // A single field + if (fields.length === 1) { + return tag[fields[0]]; + } else { + // Specified fields + return JSON.stringify( + Object.assign( + {}, + ...fields.map(field => ({ [field]: tag[field] })) + ) + ); + } + + return JSON.stringify(tag); + }, + + getDisplayField(tag) { + const hasDisplayField = this.displayField !== undefined + && this.displayField !== null + && tag[this.displayField] !== undefined + && tag[this.displayField] !== null + && tag[this.displayField] !== ''; + + return hasDisplayField + ? tag[this.displayField] + : tag[this.textField]; + }, + + cloneArray(arr) { + return arr.map(el => Object.assign({}, el)); + } + } +}); + + +/***/ }), + +/***/ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./node_modules/@voerro/vue-tagsinput/src/VoerroTagsInput.vue?vue&type=template&id=d29272ca&": +/*!*********************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options!./node_modules/@voerro/vue-tagsinput/src/VoerroTagsInput.vue?vue&type=template&id=d29272ca& ***! + \*********************************************************************************************************************************************************************************************************************************/ +/*! exports provided: render, staticRenderFns */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "render", function() { return render; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "staticRenderFns", function() { return staticRenderFns; }); +var render = function() { + var _obj + var _vm = this + var _h = _vm.$createElement + var _c = _vm._self._c || _h + return _c( + "div", + { staticClass: "tags-input-root", staticStyle: { position: "relative" } }, + [ + _c( + "div", + { + class: + ((_obj = {}), + (_obj[_vm.wrapperClass + " tags-input"] = true), + (_obj["active"] = _vm.isActive), + (_obj["disabled"] = _vm.disabled), + _obj) + }, + [ + _vm._l(_vm.tags, function(tag, index) { + return _c( + "span", + { + key: index, + staticClass: + "tags-input-badge tags-input-badge-pill tags-input-badge-selected-default", + class: { disabled: _vm.disabled } + }, + [ + _vm._t( + "selected-tag", + [ + _c("span", { + domProps: { innerHTML: _vm._s(tag[_vm.textField]) } + }), + _vm._v(" "), + _c("a", { + directives: [ + { + name: "show", + rawName: "v-show", + value: !_vm.disabled, + expression: "!disabled" + } + ], + staticClass: "tags-input-remove", + attrs: { href: "#" }, + on: { + click: function($event) { + $event.preventDefault() + return _vm.removeTag(index) + } + } + }) + ], + { tag: tag, index: index, removeTag: _vm.removeTag } + ) + ], + 2 + ) + }), + _vm._v(" "), + _c("input", { + directives: [ + { + name: "show", + rawName: "v-show", + value: !_vm.hideInputField, + expression: "!hideInputField" + } + ], + ref: "taginput", + attrs: { + type: "text", + id: _vm.inputId, + name: _vm.inputId, + placeholder: _vm.placeholder + }, + domProps: { value: _vm.input }, + on: { + input: function(e) { + return (_vm.input = e.target.value) + }, + compositionstart: function($event) { + _vm.composing = true + }, + compositionend: function($event) { + _vm.composing = false + }, + keydown: [ + function($event) { + if ( + !$event.type.indexOf("key") && + _vm._k($event.keyCode, "enter", 13, $event.key, "Enter") + ) { + return null + } + $event.preventDefault() + return _vm.tagFromInput(false) + }, + function($event) { + if (!$event.type.indexOf("key") && $event.keyCode !== 8) { + return null + } + return _vm.removeLastTag($event) + }, + function($event) { + if ( + !$event.type.indexOf("key") && + _vm._k($event.keyCode, "down", 40, $event.key, [ + "Down", + "ArrowDown" + ]) + ) { + return null + } + return _vm.nextSearchResult($event) + }, + function($event) { + if ( + !$event.type.indexOf("key") && + _vm._k($event.keyCode, "up", 38, $event.key, [ + "Up", + "ArrowUp" + ]) + ) { + return null + } + return _vm.prevSearchResult($event) + }, + _vm.onKeyDown + ], + keyup: [ + _vm.onKeyUp, + function($event) { + if ( + !$event.type.indexOf("key") && + _vm._k($event.keyCode, "esc", 27, $event.key, [ + "Esc", + "Escape" + ]) + ) { + return null + } + return _vm.clearSearchResults($event) + } + ], + focus: _vm.onFocus, + click: _vm.onClick, + blur: _vm.onBlur, + value: _vm.tags + } + }), + _vm._v(" "), + _vm.elementId + ? _c( + "div", + { staticStyle: { display: "none" } }, + _vm._l(_vm.tags, function(tag, index) { + return _c("input", { + key: index, + attrs: { type: "hidden", name: _vm.elementId + "[]" }, + domProps: { value: _vm.hiddenInputValue(tag) } + }) + }), + 0 + ) + : _vm._e() + ], + 2 + ), + _vm._v(" "), + _c( + "div", + { + directives: [ + { + name: "show", + rawName: "v-show", + value: _vm.searchResults.length, + expression: "searchResults.length" + } + ] + }, + [ + _vm.typeaheadStyle === "badges" + ? _c( + "p", + { class: "typeahead-" + _vm.typeaheadStyle }, + [ + !_vm.typeaheadHideDiscard + ? _c("span", { + staticClass: + "tags-input-badge typeahead-hide-btn tags-input-typeahead-item-default", + domProps: { + textContent: _vm._s(_vm.discardSearchText) + }, + on: { + click: function($event) { + $event.preventDefault() + return _vm.clearSearchResults(true) + } + } + }) + : _vm._e(), + _vm._v(" "), + _vm._l(_vm.searchResults, function(tag, index) { + return _c("span", { + key: index, + staticClass: "tags-input-badge", + class: { + "tags-input-typeahead-item-default": + index != _vm.searchSelection, + "tags-input-typeahead-item-highlighted-default": + index == _vm.searchSelection + }, + domProps: { innerHTML: _vm._s(tag[_vm.textField]) }, + on: { + mouseover: function($event) { + _vm.searchSelection = index + }, + mousedown: function($event) { + $event.preventDefault() + return _vm.tagFromSearchOnClick(tag) + } + } + }) + }) + ], + 2 + ) + : _vm.typeaheadStyle === "dropdown" + ? _c( + "ul", + { class: "typeahead-" + _vm.typeaheadStyle }, + [ + !_vm.typeaheadHideDiscard + ? _c("li", { + staticClass: + "tags-input-typeahead-item-default typeahead-hide-btn", + domProps: { + textContent: _vm._s(_vm.discardSearchText) + }, + on: { + click: function($event) { + $event.preventDefault() + return _vm.clearSearchResults(true) + } + } + }) + : _vm._e(), + _vm._v(" "), + _vm._l(_vm.searchResults, function(tag, index) { + return _c("li", { + key: index, + class: { + "tags-input-typeahead-item-default": + index != _vm.searchSelection, + "tags-input-typeahead-item-highlighted-default": + index == _vm.searchSelection + }, + domProps: { innerHTML: _vm._s(_vm.getDisplayField(tag)) }, + on: { + mouseover: function($event) { + _vm.searchSelection = index + }, + mousedown: function($event) { + $event.preventDefault() + return _vm.tagFromSearchOnClick(tag) + } + } + }) + }) + ], + 2 + ) + : _vm._e() + ] + ) + ] + ) +} +var staticRenderFns = [] +render._withStripped = true + + + +/***/ }), + +/***/ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/AutoCompleteTags.vue?vue&type=template&id=ce297ba8&scoped=true&": +/*!*******************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options!./resources/js/components/AutoCompleteTags.vue?vue&type=template&id=ce297ba8&scoped=true& ***! + \*******************************************************************************************************************************************************************************************************************************/ +/*! exports provided: render, staticRenderFns */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "render", function() { return render; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "staticRenderFns", function() { return staticRenderFns; }); +var render = function() { + var _vm = this + var _h = _vm.$createElement + var _c = _vm._self._c || _h + return _c("tags-input", { + attrs: { + "element-id": "tags", + "existing-tags": _vm.existingtags, + "id-field": "id", + "text-field": "label", + placeholder: "Ajouter un tag", + typeahead: true, + "typeahead-style": "dropdown" + }, + model: { + value: _vm.selectedTags, + callback: function($$v) { + _vm.selectedTags = $$v + }, + expression: "selectedTags" + } + }) +} +var staticRenderFns = [] +render._withStripped = true + + + /***/ }), /***/ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/Faq.vue?vue&type=template&id=5546b00a&scoped=true&": @@ -51469,9 +52906,12 @@ module.exports = function(module) { /*!*****************************!*\ !*** ./resources/js/app.js ***! \*****************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { +/*! no exports provided */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _voerro_vue_tagsinput__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @voerro/vue-tagsinput */ "./node_modules/@voerro/vue-tagsinput/src/main.js"); __webpack_require__(/*! ./bootstrap */ "./resources/js/bootstrap.js"); window.Vue = __webpack_require__(/*! vue */ "./node_modules/vue/dist/vue.common.js"); // Vuex @@ -51479,8 +52919,11 @@ window.Vue = __webpack_require__(/*! vue */ "./node_modules/vue/dist/vue.common. // import { Container, Draggable } from 'vue-smooth-dnd'; // import { applyDrag, generateItems } from './helpers'; + Vue.component('faq', __webpack_require__(/*! ./components/Faq.vue */ "./resources/js/components/Faq.vue")["default"]); Vue.component('products-cards-dnd', __webpack_require__(/*! ./components/ProductsCardsDnd.vue */ "./resources/js/components/ProductsCardsDnd.vue")["default"]); +Vue.component('tags-input', _voerro_vue_tagsinput__WEBPACK_IMPORTED_MODULE_0__["default"]); +Vue.component('auto-complete-tags', __webpack_require__(/*! ./components/AutoCompleteTags.vue */ "./resources/js/components/AutoCompleteTags.vue")["default"]); var app = new Vue({ el: '#app' }); @@ -51521,6 +52964,93 @@ window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; // forceTLS: true // }); +/***/ }), + +/***/ "./resources/js/components/AutoCompleteTags.vue": +/*!******************************************************!*\ + !*** ./resources/js/components/AutoCompleteTags.vue ***! + \******************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _AutoCompleteTags_vue_vue_type_template_id_ce297ba8_scoped_true___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./AutoCompleteTags.vue?vue&type=template&id=ce297ba8&scoped=true& */ "./resources/js/components/AutoCompleteTags.vue?vue&type=template&id=ce297ba8&scoped=true&"); +/* harmony import */ var _AutoCompleteTags_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./AutoCompleteTags.vue?vue&type=script&lang=js& */ "./resources/js/components/AutoCompleteTags.vue?vue&type=script&lang=js&"); +/* empty/unused harmony star reexport *//* harmony import */ var _AutoCompleteTags_vue_vue_type_style_index_0_id_ce297ba8_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./AutoCompleteTags.vue?vue&type=style&index=0&id=ce297ba8&scoped=true&lang=css& */ "./resources/js/components/AutoCompleteTags.vue?vue&type=style&index=0&id=ce297ba8&scoped=true&lang=css&"); +/* harmony import */ var _node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js */ "./node_modules/vue-loader/lib/runtime/componentNormalizer.js"); + + + + + + +/* normalize component */ + +var component = Object(_node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_3__["default"])( + _AutoCompleteTags_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__["default"], + _AutoCompleteTags_vue_vue_type_template_id_ce297ba8_scoped_true___WEBPACK_IMPORTED_MODULE_0__["render"], + _AutoCompleteTags_vue_vue_type_template_id_ce297ba8_scoped_true___WEBPACK_IMPORTED_MODULE_0__["staticRenderFns"], + false, + null, + "ce297ba8", + null + +) + +/* hot reload */ +if (false) { var api; } +component.options.__file = "resources/js/components/AutoCompleteTags.vue" +/* harmony default export */ __webpack_exports__["default"] = (component.exports); + +/***/ }), + +/***/ "./resources/js/components/AutoCompleteTags.vue?vue&type=script&lang=js&": +/*!*******************************************************************************!*\ + !*** ./resources/js/components/AutoCompleteTags.vue?vue&type=script&lang=js& ***! + \*******************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _node_modules_babel_loader_lib_index_js_ref_4_0_node_modules_vue_loader_lib_index_js_vue_loader_options_AutoCompleteTags_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/babel-loader/lib??ref--4-0!../../../node_modules/vue-loader/lib??vue-loader-options!./AutoCompleteTags.vue?vue&type=script&lang=js& */ "./node_modules/babel-loader/lib/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/AutoCompleteTags.vue?vue&type=script&lang=js&"); +/* empty/unused harmony star reexport */ /* harmony default export */ __webpack_exports__["default"] = (_node_modules_babel_loader_lib_index_js_ref_4_0_node_modules_vue_loader_lib_index_js_vue_loader_options_AutoCompleteTags_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__["default"]); + +/***/ }), + +/***/ "./resources/js/components/AutoCompleteTags.vue?vue&type=style&index=0&id=ce297ba8&scoped=true&lang=css&": +/*!***************************************************************************************************************!*\ + !*** ./resources/js/components/AutoCompleteTags.vue?vue&type=style&index=0&id=ce297ba8&scoped=true&lang=css& ***! + \***************************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _node_modules_style_loader_index_js_node_modules_css_loader_index_js_ref_7_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_7_2_node_modules_vue_loader_lib_index_js_vue_loader_options_AutoCompleteTags_vue_vue_type_style_index_0_id_ce297ba8_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/style-loader!../../../node_modules/css-loader??ref--7-1!../../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../../node_modules/postcss-loader/src??ref--7-2!../../../node_modules/vue-loader/lib??vue-loader-options!./AutoCompleteTags.vue?vue&type=style&index=0&id=ce297ba8&scoped=true&lang=css& */ "./node_modules/style-loader/index.js!./node_modules/css-loader/index.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/AutoCompleteTags.vue?vue&type=style&index=0&id=ce297ba8&scoped=true&lang=css&"); +/* harmony import */ var _node_modules_style_loader_index_js_node_modules_css_loader_index_js_ref_7_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_7_2_node_modules_vue_loader_lib_index_js_vue_loader_options_AutoCompleteTags_vue_vue_type_style_index_0_id_ce297ba8_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_index_js_node_modules_css_loader_index_js_ref_7_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_7_2_node_modules_vue_loader_lib_index_js_vue_loader_options_AutoCompleteTags_vue_vue_type_style_index_0_id_ce297ba8_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0__); +/* harmony reexport (unknown) */ for(var __WEBPACK_IMPORT_KEY__ in _node_modules_style_loader_index_js_node_modules_css_loader_index_js_ref_7_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_7_2_node_modules_vue_loader_lib_index_js_vue_loader_options_AutoCompleteTags_vue_vue_type_style_index_0_id_ce297ba8_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0__) if(["default"].indexOf(__WEBPACK_IMPORT_KEY__) < 0) (function(key) { __webpack_require__.d(__webpack_exports__, key, function() { return _node_modules_style_loader_index_js_node_modules_css_loader_index_js_ref_7_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_7_2_node_modules_vue_loader_lib_index_js_vue_loader_options_AutoCompleteTags_vue_vue_type_style_index_0_id_ce297ba8_scoped_true_lang_css___WEBPACK_IMPORTED_MODULE_0__[key]; }) }(__WEBPACK_IMPORT_KEY__)); + + +/***/ }), + +/***/ "./resources/js/components/AutoCompleteTags.vue?vue&type=template&id=ce297ba8&scoped=true&": +/*!*************************************************************************************************!*\ + !*** ./resources/js/components/AutoCompleteTags.vue?vue&type=template&id=ce297ba8&scoped=true& ***! + \*************************************************************************************************/ +/*! exports provided: render, staticRenderFns */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_AutoCompleteTags_vue_vue_type_template_id_ce297ba8_scoped_true___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!../../../node_modules/vue-loader/lib??vue-loader-options!./AutoCompleteTags.vue?vue&type=template&id=ce297ba8&scoped=true& */ "./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./resources/js/components/AutoCompleteTags.vue?vue&type=template&id=ce297ba8&scoped=true&"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "render", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_AutoCompleteTags_vue_vue_type_template_id_ce297ba8_scoped_true___WEBPACK_IMPORTED_MODULE_0__["render"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "staticRenderFns", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_AutoCompleteTags_vue_vue_type_template_id_ce297ba8_scoped_true___WEBPACK_IMPORTED_MODULE_0__["staticRenderFns"]; }); + + + /***/ }), /***/ "./resources/js/components/Faq.vue": diff --git a/resources/js/app.js b/resources/js/app.js index d201a82..422b3b2 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -5,9 +5,12 @@ window.Vue = require('vue'); // import Vuex from 'vuex'; // import { Container, Draggable } from 'vue-smooth-dnd'; // import { applyDrag, generateItems } from './helpers'; +import VoerroTagsInput from '@voerro/vue-tagsinput'; Vue.component('faq', require('./components/Faq.vue').default); Vue.component('products-cards-dnd', require('./components/ProductsCardsDnd.vue').default); +Vue.component('tags-input', VoerroTagsInput); +Vue.component('auto-complete-tags', require('./components/AutoCompleteTags.vue').default); const app = new Vue({ el: '#app', diff --git a/resources/js/components/AutocompleteTags.vue b/resources/js/components/AutocompleteTags.vue new file mode 100644 index 0000000..1cc531e --- /dev/null +++ b/resources/js/components/AutocompleteTags.vue @@ -0,0 +1,43 @@ + + + + + + diff --git a/resources/views/bo/products/edit.blade.php b/resources/views/bo/products/edit.blade.php index e5bdfcb..3a567e5 100644 --- a/resources/views/bo/products/edit.blade.php +++ b/resources/views/bo/products/edit.blade.php @@ -26,6 +26,10 @@ +
+ + +
diff --git a/resources/views/front/canard/search.blade.php b/resources/views/front/canard/search.blade.php index 95c99b0..9983536 100644 --- a/resources/views/front/canard/search.blade.php +++ b/resources/views/front/canard/search.blade.php @@ -3,7 +3,21 @@ @section('title', __('Tous les produits')) @section('content') - +
+
+
+
+ +
+
+ +
+
+
+ +
+
+
@include('partials.products-list') @include('partials.ranges-slider') diff --git a/resources/views/layouts/bo-layout.blade.php b/resources/views/layouts/bo-layout.blade.php index 8e6874b..99b1e77 100644 --- a/resources/views/layouts/bo-layout.blade.php +++ b/resources/views/layouts/bo-layout.blade.php @@ -39,7 +39,7 @@ - -
- {{--
+ --}} +
+
+
+

+ +

+
+ + +
+

-
+
-
-
--}} +

@@ -90,7 +112,7 @@

-
+