@Myself: TODO: Write better issue summary!

Context:

EUCC JavaScript functions

Problem:

The current JavaScript code of this wonderful module is very much UI based. It's hard to fire events or listen for them from external APIs. Examples can be found in the related issues.
Good examples are to show / hide the popup through a JavaScript call from a custom button, change consent, ...

Proposed solution:

Instead the current implementation should use calls to a more generic JS API which is also usable from global.

Next Steps:

  1. Write down requirements and API calls + events
  2. D8 & D7 Implementation
  3. Documentation
  4. Inform other issues about new API calls
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Anybody created an issue. See original summary.

Anybody’s picture

Title: Write public JS API for actions & events » Write & document public JS API for actions & events
Assigned: Unassigned » Anybody
reszli’s picture

the attached patch could be a starting point for this issue:

  • creates a global namespace which can be shared between modules who wish to extend it
  • defer the scipt to allow other scipts to set hanlders first
  • creates global variables for storing the current status and categories
  • replaced the use of getter callback, thus cookies are read at init, global vars are used afterwards
  • triggers events and defienes observers pre- & post- load & save status & category (8 in total)
  • shows withdraw button after accept all and save preferences without reload

done it for both D7 and D8

D8 sample:

(function ($, Drupal, drupalSettings) {

  "use strict";

  // Sep up the namespace as a function to store list of arguments in a queue.
  Drupal.eu_cookie_compliance = Drupal.eu_cookie_compliance || function() {
    (Drupal.eu_cookie_compliance.queue = Drupal.eu_cookie_compliance.queue || []).push(arguments)
  };

  // Initialize the object with some data.
  Drupal.eu_cookie_compliance.a = +new Date;

  // A shorter name to use when accessing the namespace.
  var self = Drupal.eu_cookie_compliance;

  // Define a new handler.
  var postPreferencesLoadHandler = function(response) {

    // Do your magic based on the current state:
    // response = {
    //   currentStatus: 0 / 1 / 2,
    //   currentCategories: ['functional', 'marketing', ...]
    // }

  };

  // Attach the handler to the event.
  Drupal.eu_cookie_compliance('postPreferencesLoad', postPreferencesLoadHandler);

})(jQuery, Drupal, drupalSettings);

example usage (sending category data to Google Tag Manager) for both D7 and D8 can be found in my sandbox module:
https://www.drupal.org/sandbox/reszli/3138494

Grayle’s picture

Status: Active » Needs work

Tested the last patch, and with it I'm getting a console error.

Uncaught TypeError: Cannot read property 'length' of undefined
    at Function.self.handleEvent (eu_cookie_compliance.js?v=1:781)
    at Function.Drupal.eu_cookie_compliance.getCurrentStatus (eu_cookie_compliance.js?v=1:433)
    at HTMLBodyElement.<anonymous> (eu_cookie_compliance.js?v=1:25)
    at Function.each (jquery.min.js?v=3.4.1:2)
    at k.fn.init.each (jquery.min.js?v=3.4.1:2)
    at Object.attach (eu_cookie_compliance.js?v=1:22)
    at drupal.js?v=8.8.5:25
    at Array.forEach (<anonymous>)
    at Object.Drupal.attachBehaviors (drupal.js?v=8.8.5:22)
    at drupal.init.js?v=8.8.5:28
  /**
   * Handle event by finding and executing handlers pushed to the queue.
   */
  self.handleEvent = function(eventName, observer) {
    var handlers = filterQueue(eventName);

    for (var i = 0; i < handlers.length; i++) {
      if (typeof handlers[i] !== 'undefined') {
        observer.subscribe(handlers[i]);
        observer.fire({
          currentStatus: _euccCurrentStatus,
          currentCategories: _euccSelectedCategories
        });
        observer.unsubscribe(handlers[i]);
      }
    }
  };

handlers has no length. My guess is filterQueue's if statement isn't met so it returns nothing. Moving the "var handlers = []" and "return handlers" outside the if statement should fix it.

reszli’s picture

Assigned: Anybody » Unassigned
Status: Needs work » Needs review
FileSize
24.08 KB
26.49 KB
832 bytes

thanks Grayle! indeed, when there are no handlers attached the code would fail
attached patch fixes this by always returning at least an empty array when filtering the queue

NOTE: the patches here apply only if you also have the latest patch from #3068670: Improve the UX for cookie categories

