geolocation-8.x-3.x-dev/js/geolocation-map.js

js/geolocation-map.js
/**
 * @file
 * Javascript for the Geolocation map formatter.
 */
(function (Drupal) {
  Drupal.geolocation.maps = {
    /**
     * @type {Map<string, GeolocationMapBase>}
     */
    initializedMaps: new Map(),
    mapPromises: new Map(),
    delayedInitialization: new Map(),
    mapProviderSettings: new Map(),
    addInitializedMap(map) {
      this.initializedMaps.set(map.id, map);
      if (this.mapPromises.has(map.id)) {
        for (const resolve of this.mapPromises.get(map.id)) {
          resolve(map);
        }
        this.mapPromises.delete(map.id);
      }
    },
    /**
     * @param {string} mapId
     * @returns {Promise<GeolocationMapBase>} Promise object represents the sum of a and b
     */
    getMap(mapId) {
      return new Promise((resolve) => {
        if (this.initializedMaps.has(mapId)) {
          resolve(this.initializedMaps.get(mapId));
        } else {
          const promises = this.mapPromises.get(mapId) ?? [];
          promises.push(resolve);
          this.mapPromises.set(mapId, promises);
        }
      });
    },
    addMapProviderCallback(mapProviderId, callback) {
      let mapProviderSettings;
      if (this.mapProviderSettings.has(mapProviderId)) {
        mapProviderSettings = this.mapProviderSettings.get(mapProviderId);
      } else {
        mapProviderSettings = {
          ready: false,
          callbacks: [],
        };
      }

      if (mapProviderSettings.ready) {
        callback();
      } else {
        mapProviderSettings.callbacks.push(callback);
        this.mapProviderSettings.set(mapProviderId, mapProviderSettings);
      }
    },
    mapProviderCallback(mapProviderId) {
      if (!this.mapProviderSettings.has(mapProviderId)) {
        console.error(mapProviderId, "Geolocation: Could not initialize callback for map provider.");
        return false;
      }
      const mapProviderSettings = this.mapProviderSettings.get(mapProviderId);
      mapProviderSettings.ready = true;

      while (mapProviderSettings.callbacks.length) {
        mapProviderSettings.callbacks.shift()();
      }
      this.mapProviderSettings.set(mapProviderId, mapProviderSettings);
    },
    delayInitialization(mapId, callback) {
      const callbacks = this.delayedInitialization.get(mapId) ?? [];
      callbacks.push(callback);
      this.delayedInitialization.set(mapId, callbacks);
    },
    initializeDelayed(mapId = null) {
      if (mapId) {
        if (this.delayedInitialization.has(mapId)) {
          for (const callback of this.delayedInitialization.get(mapId)) {
            callback();
          }
          this.delayedInitialization.delete(mapId);

          return true;
        }
        return false;
      }

      this.delayedInitialization.forEach((callbacks, mapId) => {
        for (const callback of this.delayedInitialization.get(mapId) ?? []) {
          callback();
        }
        this.delayedInitialization.delete(mapId);
      });

      return true;
    },
  };

  Drupal.AjaxCommands.prototype.geolocation = function (ajax, response) {
    if (response.method !== "replaceCommonMapView") {
      return;
    }

    const oldContent = document.querySelector(response.selector);

    if (!oldContent) {
      return;
    }

    const template = document.createElement("template");
    template.innerHTML = response.data.trim();
    const newContent = template.content.firstElementChild;

    Drupal.detachBehaviors(oldContent, response.settings);
    oldContent.insertAdjacentElement("afterend", newContent);

    new Promise((resolve) => {
      const mapPromises = [];
      oldContent.querySelectorAll(".geolocation-map-wrapper").forEach((oldMapWrapper) => {
        const mapId = oldMapWrapper.getAttribute("id");
        if (!mapId) {
          console.error("Ajax.replaceCommonMapView: Existing Map ID not found.");
          return;
        }

        if (!Drupal.geolocation.maps.initializedMaps.has(mapId)) {
          console.error("Ajax.replaceCommonMapView: Existing Map not found.");
          return;
        }

        const oldMapContainer = oldMapWrapper.querySelector(".geolocation-map-container");
        if (!oldMapContainer) {
          console.error("Ajax.replaceCommonMapView: Existing Map container not found.");
          return;
        }

        const newMapWrapper = newContent.querySelector(".geolocation-map-wrapper");
        if (!newMapWrapper) {
          Drupal.geolocation.maps.initializedMaps.delete(mapId);
          console.error(`Ajax.replaceCommonMapView: New Map wrapper '${mapId}' not found.`);
          return;
        }

        const newMapContainer = newMapWrapper.querySelector(".geolocation-map-container");
        if (!newMapContainer) {
          console.error("Ajax.replaceCommonMapView: New Map container not found.");
          return;
        }

        mapPromises.push(
          new Promise((resolve) => {
            const map = Drupal.geolocation.maps.initializedMaps.get(mapId);
            map.wrapper = newMapWrapper;
            const newContainerParent = newMapContainer.parentNode;
            newMapContainer.remove();
            newContainerParent.appendChild(oldMapContainer);
            resolve();
          })
        );
      });

      resolve(Promise.all(mapPromises));
    }).then(() => {
      oldContent.remove();
      Drupal.attachBehaviors(newContent, response.settings);
    });
  };

  /**
   * Find and display all maps.
   *
   * @type {Drupal~behavior}
   *
   * @prop {Drupal~behaviorAttach} attach
   *   Attaches Geolocation Maps formatter functionality to relevant elements.
   */
  Drupal.behaviors.geolocationMap = {
    /**
     * @param context
     * @param drupalSettings
     * @param {Object} drupalSettings.geolocation
     * @param {GeolocationMapSettings[]} drupalSettings.geolocation.maps
     */
    attach: (context, drupalSettings) => {
      context.querySelectorAll(".geolocation-map-wrapper").forEach(function (mapWrapper) {
        if (typeof drupalSettings.geolocation === "undefined") {
          throw new Error("Bailing out for lack of settings.");
        }

        if (mapWrapper.length === 0) {
          console.info("Stopping map processing as no map wrapper present.");
          return;
        }

        if (mapWrapper.classList.contains("geolocation-map-processed")) {
          return;
        }
        mapWrapper.classList.add("geolocation-map-processed");

        const mapSettings = {};
        mapSettings.id = mapWrapper.getAttribute("id");
        mapSettings.wrapper = mapWrapper;

        mapSettings.lat = 0;
        mapSettings.lng = 0;

        for (const mapId of Object.keys(drupalSettings.geolocation.maps)) {
          if (mapId === mapSettings.id) {
            Object.assign(mapSettings, drupalSettings.geolocation.maps[mapId]);
          }
        }

        if (mapWrapper.getAttribute("data-lat") && mapWrapper.getAttribute("data-lng")) {
          mapSettings.lat = Number(mapWrapper.getAttribute("data-lat"));
          mapSettings.lng = Number(mapWrapper.getAttribute("data-lng"));
        }

        if (mapWrapper.getAttribute("map-type")) {
          mapSettings.type = mapWrapper.getAttribute("map-type");
        }

        new Promise((resolve, reject) => {
          const map = Drupal.geolocation.maps.initializedMaps.get(mapSettings.id);
          if (map) {
            resolve(map);
          } else {
            reject(new Error("geolocation-map: Could not create GeolocationMap object."));
          }
        })
          .catch(() => {
            return new Promise((resolve) => {
              switch (mapSettings.conditional_initialization ?? "no") {
                case "programmatically":
                  Drupal.geolocation.maps.delayInitialization(mapSettings.id, () => {
                    resolve();
                  });
                  break;

                case "button": {
                  Drupal.geolocation.maps.delayInitialization(mapSettings.id, () => {
                    resolve();
                  });

                  const mapContainer = mapWrapper.querySelector(".geolocation-map-container");
                  if (!mapContainer) {
                    return;
                  }
                  const conditionalInitContainer = document.createElement("div");
                  conditionalInitContainer.classList.add("geolocation-map-conditional");

                  const conditionalInitDescription = document.createElement("div");
                  conditionalInitDescription.textContent = mapSettings.conditional_description ?? Drupal.t("Clicking this button will embed a map.");
                  conditionalInitContainer.appendChild(conditionalInitDescription);

                  const button = document.createElement("button");
                  button.innerHTML = mapSettings.conditional_label ?? Drupal.t("Show map");
                  button.classList.add("button");
                  button.onclick = (event) => {
                    event.preventDefault();
                    Drupal.geolocation.maps.initializeDelayed(mapSettings.id);
                    conditionalInitContainer.remove();
                  };
                  conditionalInitContainer.appendChild(button);

                  mapContainer.appendChild(conditionalInitContainer);
                  break;
                }

                case "viewport": {
                  Drupal.geolocation.maps.delayInitialization(mapSettings.id, () => {
                    resolve();
                  });

                  const mapContainer = mapWrapper.querySelector(".geolocation-map-container");
                  if (!mapContainer) {
                    return;
                  }

                  const observer = new IntersectionObserver(
                    (entries, observer) => {
                      entries.forEach((entry) => {
                        if (entry.isIntersecting) {
                          Drupal.geolocation.maps.initializeDelayed(mapSettings.id);
                          observer.unobserve(entry.target);
                        }
                      });
                    },
                    {
                      root: null,
                      rootMargin: "0px",
                      threshold: mapSettings.conditional_viewport_threshold,
                    }
                  );
                  observer.observe(mapContainer);

                  break;
                }

                default:
                  resolve();
              }
            })
              .then(() => {
                return import(mapSettings.import_path);
              })
              .then((mapProviderImport) => {
                /** @type {GeolocationMapBase} */
                const map = new mapProviderImport.default(mapSettings);
                return map.initialize();
              })
              .then((map) => {
                Drupal.geolocation.maps.initializedMaps.set(map.id, map);
                return map.loadCenterOptions();
              })
              .then((map) => {
                return map.loadFeatures();
              })
              .then((map) => {
                map.removeControls();
                map.wrapper.querySelectorAll(".geolocation-map-controls > *").forEach((control) => {
                  map.addControl(control);
                });
                return map;
              });
          })
          .then((map) => {
            return map.loadTileLayers();
          })
          .then((map) => {
            map.removeMapMarkers();
            map.removeMapShapes();
            return map.loadDataLayers();
          })
          .then((map) => {
            if (!map.dataLayers.has("default")) {
              throw new Error("No default layer defined. Breaking");
            }
            return map;
          })
          .then((map) => {
            // Only _after_ markers are loaded.
            map.setCenterByOptions();

            // Just in case.
            map.wrapper.classList.remove("ajax-loading");

            map.wrapper.querySelectorAll(".geolocation-location").forEach((element) => {
              element.style.display = "none";
            });

            map.readyFeatures();

            return map;
          })
          .then((map) => {
            Drupal.geolocation.maps.addInitializedMap(map);
          })
          .catch((e) => {
            console.error(e, "Something failed during map init.");
            return false;
          });
      });
    },
    detach: (context, drupalSettings) => {},
  };
})(Drupal);

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc