// = require decidim/map
// = require leaflet.featuregroup.subgroup
// = require decidim/decidim_awesome/awesome_map/categories
// = require decidim/decidim_awesome/awesome_map/proposals
// = require decidim/decidim_awesome/awesome_map/meetings
// = require_self
((exports) => {
const { fetchProposals, fetchMeetings, getCategory } = exports.AwesomeMap;
const collapsedMenu = $("#map").data("collapsed");
const components = $("#map").data("components");
const popupMeetingTemplateId = "marker-meeting-popup";
const popupProposalTemplateId = "marker-proposal-popup";
const cluster = L.markerClusterGroup();
const amendments = [];
const layers = {};
const control = L.control.layers(null, null, {
position: 'topleft',
sortLayers: false,
collapsed: collapsedMenu,
// hideSingleBase: true
});
const allMarkers = [];
const drawMarker = (element, marker, component) => {
let tmpl = component.type === "proposals" ? popupProposalTemplateId : popupMeetingTemplateId,
node = document.createElement("div");
$.tmpl($(`#${tmpl}`), element).appendTo(node);
marker.bindPopup(node, {
maxwidth: 640,
minWidth: 500,
keepInView: true,
className: "map-info"
}).openPopup();
allMarkers.push({
marker: marker,
component: component,
element: element
});
// Check if it has amendments, add it to a list
if(element.amendments && element.amendments.length) {
element.amendments.forEach((amendment) => {
amendments.push(amendment.emendation.id);
});
}
// Add to category layer
let cat = getCategory(element.category);
if(layers[cat.id]) {
marker.addTo(layers[cat.id].group);
// show category if hidden
const $label = $(`.awesome_map-category_${cat.id}`).closest("label");
const $parent = $(`.awesome_map-category_${cat.parent}`).closest("label");
$label.show();
// update number of items
$label.attr("title", parseInt($label.attr("title") || 0) + 1);
// show parent if apply
$parent.show();
$parent.attr("title", parseInt($parent.attr("title") || 0) + 1);
// update component stats
const $component = $(`#awesome_map-component-${component.id}`);
$component.attr("title", parseInt($component.attr("title") || 0) + 1);
}
return marker;
};
const loadElements = (map) => {
// legends
control.addTo(map);
cluster.addTo(map);
// Load markers
components.forEach((component) => {
if(component.type == "proposals") {
// add control layer for proposals
layers.proposals = {
label: `${component.name || window.DecidimAwesome.texts.proposals}`,
group: L.featureGroup.subGroup(cluster)
};
control.addOverlay(layers.proposals.group, layers.proposals.label);
layers.proposals.group.addTo(map);
// add control layer for amendments if any
if(component.amendments) {
layers.amendments = {
label: `${window.DecidimAwesome.texts.amendment}/span>`,
group: L.featureGroup.subGroup(cluster)
}
control.addOverlay(layers.amendments.group, layers.amendments.label);
layers.amendments.group.addTo(map);
}
fetchProposals(component, '', (element, marker) => {
drawMarker(element, marker, component).addTo(layers.proposals.group);
}, () => {
// finall call
map.fitBounds(cluster.getBounds(), { padding: [50, 50] });
allMarkers.forEach((item) => {
// add marker to amendments layers if it's an amendment
if(amendments.find((a) => a == item.element.id)) {
item.marker.removeFrom(layers.proposals.group);
item.marker.addTo(layers.amendments.group);
}
});
});
}
if(component.type == "meetings") {
// add control layer for meetings
layers.meetings = {
label: `${component.name || window.DecidimAwesome.texts.meetings}/span>`,
group: L.featureGroup.subGroup(cluster)
};
control.addOverlay(layers.meetings.group, layers.meetings.label);
layers.meetings.group.addTo(map);
fetchMeetings(component, '', (element, marker) => {
drawMarker(element, marker, component).addTo(layers.meetings.group);
}, () => {
map.fitBounds(cluster.getBounds(), { padding: [50, 50] });
});
}
});
// add categories control layers
if(window.AwesomeMap.categories.length) {
let lastLayer = layers[Object.keys(layers)[Object.keys(layers).length - 1]];
// Add Categories "title"
if(lastLayer) {
lastLayer.label = `${lastLayer.label}
${window.DecidimAwesome.texts.categories}`;
control.removeLayer(lastLayer.group);
control.addOverlay(lastLayer.group, lastLayer.label);
}
window.AwesomeMap.categories.forEach((category) => {
// add control layer for this category
layers[category.id] = {
label: ` ${category.name}`,
group: L.featureGroup.subGroup(cluster)
};
layers[category.id].group.addTo(map);
control.addOverlay(layers[category.id].group, layers[category.id].label);
// hide layer by default, it will be activated if there's any marker in it
setTimeout(() => {
$(`.awesome_map-category_${category.id}`).closest("label").hide();
});
});
// watch events for subcategories syncronitzation
const getCatFromClass = (name) => {
let id = name.match(/awesome_map-category_(\d+)/)
if(!id) return;
const cat = getCategory(id[1]);
if(!cat || !cat.name) return;
return cat;
};
const indeterminateInput = (id) => {
$('[class^="awesome_map-category_"]').parent().prev().prop("indeterminate", false);
if(id) {
let $input = $(`.awesome_map-category_${id}`).parent().prev();
if(!$input.prop("checked")) {
$input.prop("indeterminate", true);
}
}
};
map.on('overlayadd', (e) => {
const cat = getCatFromClass(e.name);
if(!cat) return;
// if it's a children, put the parent to indeterminate
indeterminateInput(cat.parent);
});
// on remove a parent category, remove all children
map.on('overlayremove', (e) => {
const cat = getCatFromClass(e.name);
if(!cat) return;
cat.children().forEach((c) => {
let $el = $(`.awesome_map-category_${c.id}`);
if($el.parent().prev().prop("checked")) {
$el.click();
}
});
});
}
};
// currentMap might not be loaded yet so let's delay a bit
// TODO: improve this
const waitMap = () => {
if(exports.Decidim && exports.Decidim.currentMap) {
loadElements(exports.Decidim.currentMap);
} else {
setTimeout(() => {
waitMap();
}, 100);
}
};
waitMap();
})(window);