Skip to content
  1. Extras
  2. ms_CDEK2
  3. Development

Development

Changing styles

Wrong approach

  1. Include your styles after the default ones;
  2. Override values in your styles.

Right approach

  1. Copy the default file;
  2. Override only what you need;
  3. Set the new path in system setting ms_cdek2_frontend_css.

Changing chunks

Which chunks to use is defined in presets (similar to SendIt). To use your own chunks, set the path to your preset file in ms_cdek2_presets_path. Do not change preset parameters you do not understand.

Chunk parameters

  1. suggestItemTpl — chunk for address suggestion list items;
  2. listWrapTpl — wrapper chunk for pickup point list (must contain select[name="point"]);
  3. listItemTpl — chunk for pickup list item (must output option);
  4. emptyTpl — chunk when no pickup points found for the postal code;
  5. statusTpl — delivery status chunk.

Информация

To see available placeholders, use an empty value for the parameter (works only for statusTpl and listItemTpl).

Hide or change toast messages

Toast texts are in lexicon files with keys:

  • ms_cdek2_error
  • ms_cdek2_choose_pvz_error_message

Change map zoom on init

js
document.addEventListener('mscdek:map:show', e => {
  const {object} = e.detail;
  object.mapUpdParams['zoom'] = 10;
})

Block suggestion selection when street is empty and door delivery is selected

js
document.addEventListener('mscdek:address:select:suggestion', e => {
  const {location, object} = e.detail;
  const selectedDelivery = document.querySelector('[name="delivery"]:checked');
  if (!location.data.street && selectedDelivery.value === object.config.deliveriesByType.door) {
    e.preventDefault();
    object.sendit.Notify.error('Enter street');
  }
})

Show status as toast instead of default block

Внимание

Remove the status output block from the page.

js
document.addEventListener('mscdek:status:get', e => {
  const {status, object} = e.detail;
  if (!object.statusBlock) {
    const message = `Delivery by ${status.calc_result.delivery_date_range.max}, ${status.delivery_cost} rub.`
    object.sendit.Notify.info(message);
  }
})

Show map in modal

Внимание

This example uses Fancybox

Add a button to open the modal (hidden by default with class .hide)

html

<button type="button" class="hide" data-fancybox data-src="#map-modal">Select pickup point</button>

Add JS to show/hide the button on load and when delivery method changes

Информация

3 in toggleMapButton is the ID of the pickup delivery method.

js
const toggleMapButton = () => {
  const btn = document.querySelector('[data-src="#map-modal"]');
  const delivery = document.querySelector('[name=delivery]:checked');
  if (Number(delivery.value) === 3) {
    btn.classList.remove('hide');
  } else {
    btn.classList.add('hide');
  }
}

document.addEventListener('DOMContentLoaded', e => {
  toggleMapButton();
})

document.addEventListener('change', e => {
  if (e.target.name === 'delivery') {
    toggleMapButton();
  }
})

Put the map block inside the modal

html
<div id="map-modal" style="display:none;width:800px;max-width: 100%">
    <div data-mscdek-map class="hide"></div>
</div>

Open modal on button click

js
document.addEventListener('click', e => {
  if (e.target.closest('[data-src="#map-modal"]')) {
    Fancybox.defaults.dragToClose = false; // so user can pan the map
    Fancybox.show([{src: "#map-modal", type: "inline"}]);
  }
})

Extra pickup info and confirm selection with button

Информация

This assumes the page has no block

html
<div class="hide" data-mscdek-list></div>

and instead uses a hidden field

html
<input type="hidden" name="point">

Add template for pickup details block

html
<template data-mscdek-baloon>
    <div data-pvz-details class="hide">
        <h5>Address:<br>
            <span data-mscdek-prop="address"></span>
        </h5>
        <p>Working hours:<br>
            <span data-mscdek-prop="work_time"></span>
        </p>
        <button id="select-pvz-btn" type="button">Select</button>
    </div>
</template>

Add styles for map and details block

css
[data-mscdek-map] {
    position: relative;
}

[data-pvz-details]:not(.hide) {
    flex-direction: column;
    display: flex;
    align-items: start;
    justify-content: center;
    position: absolute;
    left: 0;
    top: 0;
    height: 100%;
    background: rgba(0, 0, 0, .7);
    width: 40%;
    padding: 30px;
    color: white;
}

Insert details block into map block after init

js
document.addEventListener('mscdek:map:init', e => {
  const {mapBlock} = e.detail;

  if (!mapBlock.querySelector('[data-pvz-details]')) {
    const baloonTemplate = document.querySelector('[data-mscdek-baloon]');
    mapBlock.insertAdjacentHTML('beforeend', baloonTemplate.innerHTML);
    baloonTemplate.innerHTML = '';
  }
})

Show pickup details

js
const showBaloon = (markerData) => {
  const baloon = document.querySelector('[data-pvz-details]');
  if (baloon) {
    const addressBlock = baloon.querySelector('[data-mscdek-prop="address"]');
    const workTimeBlock = baloon.querySelector('[data-mscdek-prop="work_time"]');
    const btn = baloon.querySelector('#select-pvz-btn');
    btn.setAttribute('data-pvz-code', markerData.code);
    addressBlock.innerHTML = markerData.location.address;
    workTimeBlock.innerHTML = markerData.work_time;

    baloon.classList.remove('hide');
    return true;
  }
  return false;
}

document.addEventListener('mscdek:map:choose', e => {
  const {markerData, object} = e.detail;
  showBaloon(markerData.properties)
})

Handle pickup selection confirm

js
document.addEventListener('click', e => {
  if (e.target.closest('#select-pvz-btn')) {
    const pointField = document.querySelector('[name="point"]');
    const pvzCode = e.target.closest('#select-pvz-btn').dataset.pvzCode;
    const msCdekList = window.mscdek.container.getModule('list');
    const result = await msCdekList.pointsStore.get(msCdekList.indexField.value);
    const selectedPoint = result.data.points.find(point => point.code === pvzCode);
    pointField && (pointField.value = selectedPoint[msCdekList.config.pointValueFieldName] ?? selectedPoint.location[msCdekList.config.pointValueFieldName]);
    pointField && pointField.dispatchEvent(new Event('change', {bubbles: true}));

    // uncomment to show toast with selected pickup address
    /*
    const message = `Pickup: ${selectedPoint.location.address} (${selectedPoint.distance} km.)`
    SendIt.Notify.info(message);
    */

    /* Fancybox.close(); */ // uncomment to close modal after selection
  }
})

Different marker for pickup with even ID

js
document.addEventListener('mscdek:marker:create', e => {
  const {marker, markerData} = e.detail;
  if (markerData.id % 2 === 0) {
    marker.querySelector('img').src = 'assets/marker.png';
  }
})