I'm testing h5p with php 8 and drupal 10 for a new site. To get it working, I applied the drupal_rector patch, adjusted the info.yml files and had to remove .once in a javascript file -> with these changes my first tests were successful.

I'll add my patch here - perhaps more changes are needed and the patch could be a starting point for drupal 10 setups.

CommentFileSizeAuthor
h5p_drupal10.patch14.03 KBanschinsan

Issue fork h5p-3348114

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

anschinsan created an issue. See original summary.

andrewjaykirkpatrick’s picture

Thanks for the .once code change.
I can confirm this works for me in Drupal 10.0.3 with PHP8.
I cannot edit new H5P interactive items due to a reliance on CKEditor3 as defined in /vendor/h5p/h5p-editor/h5peditor.class.php

'ckeditor/ckeditor.js'.

I also noted a small issue with json decoded values being null rather than empty (single quotes) in /src/Entity/H5PContent.php
- 'authors' => json_decode($this->get('authors')->value),
+ 'authors' => json_decode($this->get('authors')->value ?: ''),

- 'changes' => json_decode($this->get('changes')->value),
+ 'changes' => json_decode($this->get('changes')->value ?: ''),

omar_emailat made their first commit to this issue’s fork.

pjotr.savitski’s picture

It might be better to use the

use Drupal\Component\EventDispatcher\Event;

for FinishedEvent class as that would work with both Drupal 9 and 10.

pjotr.savitski’s picture

I'm not yet 100% sure, but inability to use interactive items might have everything to do with removal of the calls to jquery.once and not replacing those with the new custom once that is available in both versions 9 and 10.

H5P is not using the default CKEditor added by Drupal, but a custom one that is shipped with the h5p-editor dependency. This is why ckeditor/ckeditor.js is a false positive and irrelevant to the upgrade process.

I've currently refactored the code in application.js file to use the new logic and the code looks like this (please note that I've replaced this with element in all the relevant places; I've edited and included the whole file):

/* global drupalSettings jQuery Drupal */

(function ($, Drupal, H5P, H5PEditor, once) {
  var initialized;
  var submitHandlers = [];

  /**
   * One time setup of the H5PEditor
   *
   * @param Object settings from drupal
   */
  H5PEditor.init = function () {
    if (initialized) {
      return; // Prevent multi init
    }
    initialized = true;

    // Set up editor settings
    H5PEditor.$ = H5P.jQuery;
    H5PEditor.baseUrl = drupalSettings.path.baseUrl;
    H5PEditor.basePath = drupalSettings.h5peditor.libraryPath;
    H5PEditor.contentLanguage = drupalSettings.h5peditor.language;
    mapProperties(H5PEditor, drupalSettings.h5peditor,
      ['contentId', 'fileIcon', 'relativeUrl', 'contentRelUrl', 'editorRelUrl', 'apiVersion', 'copyrightSemantics', 'metadataSemantics', 'assets']);
  };

  // Init editors
  Drupal.behaviors.H5PEditor = {
    attach: function (context, settings) {
      once('H5PEditor', '.h5p-editor', context).forEach(function(element) {
        H5PEditor.init();

        // Grab data values specifc for editor instance
        var $this = $(element);
        var parametersFieldId = $this.data('parametersid');
        var libraryFieldId = $this.data('libraryid');
        var contentId = $this.data('contentId');
        var $form = $this.parents('form');

        // Locate parameters field
        var $params = $('#' + parametersFieldId, context);

        // Locate library field
        var $library = $('#' + libraryFieldId, context);

        // Create form submit handler
        var submit = {
          element: null,
          handler: function (event) {
            if (h5peditor !== undefined) {

              var params = h5peditor.getParams();

              if (params !== undefined && params.params !== undefined) {
                // Validate mandatory main title. Prevent submitting if that's not set.
                // Deliberatly doing it after getParams(), so that any other validation
                // problems are also revealed
                if (!h5peditor.isMainTitleSet()) {
                  return event.preventDefault();
                }

                // Set main library
                $library.val(h5peditor.getLibrary());

                // Set params
                $params.val(JSON.stringify(params));

                // TODO - Calculate & set max score
                // $maxscore.val(h5peditor.getMaxScore(params.params));
              }
            }
          }
        };
        submitHandlers.push(submit);

        // Create new editor
        var h5peditor = new H5PEditor.Editor($library.val(), $params.val(), element, function () {
          submit.element = this.frameElement; // Update frame element
          var iframeH5PEditor = this.H5PEditor;
          iframeH5PEditor.contentId = (contentId ? contentId : undefined);
          iframeH5PEditor.ajaxPath = settings.h5peditor.ajaxPath.replace(':contentId', (contentId ? contentId : 0));
          iframeH5PEditor.filesPath = settings.h5peditor.filesPath + '/editor';

          /**
           * Help build URLs for AJAX requests
           */
          iframeH5PEditor.getAjaxUrl = function (action, parameters) {
            var url = iframeH5PEditor.ajaxPath + action;

            if (parameters !== undefined) {
              for (var key in parameters) {
                url += '/' + parameters[key];
              }
            }

            return url;
          };
        });

        $form.submit(submit.handler);
      });
    },
    detach: function (context, settings, trigger) {
      if (trigger === 'serialize') {
        once('H5PEditor', '.h5p-editor-iframe', context).forEach(function(element) {
          for (var i = 0; i < submitHandlers.length; i++) {
            if (submitHandlers[i].element === element) {
              // Trigger submit handler
              submitHandlers[i].handler();
            }
          }
        });
      }
    }
  };

  /**
   * Map properties from one object to the other
   * @private
   * @param {Object} to
   * @param {Object} from
   * @param {Array} props
   */
  var mapProperties = function (to, from, props) {
    for (var i = 0; i < props.length; i++) {
      var prop = props[i];
      to[prop] = from[prop];
    }
  };

})(jQuery, Drupal, H5P, H5PEditor, once);

The editor seems to be working just fine for me, although I'm still on Drupal 9.5.x and can't determine if it also works with the latest release of version 10. NB! Please notice that h5peditor library will need a dependency of core/once to be added.

ammaletu’s picture

There seem to be two Merge Requests trying to make H5P ready for Drupal 10. This one, and the one in https://www.drupal.org/project/h5p/issues/3329297. Would it make sense to combine the two? Or better to simply get one of them ready and then see about cleaning up the other one? The other MR has at least one patch which is missing here (see comment #14 in the other ticket).

Is there anything I can do to move this along? We want to upgrade to Drupal 10 in a few days, and now I see that we can't without heavily patching this module. End-of-life for Drupal 9 is in 8 days! Please let me know what the next step would be. Incorporating Pjotr's comments into the MR?

catch’s picture

Status: Needs review » Closed (duplicate)

Closing this as duplicate of #3329297: Automated Drupal 10 compatibility fixes, please focus any efforts over there.