Search code examples
apostrophe-cms

add parameters for 3rd party jquery plugins like swiper


I'm using some 3rd party jquery plugins and in some cases I need to initialize the plugins separately to give them some additional parameters like shown above.

I load for example swiper library with apostophe-assets:

// lib/modules/apostrophe-assets/index.js
  scripts: [
    ...
    { name: 'vendor/swiper-bundle.min' },
    ...

So the scripts get loaded in the body with apostrophes asset chain what is fine. I'm using the script tag in my widget.html to initialize every swiper plugin on the page separately and add some additional parameters, the admin chooses in widget settings.

// lib/modules/swiper-widgets/views/widget.html

<div class="swiper-container {{ data.widget._id }}">
  <div class="swiper-wrapper">

    {% for swiper in data.widget.swipers %}
    <div class="swiper-slide">
      {{ apos.area(swiper, 'swiper', {
        edit: false,
        widgets: {
          'card': {
            size: 'one-half',
            sizesAttr: '(max-width:600px) 50vw, 40vw',
            noHeight: true,
            focalPoint: true
          },
          'texts': {},
          'video': {}
        }
      }) }}
    </div>
    {% endfor %}

  </div>
</div>

<script type="text/javascript">
  window.addEventListener('load', function () {
    var swiper{{ data.widget._id }} = new Swiper('.{{ data.widget._id }}', {
      loop: {{ data.widget.loop }},
      speed: {{ data.widget.speed }},
      {% if data.widget.autoplay %}
        autoplay: {
          delay: {{ data.widget.delay }},
          disableOnInteraction: {{ data.widget.disableOnInteraction }},
        },
      {% endif %}
    });
  });
</script>

That works ok.

But you see I needed wrap my var in a window.addEventListener('load', function () to wait until the scripts in the body have loaded. Its not really satisfying for admins, cause if they change some parameters of this widget the swiper plugin stops working and the admin need to reload the page manually.

I found out now related to my previous question you have already integrated swiper in apostrophe open museum here.

      var imageSwiper = new Swiper($widget.find('[data-slideshow]')[0], {
        loop: true,
        autoHeight: true,
        slideToClickedSlide: false,
        threshold: 10,
        effect: 'fade',
        fadeEffect: {
          crossFade: true
        },
        pagination: {
          clickable: false
        }
      });

I want something simmilar, but the admin should be able to choose the parameters like 'loop' for example. So I need to map these parameters with the fields I have in:

// lib/modules/swiper-widgets/index.js
        ...
        {
            name: 'loop',
            label: 'Loop Swiper',
            type: 'boolean',
            help: 'Activate loop for swiper (default: No)',
            def: false
        },
        {
            name: 'speed',
            label: 'Swipe Speed',
            type: 'range',
            help: 'Choose speed of transition between swpipes (format: ms, default: 300)',
            min: 100,
            max: 2000,
            step: 100,
            def: 300
        },
        ...

Solution

  • I came up with this solution:

    // lib/modules/swiper-widgets/public/js/always.js
    
    apos.define('swiper-widgets', {
      extend: 'apostrophe-widgets',
      construct: function(self, options) {
        self.play = function($widget, data, options) {
          // Notice we never use a global CSS selector - we always
          // "find" inside $widget. Swiper uses the DOM directly, so use
          // [0] to get from the jQuery object to the DOM element
          var swiper = new Swiper($widget.find('.swiper-container')[0], {
            loop: data.loop,
            speed: data.speed,
            autoHeight: data.autoHeight,
            effect: data.effect,
            cubeEffect: {
              shadow: false,
            },
            keyboard: {
              enabled: true
            },
          });
    
    
        };
      }
    });
    

    Which is working quite nice, but I if you use lean: true this won't work so I added the following file as well:

    // lib/modules/sections-widgets/public/js/lean.js
    
    apos.utils.widgetPlayers['swiper'] = function(el, data, options) {
      // Utilize the provided `data` (properties of the widget)
      // and `options` (options passed to the singleton or area for
      // this widget) to enhance `el`, a DOM element representing the widget
      var swiper = new Swiper(el.querySelector('.swiper-container'), {
        loop: data.loop,
        speed: data.speed,
        autoHeight: data.autoHeight,
        effect: data.effect,
        cubeEffect: {
          shadow: false,
        },
        autoplay: data.autoplay,
        delay: data.delay,
        disableOnInteraction: data.disableOnInteraction,
        keyboard: {
          enabled: true
        },
        navigation: {
          nextEl: '.swiper-button-next',
          prevEl: '.swiper-button-prev',
        }
      });
    };
    

    Additionally I must add the following lines to lib/modules/swiper-widgets/index.js

    ...
      construct: function(self, options) {
        if (self.apos.assets.options.lean) {
          if (self.options.player) {
            self.pushAsset('script', 'lean', { when: 'lean' });
          }
        } else {
          self.pushAsset('script', 'always', { when: 'always' });
        }
      }
    

    and of course in app.js:

    ...
        'swiper-widgets':{
          player: true
        },
    ...
    

    this enables you to initialize external jquery plugins servserside and map additional parameters from corresponding index.js file which was extremely useful for my case and I assume shlould be easily adoptable to other jquery plugin initializations as well.