Browse Source

drafted materio_sapi search block vue integration

Bachir Soussi Chiadmi 4 years ago
parent
commit
a48b7262eb
29 changed files with 586 additions and 122 deletions
  1. 1 0
      build/webpack.config.base.js
  2. 1 0
      composer.json
  3. 159 67
      composer.lock
  4. 2 2
      config/sync/autologout.settings.yml
  5. 3 0
      config/sync/core.extension.yml
  6. 7 8
      config/sync/rest.resource.entity.block.yml
  7. 1 1
      config/sync/rest.resource.entity.configurable_language.yml
  8. 1 1
      config/sync/rest.resource.entity.node.yml
  9. 17 0
      config/sync/rest.resource.entity.user_role.yml
  10. 1 0
      config/sync/user.role.adherent.yml
  11. 1 0
      config/sync/user.role.admin.yml
  12. 1 0
      config/sync/user.role.admin_showroom.yml
  13. 1 0
      config/sync/user.role.alpha_testeur.yml
  14. 1 0
      config/sync/user.role.student.yml
  15. 8 0
      web/modules/custom/materio_sapi/materio_sapi.routing.yml
  16. 84 0
      web/modules/custom/materio_sapi/src/Controller/AjaxSearchForm.php
  17. 0 5
      web/modules/custom/materio_sapi/src/Controller/FormAutocomplete.php
  18. 7 0
      web/modules/custom/materio_sapi/src/Form/MaterioSapiSearchForm.php
  19. 8 0
      web/themes/custom/materiotheme/assets/dist/main.js
  20. 45 14
      web/themes/custom/materiotheme/assets/scripts/main.js
  21. 8 0
      web/themes/custom/materiotheme/assets/styles/main.scss
  22. 44 0
      web/themes/custom/materiotheme/templates/block/block--materiosapisearchblock.html.twig
  23. 3 5
      web/themes/custom/materiotheme/templates/layout/page.html.twig
  24. 13 0
      web/themes/custom/materiotheme/vuejs/api/msapi-axios.js
  25. 65 0
      web/themes/custom/materiotheme/vuejs/components/Block/SearchBlock.vue
  26. 0 0
      web/themes/custom/materiotheme/vuejs/components/Block/UserBlock.vue
  27. 88 0
      web/themes/custom/materiotheme/vuejs/components/Form/SearchForm.vue
  28. 1 0
      web/themes/custom/materiotheme/vuejs/components/User/UserTools.vue
  29. 15 19
      web/themes/custom/materiotheme/vuejs/store/modules/user.js

+ 1 - 0
build/webpack.config.base.js