svenryen’s picture

@reszli: Do you have any steps or sample code that can be used to review this issue?

reszli’s picture

@svenryen example usage (sending category data to Google Tag Manager) for both D7 and D8 can be found in my sandbox module
https://www.drupal.org/sandbox/reszli/3138494

Anybody’s picture

Hi reszli,

great work, thanks a lot! What we can see is, that this concept can even make the code simpler or better readable in some areas and we should definitely use this chance for a refactoring of the JS code.

Some critical questions, not to criticise you or your solution, but to discuss for the best solution:
1)

defer the scipt to allow other scripts to set hanlders first

Which would mean EUCC doesn't "block" scripts, instead it also "defers" their execution. So Google Analytics for example registers its codes for eventual execution instead of executing itself?

Can we think of cases where that would not work and perhaps make things even worse because of the "defer"? Another module would have to rely on this, correct?

For reference: EUCCX instead encapsulated scripts and defers their execution. Before we decide which way to go (or both), we should think about how to interact best with Drupal libraries, dynamic code and the possibility that a third-party module isn't changed by the maintainer but other modules can define plugins to defer their execution.

I'd like to discuss this now, before the "defer" logic gets in because once shipped this all will be hard to remove / change again!

And my bitter results from many problems with tracking snippets and cookie compliance is that priority /loading order is often a problem if you only have limited access to all parts of the code (e.g. comes from different contrib modules).

2) You decided to implement your own observers. That's fair, while still using jQuery in eu_cookie_compliance a trigger() / on() event could be a lot more "lightweight" (if jQuery is not removed here)?

I know that's a heretical debate... ;) I just want to point out, that we should be sure this is the best way to go. Quite a lot of boilerplate code is added for these observers.

Thank you very much again and as said above - this is for discussion, not because I don't like your patch :)

svenryen’s picture

> we should definitely use this chance for a refactoring of the JS code.

I disagree with this. I think we should get these new features out the door in 1.x. Refactoring all the JS code (and removing jQuery) is probably a 2.x task.

Anybody’s picture

re: @svenryen: Ok that sounds fair and you are the maintainer. :)

2.x could then perhaps start with several concept & code cleanup steps plus test driven. What I just wanted to say with
> we should definitely use this chance for a refactoring of the JS code.

is, that these added functionalities lead to more and more complex code and eventually spaghetti, which justifies a refactoring as soon as we know how to proceed. But also it shows chances to better encapsulation and separation via API. I agree keeping 1.x stable is very important.

svenryen’s picture

I tried the EUCC GTM module the other day and it seems to work.

Is that sufficient testing, or do we need more testing of this patch?

Grayle’s picture

We've been using this patch successfully in several projects, so for us I think we can call that RTBC.

svenryen’s picture

Status: Needs review » Reviewed & tested by the community

I trust you on that (will still give it some scrutiny as well) so bumping the status.

Anybody’s picture

Could someone please help to create a follow-up for an 2.0.x issue with a clean issue summary (by issue template) to write down the requirements? That would help a lot!

I think a complete rewrite makes sense, but as @svenryen decided, this issue itself should go into 1.x.

svenryen’s picture

Status: Reviewed & tested by the community » Needs work

@grayle, I tried the d8 and maybe I'm missing something, but it doesn't cleanly apply. We've added quite a bit to the module since June. Would you be able to do a re-roll of the patches?

Grayle’s picture

Sure thing

Grayle’s picture

Status: Needs work » Needs review
FileSize
26.89 KB

Rerolled D8 patch against current head of dev (instead of against patched dev as old patch).

Grayle’s picture

FileSize
27.12 KB

The last submitted patch, 17: D8.3130015.public-js-api.17.patch, failed testing. View results

  • Grayle authored e598590 on 8.x-1.x
    Issue #3130015 by reszli, Grayle, Anybody, svenryen: Write...
svenryen’s picture

Committed the D8 version just now.

svenryen’s picture

Status: Needs review » Patch (to be ported)
Grayle’s picture

Grayle’s picture

Status: Patch (to be ported) » Needs review

  • Grayle committed ad3f424 on 7.x-1.x
    Issue #3130015 by reszli, Grayle, svenryen, Anybody: Write...
Grayle’s picture

Status: Needs review » Fixed
Grayle’s picture

Talked with Sven on slack to review/commit this patch

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.