activities_panels_Menu.js

/**
 *  File    : activities/panels/Menu.js
 *  Created : 20/07/2017
 *  By      : Francesc Busquets <francesc@gmail.com>
 *
 *  JClic.js
 *  An HTML5 player of JClic activities
 *  https://projectestac.github.io/jclic.js
 *
 *  @source https://github.com/projectestac/jclic.js
 *
 *  @license EUPL-1.2
 *  @licstart
 *  (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)
 *
 *  Licensed under the EUPL, Version 1.1 or -as soon they will be approved by
 *  the European Commission- subsequent versions of the EUPL (the "Licence");
 *  You may not use this work except in compliance with the Licence.
 *
 *  You may obtain a copy of the Licence at:
 *  https://joinup.ec.europa.eu/software/page/eupl
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the Licence is distributed on an "AS IS" basis, WITHOUT
 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 *  Licence for the specific language governing permissions and limitations
 *  under the Licence.
 *  @licend
 *  @module
 */

import $ from 'jquery';
import { Activity, ActivityPanel } from '../../Activity';
import MediaContent from '../../media/MediaContent';
import { log } from '../../Utils';

// Use Webpack to import PNG files
import ico00 from './icons/ico00.png';
import ico01 from './icons/ico01.png';
import ico02 from './icons/ico02.png';
import ico03 from './icons/ico03.png';
import icoFolder from './icons/icofolder.png';

/**
 * This class of {@link module:Activity.Activity Activity} is only used in legacy JClic project libraries. It contains
 * one or more buttons pointing to specific JClic projects or to other `Menu` activity panels.
 * @extends module:Activity.Activity
 */
export class Menu extends Activity {
  /**
   * Menu constructor
   * @param {module:project/JClicProject.JClicProject} project - The {@link module:project/JClicProject.JClicProject JClicProject} to which this activity belongs
   */
  constructor(project) {
    super(project);
    this.menuElements = [];
    // This kind of activities are not reported
    this.includeInReports = false;
    this.reportActions = false;
  }
}

/**
 * The {@link module:Activity.ActivityPanel ActivityPanel} where Menu will show its content.
 * @extends module:Activity.ActivityPanel
 */
export class MenuPanel extends ActivityPanel {
  /**
   * MenuPanel constructor
   * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs
   * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the
   * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.
   * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy
   */
  constructor(act, ps, $div) {
    super(act, ps, $div);
    // This kind of activity will always clean the "last project skin" setting
    ps.lastProjectSkin = null;
  }

  /**
   * Prepares the visual components of the activity
   * @override
   */
  buildVisualComponents() {
    if (this.firstRun)
      super.buildVisualComponents();
    // This `div` will contain the action buttons
    const $btnDiv = $('<div/>').css({
      'width': '100%',
      'max-height': '100%',
      'position': 'absolute',
      'top': '50%',
      'transform': 'translateY(-50%)',
      'display': 'flex',
      'flex-wrap': 'wrap',
      'overflow-y': 'auto',
      'place-content': 'center',
      'overflow-y': 'auto'
    });
    this.act.menuElements.forEach((me) => {
      // Create a button for each menu element
      const caption = me.description || me.caption || 'JClic';
      const $btn = $('<button/>', {
        class: 'StockBtn',
        title: caption,
        'aria-label': caption
      }).css({
        'min-width': '80px',
        'max-width': '200px',
        'min-height': '80px',
        'margin': '4px',
        'padding': '4px',
        'display': 'flex',
        'flex-direction': 'column',
        'justify-content': 'center',
        'align-items': 'center'
      });

      // Set the button icon
      const
        iconSrc = MenuPanel.icons[me.icon || '@ico00.png'],
        $img = $('<img/>', { src: iconSrc || '' }).css({
          'max-width': '180px',
          'max-height': '100px',
          'margin': '4px'
        });
      if (!iconSrc) {
        // It's not a stock image, so load `src` when available
        const mbe = this.act.project.mediaBag.getElement(me.icon, true);
        mbe.getFullPathPromise().then(imgFullPath => $img.attr('src', imgFullPath));
      }
      $btn.append($img);

      // Set the button text
      $btn.append($('<span/>').css({
        'max-width': '180px',
        'overflow': 'hidden',
        'white-space': 'nowrap',
        'text-overflow': 'ellipsis'
      }).html(me.caption));

      // Set a click listener method
      // $btn.on('click', function...) does not work!
      $btn[0].addEventListener('click', (ev) => {
        const mc = new MediaContent(me.projectPath ? 'RUN_CLIC_PACKAGE' : 'RUN_CLIC_ACTIVITY', me.sequence);
        if (me.projectPath)
          mc.externalParam = me.projectPath;
        log('info', `Launching ${me.projectPath || ''} ${me.sequence || ''}`);
        this.ps.playMedia(mc);
        ev.preventDefault();
      });

      // Place the created button on the container
      $btnDiv.append($btn);
    });

    // Add the buttons container on the main panel `div`
    this.$div.empty().append($btnDiv);
  }

  /**
   * Sets the real dimension of this panel.
   * @override
   * @param {module:AWT.Dimension} preferredMaxSize - The maximum surface available for the activity panel
   * @returns {module:AWT.Dimension}
   */
  setDimension(preferredMaxSize) {
    return preferredMaxSize;
  }

  /**
   * Basic initialization procedure
   * @override
   */
  initActivity() {
    super.initActivity();

    if (!this.firstRun)
      this.buildVisualComponents();
    else
      this.firstRun = false;

    this.setAndPlayMsg('initial', 'start');
    this.playing = true;
  }
}

/**
 * Default icons used in buttons, inherited from JClic
 * @type {object}
 */
MenuPanel.icons = {
  '@ico00.png': ico00,
  '@ico01.png': ico01,
  '@ico02.png': ico02,
  '@ico03.png': ico03,
  '@icofolder.png': icoFolder,
};

/**
 * Panel class associated to this type of activity: {@link module:activities/panels/Menu.MenuPanel MenuPanel}
 * @type {class} */
Menu.Panel = MenuPanel;

// Register activity class
export default Activity.registerClass('@panels.Menu', Menu);