@@ -11,6 +11,7 @@ module.exports = {
   resolve: {
     extensions: ['.js', '.vue', '.json'],
     alias: {
+      'vue': 'vue/dist/vue.js',
       'theme': utils.resolve(themePath),
       'vuejs': utils.resolve(themePath+'/vuejs')
     }

+ 1 - 0
composer.json

@@ -37,6 +37,7 @@
         "drupal/error_log": "^1.0",
         "drupal/genpass": "1.x-dev",
         "drupal/image_delta_formatter": "1.x-dev",
+        "drupal/jsonrpc": "1.x-dev",
         "drupal/login_history": "1.x-dev",
         "drupal/mailgun": "1.x-dev",
         "drupal/mailsystem": "^4.1",

+ 159 - 67
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "8a8cacad3f133bac4dc306fda59b40d7",
+    "content-hash": "94914ee080097da2be34ee7047311647",
     "packages": [
         {
             "name": "alchemy/zippy",
@@ -6949,6 +6949,55 @@
                 "source": "https://git.drupalcode.org/project/interval"
             }
         },
+        {
+            "name": "drupal/jsonrpc",
+            "version": "dev-1.x",
+            "source": {
+                "type": "git",
+                "url": "https://git.drupalcode.org/project/jsonrpc.git",
+                "reference": "50ca339a2d241df19806a17418bab38fa5c12278"
+            },
+            "require": {
+                "drupal/core": "~8.0",
+                "e0ipso/shaper": "^1.2.1"
+            },
+            "type": "drupal-module",
+            "extra": {
+                "branch-alias": {
+                    "dev-1.x": "1.x-dev"
+                },
+                "drupal": {
+                    "version": "8.x-1.0-beta6+0-dev",
+                    "datestamp": "1552196884",
+                    "security-coverage": {
+                        "status": "not-covered",
+                        "message": "Dev releases are not covered by Drupal security advisories."
+                    }
+                }
+            },
+            "notification-url": "https://packages.drupal.org/8/downloads",
+            "license": [
+                "GPL-2.0+"
+            ],
+            "authors": [
+                {
+                    "name": "Mateu Aguiló Bosch",
+                    "homepage": "https://www.drupal.org/user/550110",
+                    "email": "mateu.aguilo.bosch@gmail.com"
+                },
+                {
+                    "name": "Gabriel Sullice",
+                    "homepage": "https://www.drupal.org/user/2287430",
+                    "email": "gabriel@sullice.com"
+                }
+            ],
+            "description": "Infrastructure for JSON-RPC 2.0 compliant web services.",
+            "homepage": "https://www.drupal.org/project/jsonrpc",
+            "support": {
+                "source": "https://git.drupalcode.org/project/jsonrpc"
+            },
+            "time": "2019-03-10T05:42:49+00:00"
+        },
         {
             "name": "drupal/kint",
             "version": "2.1.0",
@@ -10114,6 +10163,48 @@
             "homepage": "http://www.drush.org",
             "time": "2019-04-03T11:17:00+00:00"
         },
+        {
+            "name": "e0ipso/shaper",
+            "version": "1.2.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/e0ipso/shaper.git",
+                "reference": "a9b1420201ca3d0831d91879f72bf90e1186fd32"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/e0ipso/shaper/zipball/a9b1420201ca3d0831d91879f72bf90e1186fd32",
+                "reference": "a9b1420201ca3d0831d91879f72bf90e1186fd32",
+                "shasum": ""
+            },
+            "require": {
+                "justinrainbow/json-schema": "^5.2"
+            },
+            "require-dev": {
+                "php-coveralls/php-coveralls": "^2.0",
+                "phpunit/phpcov": "^5.0",
+                "phpunit/phpunit": "^7.0.2"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Shaper\\": "src",
+                    "Shaper\\Tests\\": "tests/src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "GPL-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "Mateu Aguiló Bosch",
+                    "email": "mateu.aguilo.bosch@gmail.com"
+                }
+            ],
+            "description": "Lightweight library to handle in and out transformations in PHP.",
+            "time": "2018-04-23T08:52:32+00:00"
+        },
         {
             "name": "easyrdf/easyrdf",
             "version": "0.9.1",
@@ -10808,6 +10899,72 @@
             "description": "Highlight PHP code in terminal",
             "time": "2018-09-29T18:48:56+00:00"
         },
+        {
+            "name": "justinrainbow/json-schema",
+            "version": "5.2.8",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/justinrainbow/json-schema.git",
+                "reference": "dcb6e1006bb5fd1e392b4daa68932880f37550d4"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/dcb6e1006bb5fd1e392b4daa68932880f37550d4",
+                "reference": "dcb6e1006bb5fd1e392b4daa68932880f37550d4",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "~2.2.20",
+                "json-schema/json-schema-test-suite": "1.2.0",
+                "phpunit/phpunit": "^4.8.35"
+            },
+            "bin": [
+                "bin/validate-json"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "JsonSchema\\": "src/JsonSchema/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Bruno Prieto Reis",
+                    "email": "bruno.p.reis@gmail.com"
+                },
+                {
+                    "name": "Justin Rainbow",
+                    "email": "justin.rainbow@gmail.com"
+                },
+                {
+                    "name": "Igor Wiedler",
+                    "email": "igor@wiedler.ch"
+                },
+                {
+                    "name": "Robert Schönthal",
+                    "email": "seroscho@googlemail.com"
+                }
+            ],
+            "description": "A library to validate a json schema.",
+            "homepage": "https://github.com/justinrainbow/json-schema",
+            "keywords": [
+                "json",
+                "schema"
+            ],
+            "time": "2019-01-14T23:55:14+00:00"
+        },
         {
             "name": "league/container",
             "version": "2.4.1",
@@ -15488,72 +15645,6 @@
             ],
             "time": "2016-12-01T10:57:30+00:00"
         },
