Skip to content

Instantly share code, notes, and snippets.

@fczbkk
Created September 10, 2019 06:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fczbkk/0bbca7851dc05f166fe7485152a3c12e to your computer and use it in GitHub Desktop.
Save fczbkk/0bbca7851dc05f166fe7485152a3c12e to your computer and use it in GitHub Desktop.
Robustný spôsob, ako dynamicky vložiť mapu z api.mapy.cz do stránky. Použité knižnice "gatedQueue" a "loadExternalScript" sú znovupoužiteľné.
/**
* @typedef {Object} gatedQueueInterface
* @property {Function} openGate - Executes all functions currently in the queue. Functions added to the queue will be executed immediately, until the gate is closed again.
* @property {Function} closeGate - Closes the gate. Functions added to the queue will be executed only once the gate is opened again.
* @property {function(): boolean} isGateOpen - Checks whether the gate is currently open.
* @property {Function} addToQueue - Adds function(s) to the queue. Accepts single function or an array of functions.
* @property {Function} clearQueue - Removes all functions from the queue.
* @property {Function} processQueue - Calls all functions in the queue. Even if the gate is currently closed.
* @property {Function} getQueue - Returns copy of current queue.
*/
/**
* Creates queue object filled with functions to be called once gate has been opened.
* This was primarily developed for mechanisms of asynchronously loading external dependencies while giving the ability to call these dependencies' methods before they have been loaded.
* @param {Object} [config]
* @param {Array.<Function>} [config.queue = []]
* @param {boolean} [isOpen = false]
* @return {{openGate: openGate, addToQueue: addToQueue, closeGate: closeGate, getQueue: (function(): *[]), clearQueue: clearQueue, processQueue: processQueue, isGateOpen: (function(): boolean)}}
*/
export function createGatedQueue ({
queue = [],
isOpen = false
} = {}) {
const openGate = () => {
processQueue()
isOpen = true
}
const closeGate = () => {
isOpen = false
}
const clearQueue = () => {
queue = []
}
const addToQueue = (newItems) => {
queue = [].concat(queue, newItems)
if (isOpen) {
processQueue()
}
}
const processQueue = () => {
queue.forEach((fn) => fn())
clearQueue()
}
const isGateOpen = () => isOpen
const getQueue = () => [].concat(queue)
if (isOpen) {
processQueue()
}
return {
openGate,
closeGate,
isGateOpen,
clearQueue,
addToQueue,
processQueue,
getQueue
}
}
import { createGatedQueue } from './gatedQueue.js'
const NOOP = () => {}
const IS_LOADED = '1'
const IS_NOT_LOADED = '0'
const SCRIPT_LOAD_QUEUES = {}
/**
* @typedef {Object} load_external_script_options
* @property {boolean} [async = true] - If set to `true`, the SCRIPT element will be created with "async" attribute.
*/
/**
* Loads external script into the page. Makes sure the script is only inserted once.
* @param {string} url
* @param {load_external_script_options} [options]
* @return {Promise} - Called when script is inserted and loaded.
*/
export function loadExternalScript (url, options = {}) {
return new Promise((resolve) => {
const existingScriptElement = findScriptElement(url)
if (existingScriptElement) {
if (existingScriptElement.dataset.loaded === IS_LOADED) {
resolve()
} else {
addToScriptLoadQueue(url, resolve)
}
} else {
createScriptElement(url, options, resolve)
}
})
}
/**
* Finds SCRIPT element with given `url` as a "src" attribute.
* @param {string} url
* @return {Element | null}
*/
export function findScriptElement (url) {
return document.head.querySelector(`script[src="${url}"]`)
}
/**
* Creates SCRIPT element.
* @param {string} url
* @param {load_external_script_options} [options]
* @param {Function} [onload] - Function to be called when script is inserted and loaded.
* @return {HTMLElement} - Inserted SCRIPT element.
*/
export function createScriptElement (url, options = {}, onload = NOOP) {
const { async = true } = options
const scriptElement = document.createElement('script')
addToScriptLoadQueue(url, onload)
if (async) {
scriptElement.setAttribute('async', 'true')
}
scriptElement.dataset.loaded = IS_NOT_LOADED
scriptElement.onload = () => {
scriptElement.dataset.loaded = IS_LOADED
SCRIPT_LOAD_QUEUES[url].openGate()
}
document.head.appendChild(scriptElement)
// Set the "src" attribute as a last thing, otherwise eager browsers (e.g. IE) will start loading it too soon and miss the "onload" event.
scriptElement.setAttribute('src', url)
return scriptElement
}
function addToScriptLoadQueue (id, fn) {
if (typeof SCRIPT_LOAD_QUEUES[id] === 'undefined') {
SCRIPT_LOAD_QUEUES[id] = createGatedQueue({ queue: [fn] })
} else {
SCRIPT_LOAD_QUEUES[id].addToQueue(fn)
}
}
import { loadExternalScript } from '../utils/loadExternalScript'
const LOADER_URL = 'https://api.mapy.cz/loader.js'
const LOADER_QUEUE = createGatedQueue()
const DEFAULT_LONGITUDE = 14.41790
const DEFAULT_LATITUDE = 50.12655
const DEFAULT_ZOOM = 7
export function init () {
return new Promise((resolve) => {
LOADER_QUEUE.addToQueue(resolve)
loadExternalScript(LOADER_URL, { async: true })
.then(() => {
// Seznam's loader object
const { Loader } = window
Loader.lang = 'cs'
Loader.async = true
Loader.load(null, { suggest: true }, () => {
createMapObject()
LOADER_QUEUE.openGate()
})
})
})
}
function createMapObject ({
longitude = DEFAULT_LONGITUDE,
latitude = DEFAULT_LATITUDE,
zoom = DEFAULT_ZOOM
} = {}) {
// TODO: dohladanie spravneho elementu, do ktoreho sa ma mapa vlozit
const mapElement = document.getElementById('mapWrapper')
const center = window.SMap.Coords.fromWGS84(longitude, latitude)
const map = new window.SMap(getMapElement(), center, zoom)
// TODO: tu sa nastavuje konfiguracia mapy
return map
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment