/**
* This file includes general methods for all maps.
* */
/**
* Return custom [lat,long] of Iran provinces(states)
* GENERAL METHOD
* @return array
* */
function pws_map_get_province_location(province) {
switch (province) {
case "استان آذربایجان شرقی":
case "آذربایجان شرقی":
return [38.07334959970686, 46.29652594872965];
case "استان آذربایجان غربی":
case "آذربایجان غربی":
return [37.549090717092994, 45.066199010210255];
case "استان اردبیل":
case "اردبیل":
return [38.250977963284896, 48.29705810186877];
case "استان اصفهان":
case "اصفهان":
return [32.64673138417923, 51.667879557967524];
case "استان البرز":
case "البرز":
return [35.81196370276513, 51.007535158359644];
case "استان ایلام":
case "ایلام":
return [33.636365996683466, 46.42491419928686];
case "استان بوشهر":
case "بوشهر":
return [28.93175276389951, 50.86857312232024];
case "استان تهران":
case "تهران":
return [35.6997006457524, 51.33774439566025];
case "استان چهارمحال و بختیاری":
case "چهارمحال و بختیاری":
case "استان چهار محال بختیاری":
return [32.32563021660313, 50.84949361049016];
case "استان خراسان جنوبی":
case "خراسان جنوبی":
return [32.86310366749149, 59.21695375448638];
case "استان خراسان رضوی":
case "خراسان رضوی":
return [36.29749367352903, 59.60612708710633];
case "استان خراسان شمالی":
case "خراسان شمالی":
return [37.47623251667375, 57.33164422289255];
case "استان خوزستان":
case "خوزستان":
return [31.323059172676807, 48.679357419175574];
case "استان زنجان":
case "زنجان":
return [36.66799998523621, 48.48300964754603];
case "استان سمنان":
case "سمنان":
return [35.58316228924757, 53.38874832538042];
case "استان سیستان و بلوچستان":
case "سیستان و بلوچستان":
return [29.489146181976437, 60.86376908620963];
case "استان فارس":
case "فارس":
return [29.603818535342484, 52.5385086580618];
case "استان قزوین":
case "قزوین":
return [36.27970518245759, 50.00488463587101];
case "استان قم":
case "قم":
return [34.64630675359567, 50.88227991502279];
case "استان کردستان":
case "کردستان":
return [35.3114839356263, 47.002433312163674];
case "استان کرمان":
case "کرمان":
return [30.292465037358852, 57.066016844077694];
case "استان کرمانشاه":
case "کرمانشاه":
return [34.32392220244171, 47.07327816944752];
case "استان کهگیلویه و بویراحمد":
case "کهگیلویه و بویراحمد":
return [30.667254302880878, 51.57938820663321];
case "استان گلستان":
case "گلستان":
return [36.84175133875932, 54.43273154185354];
case "استان گیلان":
case "گیلان":
return [37.27888580875177, 49.58475222497668];
case "استان لرستان":
case "لرستان":
return [33.48489556493388, 48.35352126935422];
case "استان مازندران":
case "مازندران":
return [36.56589812594005, 53.058534799566075];
case "استان مرکزی":
case "مرکزی":
return [34.095494177321996, 49.690812344504934];
case "استان هرمزگان":
case "هرمزگان":
return [27.179653213579527, 56.27686633792305];
case "استان همدان":
case "همدان":
return [34.79871932655388, 48.51427475358636];
case "استان یزد":
case "یزد":
return [31.888301558794836, 54.364528979651965];
default:
return null;
}
}
/**
* Check if current viewing page is admin area or not!
* @return bool
* */
function pws_is_admin() {
return pws_map_params.is_admin !== '' && typeof pagenow !== 'undefined';
}
function pws_map_distance_between_two_points(user_coords, distance_type) {
return new Promise(function (resolve, reject) {
// rest url with distance endpoint
let rest_url = pws_map_params.rest_url + 'distance';
let request_payload = {
user_coords: user_coords,
type: distance_type,
};
// Make the AJAX request to OpenRouteService
jQuery.ajax({
url: rest_url,
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(request_payload),
success: function (response) {
if (response.success) {
resolve(response);
} else {
reject(new Error(response.message));
}
},
error: function (error) {
console.error('خطا در محاسبه فاصله: ', error);
reject(error);
}
});
});
}
function pws_map_show_distance(vars) {
let pws_map_shipping_information = jQuery('.pws-order__map__shipping__information');
let user_coords = JSON.stringify({"lat": vars.user_lat, "long": vars.user_long});
if (!vars.show_distance_type || vars.show_distance_type === 'none') {
return;
}
if (!pws_map_shipping_information.length) {
return;
}
if (!vars.user_has_location) {
return;
}
pws_map_distance_between_two_points(user_coords, vars.show_distance_type)
.then(function (data) {
pws_map_shipping_information.html('' + data.distance + '')
})
.catch(function (error) {
pws_map_shipping_information.html('');
console.error('خطا در محاسبه فاصله: ', error);
});
}
/**
* Check map placement which passed in params
* @return bool
* */
function pws_map_after_checkout() {
return pws_map_params.checkout_placement === 'after_form';
}
/**
* Method to check if shipping state has been enabled
* @return bool
* */
function pws_checkout_shipping_address_enabled() {
return jQuery('#ship-to-different-address-checkbox').is(':checked');
}
/**
* Check if admin can edit and set new point on the map
* */
function pws_map_admin_editing_enabled() {
if (!pws_is_admin()) {
return true;
}
return jQuery('#pws-map-admin-edit').is(':checked');
}
function pws_map_is_admin_tools_page() {
let currentUrl = window.location.href;
if (currentUrl.includes('?page=pws-tools')) {
return true;
}
}
function pws_map_get_order_id_from_url() {
let url_params = new URLSearchParams(window.location.search);
let order_id = 0;
if (url_params.has('post')) {
order_id = url_params.get('post');
}
if (url_params.has('id')) {
order_id = url_params.get('id');
}
return order_id;
}
/*
* Function to add geolocate control and logic to map
* TODO: Fix locate control
*/
function pws_map_add_geolocate_control(map_object) {
return false;
L.control.locate({
strings: {
title: "دریافت مکان فعلی"
},
position: "topright",
locateOptions: {
enableHighAccuracy: true
}
}).addTo(map_object);
}
// Function to add markers to the map
function pws_map_add_marker(map_coords, icon_url, marker_layer_group) {
var icon = L.icon({
iconUrl: icon_url,
iconSize: [18, 32],
iconAnchor: [16, 32]
});
var marker = L.marker(map_coords, {icon: icon});
// Each layer group can only have one marker
marker_layer_group.clearLayers();
marker.addTo(marker_layer_group);
}
/**
* Set map initial styles and customization
* */
function pws_map_customize(container) {
/*Append custom css*/
var pws_map_css_customization = ``;
let pws_map_style_tag = jQuery('');
pws_map_style_tag.text(pws_map_css_customization);
jQuery('head').append(pws_map_style_tag);
container.css({
'min-width': container.data('min-width'),
'min-height': container.data('min-height')
});
}
function pws_map_call_ajax(url, callback, headers) {
jQuery.ajax({
url: url,
type: 'GET',
xhrFields: {
responseType: 'blob'
},
beforeSend: function (xhr) {
headers.forEach(h => {
xhr.setRequestHeader(h.header, h.value);
});
},
success: function (response) {
callback(response);
},
error: function (xhr, status, error) {
console.error('AJAX request failed:', status, error);
}
});
}
function pws_show_location_data(lat, lng, vars) {
let pws_order_map_coords = jQuery(".pws-order__map__coords");
if (!pws_order_map_coords.length || !vars.user_has_location) {
return;
}
pws_order_map_coords.html('' + 'عرض جغرافیایی (lat): ' + lat + '
' + 'طول جغرافیایی (long): ' + lng + '');
}
function pws_show_location_on_map(map_object, user_input_address, zoom, user_marker_layer) {
let province_coords = pws_map_get_province_location(user_input_address);
if (province_coords == null) {
return;
}
map_object.setView(province_coords, zoom);
jQuery("#pws_map_location").val('');
user_marker_layer.clearLayers();
}
function pws_map_is_checkout() {
let body = jQuery('body');
return body.hasClass('woocommerce-checkout') &&
!body.hasClass('woocommerce-order-received') &&
!window.location.search.includes('order-pay')
}
/**
* Interact with click on map
* */
function pws_map_on_click(event, map_object, vars, user_marker_layer, store_marker_layer) {
// If user is admin but the general editing option is not enabled, do nothing!
if (pws_is_admin() && !pws_map_admin_editing_enabled()) {
return;
}
let clicked_lat_lng = event.latlng;
let clicked_lat = clicked_lat_lng.lat;
let clicked_lng = clicked_lat_lng.lng;
if (clicked_lat < 0 || clicked_lng < 0) {
jQuery('#pws_map_location').val('');
user_marker_layer.clearLayers();
store_marker_layer.clearLayers();
return;
}
let clicked_location = {lat: clicked_lat, long: clicked_lng};
// Two different situation in editing map location for user marker
let is_admin_order_editing = pws_is_admin() && pws_map_admin_editing_enabled() && !pws_map_is_admin_tools_page();
let is_user_editing = !pws_is_admin() && pws_map_is_checkout();
if (is_admin_order_editing || is_user_editing) {
// Set the map view to the clicked location for user
map_object.setView([clicked_lat, clicked_lng], map_object.getZoom());
pws_map_add_marker([clicked_lat, clicked_lng], vars.user_marker_url, user_marker_layer);
jQuery('#pws_map_location').val(JSON.stringify(clicked_location));
// Show lat and long in order editing mode
pws_show_location_data(clicked_lat, clicked_lng);
vars.user_lat = clicked_lat;
vars.user_long = clicked_lng;
pws_map_show_distance(vars);
}
// If admin tools page is active, add store marker
let is_admin_settings_editing = pws_map_admin_editing_enabled() && pws_map_is_admin_tools_page();
if (pws_is_admin() && is_admin_settings_editing) {
pws_map_add_marker([clicked_lat, clicked_lng], vars.store_marker_url, store_marker_layer);
jQuery('#pws_map\\[store_location\\]').val(JSON.stringify(clicked_location));
}
// Draw route if store marker and line drawing are enabled
if (pws_is_admin() && !is_admin_settings_editing) {
pws_map_draw_route([vars.store_lat, vars.store_long], [clicked_lat, clicked_lng], vars, map_object);
}
}
/**
* Set data global variables
* */
function pws_map_set_variables(container) {
// Extract map container ID
var map_id = container.attr('id') || '';
// Extract marker-related data attributes from the container
let user_marker_color = container.data('user-marker-color');
let store_marker_color = container.data('store-marker-color');
let user_marker_url = container.data('user-marker-url');
let store_marker_url = container.data('store-marker-url');
let is_store_marker_enabled = container.data('store-marker-enable');
// Extract ORS-related data
let draw_line_color = container.data('store-draw-line-color');
// Extract location-related data attributes
let user_lat = container.data('center-lat');
let user_long = container.data('center-long');
let store_lat = container.data('store-lat');
let store_long = container.data('store-long');
let center_lat = user_lat;
let center_long = user_long;
if (pws_is_admin() && pws_map_is_admin_tools_page()) {
center_lat = store_lat;
center_long = store_long;
}
// Extract zoom level and other map-specific settings
let map_zoom = container.data('zoom') || 13;
let show_distance_type = container.data('show-distance-type');
let user_has_location = container.data('user-has-location');
// Neshan map specific data
let type = container.data('type') || 'neshan';
let poi = container.data('poi') || false;
let traffic = container.data('traffic') || false;
// Return all variables as an object
return {
map_id,
user_marker_color,
store_marker_color,
user_marker_url,
store_marker_url,
is_store_marker_enabled,
draw_line_color,
user_lat,
user_long,
store_lat,
store_long,
center_lat,
center_long,
map_zoom,
show_distance_type,
user_has_location,
type,
poi,
traffic
};
}
function pws_map_geolocation(map_object, vars, marker_layer) {
// API endpoint for geolocation-db
var geolocation_url = "https://geolocation-db.com/json/";
// Make an AJAX request to fetch the user's geolocation data
jQuery.ajax({
url: geolocation_url,
method: 'GET',
success: function (response) {
// If the response is a string, parse it as JSON
if (typeof response === 'string') {
try {
response = JSON.parse(response);
} catch (error) {
console.error('Error parsing JSON response:', error);
return;
}
}
// Ensure response contains valid latitude and longitude
if (typeof response.latitude === 'undefined' || typeof response.longitude === 'undefined') {
console.error('Geolocation response did not contain valid coordinates.');
return;
}
var lat = response.latitude;
var lng = response.longitude;
// Check if lat and lng are valid numbers before proceeding
if (isNaN(lat) || isNaN(lng)) {
console.error('Invalid latitude or longitude:', lat, lng);
return;
}
// Create an object to store the lat/lng for setting input values
var geolocation = {
lat: lat,
long: lng
};
// Add marker to the map using pws_map_add_marker method
pws_map_add_marker([lat, lng], vars.user_marker_url, marker_layer);
// Set the #pws_map_location value with the coordinates in JSON format
jQuery('#pws_map_location').val(JSON.stringify(geolocation));
// Optionally, center the map on the user's location
map_object.setView([lat, lng], vars.map_zoom);
// Draw route if store marker and line drawing are enabled
if (pws_is_admin() && vars.is_store_marker_enabled) {
pws_map_draw_route([vars.store_lat, vars.store_long], [lat, lng], vars, map_object);
}
},
error: function (error) {
// Handle any errors that occur during the request
console.error('Error fetching geolocation data:', error);
}
});
}
/**
* Init the store marker on the map
* */
function pws_map_initialize_store_marker(marker_layer, vars) {
// Add store marker if enabled
if (!vars.is_store_marker_enabled && !pws_is_admin()) {
return;
}
pws_map_add_marker([vars.store_lat, vars.store_long], vars.store_marker_url, marker_layer);
}
/**
* Init the user marker on the map
* */
function pws_map_initialize_user_marker(marker_layer, vars, map_object) {
// Add user marker and center the map to user location
if (!vars.user_has_location) {
return;
}
pws_map_add_marker([vars.user_lat, vars.user_long], vars.user_marker_url, marker_layer);
jQuery('#pws_map_location').val(JSON.stringify({
lat: vars.user_lat,
long: vars.user_long
}));
map_object.setView([vars.user_lat, vars.user_long], 15);
// Draw route if is in admin area and line drawing are enabled
if (pws_is_admin()) {
pws_map_draw_route([vars.store_lat, vars.store_long], [vars.user_lat, vars.user_long], vars, map_object);
}
}
/**
* Controls over hiding the map
* If map is hidden but location is required, It'll
*/
function pws_map_view_control(hide) {
let map_container = jQuery('.pws-map__container');
let required_location = jQuery('input[name="pws_map_required_location"]');
if (map_container.length === 0) {
return;
}
if (hide) {
map_container.hide();
if (required_location.length > 0) {
required_location.val('0');
}
} else {
map_container.show();
if (required_location.length > 0) {
required_location.val('1');
}
}
}
/**
* Draw route between store and user on map
* */
function pws_map_draw_route(start_coords, end_coords, vars, map_object, retryCount = 0) {
// The line drawing is accessible when real distance type is on real
// It shows the user the example routing of distance + When real distance type is selected ORS token will be accessible
if (!vars.show_distance_type || vars.show_distance_type !== 'real') {
return;
}
const MAX_RETRIES = 3;
if (!pws_map_params.ORS_token) {
console.error('لطفا کلید دسترسی معتبر OpenRouteService برای مسیریابی بین فروشگاه و کاربر را وارد کنید.');
return;
}
// Construct the OpenRouteService URL for driving directions
var pws_map_ORS_url = `https://api.openrouteservice.org/v2/directions/driving-car?api_key=${pws_map_params.ORS_token}&start=${start_coords[1]},${start_coords[0]}&end=${end_coords[1]},${end_coords[0]}`;
// Make an AJAX request to the OpenRouteService API
jQuery.ajax({
url: pws_map_ORS_url,
method: 'GET',
success: function (pws_map_response) {
if (pws_map_response.features && pws_map_response.features.length > 0) {
var pws_map_coordinates = pws_map_response.features[0].geometry.coordinates;
var pws_map_lat_lngs = pws_map_coordinates.map(function (pws_map_coord) {
return [pws_map_coord[1], pws_map_coord[0]];
});
// Remove the old polyline if it exists in vars
if (vars.pws_map_polyline) {
map_object.removeLayer(vars.pws_map_polyline);
}
// Draw the polyline on the map
vars.pws_map_polyline = L.polyline(pws_map_lat_lngs, {
color: vars.draw_line_color,
weight: 4
}).addTo(map_object);
} else {
console.error('هیچ داده جغرافیایی از مسیر یافت نشد.');
}
},
error: function (pws_map_error) {
if (pws_map_error.status === 503 && retryCount < MAX_RETRIES) {
// Retry the request after a delay (e.g., 2 seconds)
console.warn(`سرویس در دسترس نیست، تلاش (${retryCount + 1}/${MAX_RETRIES})...`);
setTimeout(function () {
pws_map_draw_route(start_coords, end_coords, vars, map_object, retryCount + 1);
}, 2000);
} else {
console.error('خطا در دریافت اطلاعات مسیر: ', pws_map_error.responseText || pws_map_error.statusText);
}
}
});
}
/**
* Zoom on provinces
* */
function pws_map_zoom_on_province(map_object, marker_layer) {
let billing_state_element = jQuery("#billing_state");
if (billing_state_element.length) {
billing_state_element.on('change', function (e) {
let user_input_address = 'استان ' + jQuery('#billing_state option:selected').text();
pws_show_location_on_map(map_object, user_input_address, 10, marker_layer);
});
}
let shipping_state_element = jQuery('#shipping_state');
if (shipping_state_element.length) {
shipping_state_element.on('change', function (e) {
let user_input_address = 'استان ' + jQuery('#shipping_state option:selected').text();
pws_show_location_on_map(map_object, user_input_address, 10, marker_layer);
});
}
}
(function ($) {
$(document).ready(function () {
/**
* Toggle show map in billing and shipping forms of woocommerce checkout
* */
$("#ship-to-different-address-checkbox").change(function () {
if (this.checked) {
$('.woocommerce-billing-fields').find('.pws-map__container').hide();
} else {
$('.woocommerce-billing-fields').find('.pws-map__container').show();
}
});
/**
* Disables the map when virtual products exists in the Cart
* Using WC()->cart->needs_shipping() method
*/
if (pws_map_is_checkout() && pws_map_params.needs_shipping !== "1") {
// Hide the map
pws_map_view_control(true);
}
/**
* Toggle alert admin about editing the map
* */
let pws_map_admin_edit_checkbox = $("#pws-map-admin-edit");
if (pws_map_admin_edit_checkbox.length) {
pws_map_admin_edit_checkbox.on('change', function () {
let pws_map_admin_edit_checkbox_label = $('label[for="' + $(this).attr('id') + '"]');
if (!this.checked) {
pws_map_admin_edit_checkbox_label.html('ویرایش نقشه')
pws_map_admin_edit_checkbox_label.css({
'color': '#2271b1',
'border-color': '#2271b1'
});
return;
}
pws_map_admin_edit_checkbox_label.css({
'color': '#b14a22',
'border-color': '#b14a22'
});
pws_map_admin_edit_checkbox_label.html('در حال ویرایش')
});
}
});
$(document).on('ajaxComplete', function () {
/**
* Remove | from leaflet attribution
* */
let leaflet_control_attribution = $('.leaflet-control-attribution');
if (leaflet_control_attribution.length) {
leaflet_control_attribution.html(function (_, html) {
return html.replace(/\s*\|\s*/g, '');
});
}
// Controls over enabled shipping methods
function pws_map_log_shipping_method(input_enabled_methods) {
let selected_method = $('input[name="shipping_method[0]"]:checked').val();
if (selected_method === undefined) {
selected_method = $('input[name="shipping_method[0]"]').val();
}
if (selected_method === undefined) {
return;
}
let enabled_methods = [];
try {
enabled_methods = JSON.parse(input_enabled_methods);
} catch (e) {
enabled_methods = ['all_shipping_methods'];
console.log('روش های حمل و نقل نامعتبر هستند. نقشه در تمامی روش های حمل و نقل نمایش داده خواهد شد.');
}
// Always show the map if "all_shipping_methods" is included
if (enabled_methods.includes('all_shipping_methods')) {
return;
}
// Dynamically remove variants from enabled methods
let base = [];
enabled_methods.forEach(string => {
if (string.indexOf(':') === -1) { // No colon means base method
base.push(string);
}
});
enabled_methods = enabled_methods.filter(string => {
// Keep the method if it is not a variant (doesn't have a colon)
return !base.some(baseMethod => string.startsWith(baseMethod + ':')) || base.includes(string);
});
// Check if the selected method is either a base method or a valid variant of an enabled base method
if (!enabled_methods.some(baseMethod => {
// If the selected method doesn't have a colon, it's a base method
if (selected_method.indexOf(':') === -1) {
return baseMethod === selected_method;
}
// If the selected method is a variant, check if its base method is in the enabled methods
let baseMethodSelected = selected_method.split(':')[0];
return enabled_methods.includes(baseMethodSelected) || enabled_methods.includes(selected_method);
})) {
pws_map_view_control(true); // Hide map if not valid
} else {
pws_map_view_control(false); // Show map if valid
}
}
// Control the shipping method, only when there's enabled shipping methods element exist
let pws_map_enabled_shipping_methods = $('input[name="pws_map_enabled_shipping_methods"]');
let pws_map_shipping_method_field = $('input[name="shipping_method[0]"]');
if (pws_map_enabled_shipping_methods.length && pws_map_shipping_method_field.length) {
pws_map_enabled_shipping_methods = pws_map_enabled_shipping_methods.val();
pws_map_log_shipping_method(pws_map_enabled_shipping_methods);
$(document).on('change, load', 'input[name="shipping_method[0]"]', function () {
pws_map_log_shipping_method(pws_map_enabled_shipping_methods);
});
}
});
})(jQuery);