-        {
-            "name": "justinrainbow/json-schema",
-            "version": "5.2.8",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/justinrainbow/json-schema.git",
-                "reference": "dcb6e1006bb5fd1e392b4daa68932880f37550d4"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/dcb6e1006bb5fd1e392b4daa68932880f37550d4",
-                "reference": "dcb6e1006bb5fd1e392b4daa68932880f37550d4",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "require-dev": {
-                "friendsofphp/php-cs-fixer": "~2.2.20",
-                "json-schema/json-schema-test-suite": "1.2.0",
-                "phpunit/phpunit": "^4.8.35"
-            },
-            "bin": [
-                "bin/validate-json"
-            ],
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "5.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "JsonSchema\\": "src/JsonSchema/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Bruno Prieto Reis",
-                    "email": "bruno.p.reis@gmail.com"
-                },
-                {
-                    "name": "Justin Rainbow",
-                    "email": "justin.rainbow@gmail.com"
-                },
-                {
-                    "name": "Igor Wiedler",
-                    "email": "igor@wiedler.ch"
-                },
-                {
-                    "name": "Robert Schönthal",
-                    "email": "seroscho@googlemail.com"
-                }
-            ],
-            "description": "A library to validate a json schema.",
-            "homepage": "https://github.com/justinrainbow/json-schema",
-            "keywords": [
-                "json",
-                "schema"
-            ],
-            "time": "2019-01-14T23:55:14+00:00"
-        },
         {
             "name": "mikey179/vfsStream",
             "version": "v1.6.6",
@@ -17180,6 +17271,7 @@
         "drupal/computed_field": 10,
         "drupal/genpass": 20,
         "drupal/image_delta_formatter": 20,
+        "drupal/jsonrpc": 20,
         "drupal/login_history": 20,
         "drupal/mailgun": 20,
         "drupal/migrate_plus": 20,

+ 2 - 2
config/sync/autologout.settings.yml

@@ -1,6 +1,6 @@
-timeout: 1800
+timeout: 3600
 max_timeout: 172800
-padding: 60
+padding: 360
 role_logout: true
 redirect_url: /
 no_dialog: false

+ 3 - 0
config/sync/core.extension.yml

@@ -77,6 +77,9 @@ module:
   inline_entity_form: 0
   interval: 0
   jsonapi: 0
+  jsonrpc: 0
+  jsonrpc_core: 0
+  jsonrpc_discovery: 0
   kint: 0
   language: 0
   link: 0

+ 7 - 8
config/sync/rest.resource.entity.block.yml

@@ -1,6 +1,6 @@
 uuid: 9d8cdf5f-aab0-4a7a-b60b-1a20635a0baa
 langcode: en
-status: true
+status: false
 dependencies:
   module:
     - block
@@ -8,11 +8,10 @@ dependencies:
     - user
 id: entity.block
 plugin_id: 'entity:block'
-granularity: resource
+granularity: method
 configuration:
-  methods:
-    - GET
-  formats:
-    - json
-  authentication:
-    - cookie
+  GET:
+    supported_formats:
+      - json
+    supported_auth:
+      - cookie

+ 1 - 1
config/sync/rest.resource.entity.configurable_language.yml

@@ -1,6 +1,6 @@
 uuid: 0c0bfe4d-3362-49f3-8ea3-f542442a8aed
 langcode: en
-status: true
+status: false
 dependencies:
   module:
     - language

+ 1 - 1
config/sync/rest.resource.entity.node.yml

@@ -1,6 +1,6 @@
 uuid: 268f10a8-04a2-4b09-a229-35fd0bf2061e
 langcode: en
-status: true
+status: false
 dependencies:
   module:
     - node

+ 17 - 0
config/sync/rest.resource.entity.user_role.yml

@@ -0,0 +1,17 @@
+uuid: 089bb52b-6c53-47c3-a06d-df3857d089d9
+langcode: en
+status: false
+dependencies:
+  module:
+    - serialization
+    - user
+id: entity.user_role
+plugin_id: 'entity:user_role'
+granularity: resource
+configuration:
+  methods:
+    - GET
+  formats:
+    - json
+  authentication:
+    - cookie

+ 1 - 0
config/sync/user.role.adherent.yml

@@ -10,4 +10,5 @@ permissions:
   - 'access materio search'
   - 'create member profile'
   - 'update own member profile'
+  - 'use jsonrpc services'
   - 'view own member profile'

+ 1 - 0
config/sync/user.role.admin.yml

@@ -134,6 +134,7 @@ permissions:
   - 'update commerce_promotion'
   - 'update content translations'
   - 'update materio_order_type commerce_order'
+  - 'use jsonrpc services'
   - 'use text format wysiwyg'
   - 'view any commerce_license'
   - 'view any contact_company profile'

+ 1 - 0
config/sync/user.role.admin_showroom.yml

@@ -8,3 +8,4 @@ weight: 0
 is_admin: null
 permissions:
   - 'access materio search'
+  - 'use jsonrpc services'

+ 1 - 0
config/sync/user.role.alpha_testeur.yml

@@ -10,4 +10,5 @@ permissions:
   - 'access materio search'
   - 'create member profile'
   - 'update own member profile'
+  - 'use jsonrpc services'
   - 'view own member profile'

+ 1 - 0
config/sync/user.role.student.yml

@@ -10,4 +10,5 @@ permissions:
   - 'access materio search'
   - 'create member profile'
   - 'update own member profile'
+  - 'use jsonrpc services'
   - 'view own member profile'

+ 8 - 0
web/modules/custom/materio_sapi/materio_sapi.routing.yml

@@ -5,6 +5,14 @@ materio_sapi.search_autocomplete:
     _format: json
   requirements:
     _permission: 'access materio search'
+
+materio_sapi.search_form:
+  path: '/materio_sapi/search_form'
+  defaults:
+    _controller: '\Drupal\materio_sapi\Controller\AjaxSearchForm::getForm'
+    _format: json
+  requirements:
+    _permission: 'access materio search'
 #
 # materio_sapi.materio_sapi_search_form:
 #   path: '/materio_sapi/form/materio_sapi_search'

+ 84 - 0
web/modules/custom/materio_sapi/src/Controller/AjaxSearchForm.php

@@ -0,0 +1,84 @@
+<?php
+// https://www.qed42.com/blog/autocomplete-drupal-8
+// https://www.drupal.org/docs/8/modules/search-api/developer-documentation/executing-a-search-in-code
+
+namespace Drupal\materio_sapi\Controller;
+
+use Drupal\Core\Controller\ControllerBase;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\Core\Form\FormBuilder;
+use Drupal\Core\Form\FormState;
+use Symfony\Component\HttpFoundation\JsonResponse;
+use Symfony\Component\HttpFoundation\Request;
+use Drupal\Core\Cache\CacheableJsonResponse;
+use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\core\render\RenderContext;
+
+
+/**
+ * Defines a route controller for entity autocomplete form elements.
+ */
+class AjaxSearchForm extends ControllerBase {
+
+  /**
+   * The form builder.
+   *
+   * @var \Drupal\Core\Form\FormBuilder
+   */
+  protected $formBuilder;
+
+  /**
+   * Construct.
+   */
+  public function __construct(FormBuilder $formBuilder) {
+    $this->formBuilder = $formBuilder;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('form_builder')
+    );
+  }
+
+  private function getFormDefinition(){
+    $language = \Drupal::languageManager()->getCurrentLanguage()->getId();
+    \Drupal::logger('materio_sapi')->notice($language);
+
+    // $form_state = new FormState();
+    $this->form_builded = $this->formBuilder->getForm('Drupal\materio_sapi\Form\MaterioSapiSearchForm', $language);
+  }
+
+  /**
+   * Handler for getform request.
+   */
+  public function getForm(Request $request) {
+    
+    $this->getFormDefinition();
+
+    $rendered = render($this->form_builded);
+    // $form_builded = $this->form_builded;
+    // $rendered = \Drupal::service('renderer')->executeInRenderContext(new RenderContext(), function () use ($form_builded) {
+    //     return render($form_builded);
+    //   });
+    $data = [
+      'rendered' => $rendered,
+      // '#cache' => [
+      //   'max-age' => \Drupal\Core\Cache\Cache::PERMANENT,
+      //   'tags' => [
+      //     'materio_sapi-search_form-cache',
+      //   ]
+      // ]
+    ];
+
+    $response = new JsonResponse();
+    $response->setData($data);
+    // $response = new CacheableJsonResponse($data);
+    // $response->addCacheableDependency(CacheableMetadata::createFromRenderArray($data));
+
+    return $response;
+  }
+
+}

+ 0 - 5
web/modules/custom/materio_sapi/src/Controller/FormAutocomplete.php

@@ -58,13 +58,8 @@ class FormAutocomplete extends ControllerBase {
       // @see hook_search_api_results_TAG_alter()
       $query->addTag('materio_sapi_autocomplete');
 
-      // Execute the search.
       $results = $query->execute();
 
-      // echo "Result count: {$results->getResultCount()}\n";
-      // $ids = implode(', ', array_keys($results->getResultItems()));
-      // echo "Returned IDs: $ids.\n";
-
       // $items = $results->getResultItems();
       // \Drupal::logger('materio_sapi')->notice($results->getResultCount());
       // \Drupal::logger('materio_sapi')->notice(implode(', ', array_keys($items)));

+ 7 - 0
web/modules/custom/materio_sapi/src/Form/MaterioSapiSearchForm.php

@@ -30,12 +30,19 @@ class MaterioSapiSearchForm extends FormBase {
       '#weight' => '0',
       '#attributes' => [
         "placeholder" => $this->t('Search'),
+        "@keyup" => "keyup",
+        "@keyup.enter" => "submit",
+        "v-model" => "typed"
+
       ],
       '#autocomplete_route_name' => 'materio_sapi.search_autocomplete',
     ];
     $form['submit'] = [
       '#type' => 'submit',
       '#value' => $this->t('Search'),
+      '#attributes' => [
+        '@click.prevent' => "submit",
+      ]
     ];
 
     return $form;

File diff suppressed because it is too large
+ 8 - 0
web/themes/custom/materiotheme/assets/dist/main.js


+ 45 - 14
web/themes/custom/materiotheme/assets/scripts/main.js

@@ -1,7 +1,10 @@
 import Vue from 'vue'
+
 import store from 'vuejs/store'
-import VUserBlock from 'vuejs/components/User/UserBlock'
+
+import VUserBlock from 'vuejs/components/Block/UserBlock'
 import VMainContent from 'vuejs/components/Content/MainContent'
+import VSearchBlock from 'vuejs/components/Block/SearchBlock'
 
 import { mapState } from 'vuex'
 
@@ -12,9 +15,8 @@ import 'theme/assets/styles/main.scss'
 
   var MaterioTheme = function(){
 
-    var v_user_block, v_main_content;
-    // var _is_front = drupalSettings.path.isFront;
-
+    var _v_user_block, _v_main_content, _v_search_block;
+    var _is_front = drupalSettings.path.isFront;
 
     console.log('drupalSettings', drupalSettings);
 
@@ -30,15 +32,20 @@ import 'theme/assets/styles/main.scss'
     function initVues(){
       initUserVBlock()
       initVMainContent()
+      initVSearchBlock()
     }
 
     function initUserVBlock(){
       let mount_point = drupalSettings.user.uid !== 0 ? '#block-userblock' : '#block-userlogin';
       let props = {
-        title: ""
+        title: "",
+        form:""
       };
       switch (mount_point) {
         case '#block-userlogin':
+          // let $form = document.getElementById('user-login-form');
+          // console.log('login form html', $form);
+          // props.form = $form.outerHTML
           let $block = document.querySelector(mount_point);
           props = {
             title: $block.querySelector('h2').textContent,
@@ -63,13 +70,13 @@ import 'theme/assets/styles/main.scss'
       }
       // console.log(props);
 
-      v_user_block = new Vue({
+      _v_user_block = new Vue({
         store,
-        computed: {
-          ...mapState({
-            isloggedin: state => state.User.isloggedin
-          })
-        },
+        // computed: {
+        //   ...mapState({
+        //     isloggedin: state => state.User.isloggedin
+        //   })
+        // },
         created () {
           if(drupalSettings.user.uid !== 0){
             this.$store.commit('User/setUid', drupalSettings.user.uid)
@@ -78,20 +85,44 @@ import 'theme/assets/styles/main.scss'
         },
         render: h => h(VUserBlock, {props:props})
       }).$mount(mount_point)
-      console.log('initUserVBlock', v_user_block);
+      // console.log('initUserVBlock', _v_user_block);
     }
 
     function initVMainContent(){
       let $main_content = document.querySelector('#main-content')
-      console.log('main-content', $main_content);
+      // console.log('main-content', $main_content);
       let main_html = $main_content.innerHTML
-      v_main_content = new Vue({
+      _v_main_content = new Vue({
         store,
         render: h => h(VMainContent, {props:{html:main_html}})
       }).$mount('#main-content')
       // console.log('initTestVContent', v_test_content);
     }
 
+    function initVSearchBlock(){
+      // console.log('initVSearchBlock');
+      let id = "block-materiosapisearchblock"
+      let $search_block = document.getElementById(id)
+      var formhtml = null
+      if($search_block){
+        // get the search form html to pass it as template to the vue
+        // we gain display speed vs async downloaded data
+        formhtml = $search_block.innerHTML
+      }else{
+        // else create the empty block to fill it later with async data
+        $search_block = document.createElement('div')
+        $search_block.setAttribute('id', id)
+        let $region = document.getElementById('content-top');
+        $region.appendChild($search_block);
+      }
+
+      // in any case create the vue
+      _v_search_block = new Vue({
+        store,
+        render: h => h(VSearchBlock, {props:{blockid:id, formhtml:formhtml}})
+      }).$mount('#'+id)
+    }
+
     init()
   } // end MaterioTheme()
 

+ 8 - 0
web/themes/custom/materiotheme/assets/styles/main.scss

@@ -131,6 +131,14 @@ aside.messages{
   padding: 0;
 }
 
+// content top
+#materio-sapi-search-form{
+  .form-item, input.button{
+    display: inline-block;
+  }
+}
+
+
 // front
 article.node--type-frontpage{
   .node__content{

+ 44 - 0
web/themes/custom/materiotheme/templates/block/block--materiosapisearchblock.html.twig

@@ -0,0 +1,44 @@
+{#
+/**
+ * @file
+ * Theme override to display a block.
+ *
+ * Available variables:
+ * - plugin_id: The ID of the block implementation.
+ * - label: The configured label of the block if visible.
+ * - configuration: A list of the block's configuration values.
+ *   - label: The configured label for the block.
+ *   - label_display: The display settings for the label.
+ *   - provider: The module or other provider that provided this block plugin.
+ *   - Block plugin specific settings will also be stored here.
+ * - content: The content of this block.
+ * - attributes: array of HTML attributes populated by modules, intended to
+ *   be added to the main container tag of this template.
+ *   - id: A valid HTML ID and guaranteed unique.
+ * - title_attributes: Same as attributes, except applied to the main title
+ *   tag that appears in the template.
+ * - title_prefix: Additional output populated by modules, intended to be
+ *   displayed in front of the main title tag that appears in the template.
+ * - title_suffix: Additional output populated by modules, intended to be
+ *   displayed after the main title tag that appears in the template.
+ *
+ * @see template_preprocess_block()
+ */
+#}
+{%
+  set classes = [
+    'block',
+    'block-' ~ configuration.provider|clean_class,
+    'block-' ~ plugin_id|clean_class,
+  ]
+%}
+<div{{ attributes.addClass(classes) }}>
+  {{ title_prefix }}
+  {% if label %}
+    <h2{{ title_attributes }}>{{ label }}</h2>
+  {% endif %}
+  {{ title_suffix }}
+  {% block content %}
+    {{ content }}
+  {% endblock %}
+</div>

+ 3 - 5
web/themes/custom/materiotheme/templates/layout/page.html.twig

@@ -66,11 +66,9 @@
       </aside>
     {% endif %}
 
-    {% if page.content_top %}
-      <div class="content-top">
-        {{ page.content_top }}
-      </div>
-    {% endif %}
+    <div id="content-top">
+      {{ page.content_top }}
+    </div>
 
     <div id="main-content">
       {{ page.content|without('messages') }}

+ 13 - 0
web/themes/custom/materiotheme/vuejs/api/msapi-axios.js

@@ -0,0 +1,13 @@
+import axios from 'axios'
+
+// https://github.com/alvar0hurtad0/drupal-vuejs-todo/blob/master/frontend/src/api/axiosInterceptor.js
+
+// console.log('drupalSettings', drupalSettings);
+
+export const MSAPI = axios.create({
+  baseURL: window.location.origin + '/' + drupalSettings.path.pathPrefix + `materio_sapi`,
+  withCredentials: true,
+  headers: {
+    "Content-Type": "application/json"
+  }
+})

+ 65 - 0
web/themes/custom/materiotheme/vuejs/components/Block/SearchBlock.vue

@@ -0,0 +1,65 @@
+<template v-slot="default">
+  <div v-bind:id="blockid">
+    <SearchForm
+      v-if="displayform"
+      v-bind:form="form"></SearchForm>
+  </div>
+</template>
+
+<script>
+import SearchForm from 'vuejs/components/Form/SearchForm'
+import { mapState, mapActions } from 'vuex'
+import { MSAPI } from 'vuejs/api/msapi-axios'
+
+export default {
+  props: ['blockid', 'formhtml'],
+  data(){
+    return {
+      form: null
+    }
+  },
+  computed: {
+    ...mapState({
+      canSearch: state => state.User.canSearch
+    }),
+    displayform(){
+      console.log('computed displayform');
+      return this.canSearch && this.form
+    }
+  },
+  beforeMount() {
+    console.log('SearchBlock beforeMount');
+    this.form = this.formhtml
+  },
+  watch: {
+    canSearch(new_value, old_value) {
+      console.log('canSearch changed, old: '+old_value+", new: "+new_value);
+      if(new_value && !this.form){
+        this.getSearchForm()
+      }
+      if(!new_value && this.form){
+        this.form = null
+      }
+    }
+  },
+  methods: {
+    getSearchForm(){
+      MSAPI.get(`/search_form`)
+        .then(({data}) => {
+          console.log("getSearchForm");
+          this.form = data.rendered
+        })
+        .catch(( error ) => {
+            console.warn('Issue with get searchform', error)
+        })
+    }
+  },
+  components: {
+    SearchForm
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 0 - 0
web/themes/custom/materiotheme/vuejs/components/User/UserBlock.vue → web/themes/custom/materiotheme/vuejs/components/Block/UserBlock.vue


+ 88 - 0
web/themes/custom/materiotheme/vuejs/components/Form/SearchForm.vue

@@ -0,0 +1,88 @@
+<script>
+
+import Vue from 'vue'
+import { MSAPI } from 'vuejs/api/msapi-axios'
+
+export default {
+  data() {
+    return {
+      template: null,
+      typed: ""
+    }
+  },
+  props: ['form'],
+  methods: {
+    keyup() {
+      console.log("search typed", this.typed);
+    },
+    submit() {
+      console.log("search clicked");
+    }
+  },
+  beforeMount() {
+    console.log('SearchForm beforeMount');
+    if(this._props.form){
+      console.log('SearchForm beforeMount if this._props.form ok');
+      this.template = Vue.compile(this._props.form).render
+    }
+  },
+  beforeUpdate() {
+    console.log('SearchForm beforeUpdate');
+    if(this._props.form){
+      console.log('SearchForm beforeUpdate if this._props.form ok');
+      this.template = Vue.compile(this._props.form).render
+    }
+  },
+  mounted(){
+    console.log('SearchForm mounted');
+    // Drupal.attachBehaviors(this.$el);
+  },
+  updated(){
+    console.log('SearchForm updated');
+    // Drupal.attachBehaviors(this.$el);
+  },
+  render(h) {
+    console.log('searchForm render');
+    if(!this.template){
+      return h('span', 'Loading ...')
+    }else{
+      return this.template()
+    }
+  }
+}
+// searchform: (resolve, reject) => (
+//   MSAPI.get(`/search_form`)
+//     .then(({data}) => {
+//       // console.log("materiosapisearchform", data);
+//       resolve({
+//         data() {
+//           return {
+//             typed:""
+//           }
+//         },
+//         methods: {
+//           keyup() {
+//             console.log("search typed", this.typed);
+//           },
+//           submit() {
+//             console.log("search clicked");
+//           }
+//         },
+//         mounted() {
+//           Drupal.attachBehaviors(this.$el);
+//         },
+//         template: data.rendered
+//       })
+//     })
+//     .catch(( error ) => {
+//         console.warn('Issue with get searchform', error)
+//         Promise.reject(error)
+//     })
+//
+// )
+</script>
+
+<style lang="scss" scoped>
+
+
+</style>

+ 1 - 0
web/themes/custom/materiotheme/vuejs/components/User/UserTools.vue

@@ -36,6 +36,7 @@ export default {
       userLogout: 'User/userLogout'
     }),
     onLogout () {
+      console.log('UserTools onLogout');
       this.userLogout()
     }
   }

+ 15 - 19
web/themes/custom/materiotheme/vuejs/store/modules/user.js

@@ -13,7 +13,8 @@ export default {
     token: null,
     logout_token: null,
     isloggedin: false,
-    isAdmin: false
+    isAdmin: false,
+    canSearch: false
   },
 
   // getters
@@ -38,25 +39,35 @@ export default {
       state.uuid = data.uuid[0].value
     },
     setRoles (state, roles) {
+      console.log("User setRoles", roles);
       state.roles = []
       for (var i = 0; i < roles.length; i++) {
         state.roles.push(roles[i].target_id)
       }
-      if(state.roles.indexOf('admin') != -1){
-        console.log('is admin');
+      // check if admin
+      if(state.roles.indexOf('admin') != -1 || state.roles.indexOf('root') != -1){
+        // console.log('is admin');
         state.isAdmin = true
       }
+      // check if has access to search
+      if(state.roles.indexOf('adherent') != -1){
+        // console.log('is admin');
+        state.canSearch = true
+      }
     },
     setLoggedOut (state) {
+      console.log("setLoggedOut state", state);
       state.uid= null
       state.mail = ''
       state.token = null
       state.isloggedin = false
       state.logout_token = null
       if (state.isAdmin){
+
         window.location.reload(true);
       }
       state.asAdmin = false
+      state.canSearch = false
     }
   },
 
@@ -96,34 +107,19 @@ export default {
           if(data.roles){
             commit('setRoles', data.roles)
           }
-          // JSONAPI.get(`/user/user/${state.uuid}?include=roles`)
-          //   .then(({ data }) => {
-          //     console.log('user JSONAPI getUser data', data)
-          //   })
-          //   .catch(( error ) => {
-          //       console.warn('Issue with getUser', error)
-          //       Promise.reject(error)
-          //   })
         })
         .catch(( error ) => {
             console.warn('Issue with getUser', error)
             Promise.reject(error)
         })
     },
-    // checkLoginRole ({ commit, state }){
-    //   console.log('checkLoginRole', state.roles, state.roles.indexOf('admin'))
-    //   if(state.roles.indexOf('admin') != -1){
-    //     console.log('is admin')
-    //     window.
-    //   }
-    // },
     userLogout ({ commit, state }) {
       let credentials = qs.stringify({
         token: state.token
       })
       REST.post('/user/logout', credentials)
         .then((resp) => {
-          console.log('resp', resp)
+          console.log('userLogout resp', resp)
           commit('setLoggedOut')
         })
         .catch(( error ) => {

Some files were not shown because too many files changed in this diff