Separator

 

Bitrix: Множественное свойство типа "Привязка к карте Google Maps", исправление ошибки

Свойство типа Привязка к карте Google Maps появилось в Битриксе уже давно, аж в 2009 году. Если прокрутить до комментов, можно найти внизу такую проблему:

anya_o 28.05.2010 15:10:53
добрый день! не получается вводить множественные значения этих свойств, пробовала в разных браузерах. у гугла показывается одна карта и несколько еще "загружается" (в эксплорере вообще показывается пустая страница), у яндекса показывается несколько строк для координат но сохраняется только верхняя. это будет исправлено?

Надо сказать это не единственное упоминание, встречаются и другие. Проблема судя по всему до сих пор не исправлена, хотя отзывы от пользователей с просьбой устранить баг были и в 2011 году. Я проблему решил и предлагаю почитать об этом далее.

Итак, делаем множественное свойство "Привязка к карте Google Maps", заходим в создание элемента и... свойство не работает, т.к. все карты являются простыми картинками. В js-отладчике явственно видна ошибка от google js-api указывающее на дублирующее подключение скрипта карт. Явная ошибка. Лезем в ядро (пока только посмотреть). В /bitrix/modules/fileman/properties.php обнаруживаем что за вывод карт отвечает компонент bitrix:map.google.system. Лезем туда. В коде компонента оказывается мало полезного, зато в шаблоне встречается такой вот код:
function BXMapLoader_(MAP_KEY)
{
 if (null == window.bGoogleMapScriptsLoaded)
 {
  if (window.google && window.google.maps)
  {
   window.bGoogleMapScriptsLoaded = true;
   BX.ready(init_);
  }
  else
  {
   BX.loadScript(
    'http://www.google.com/jsapi?rnd=' + Math.random(), 
    function () {
     if (BX.browser.IsIE())
      setTimeout("window.google.load('maps', , {callback: init_, other_params: 'sensor=false&language='})", 1000);
     else
      google.load('maps', , {callback: init_, other_params: 'sensor=false&language='});
    }
   );
  }
 }
 else
 {
  init_();
 }
}

Невооружённым глазом видно что битрикс загружает гугловый js-api, а когда он подгрузится вызывает подгрузку гугл-карт. У гугл-карт стоит callback-вызов на инициализацию карты (т.е. когда скрипт гугл-карт подгрузится пустые блоки google-карт заменятся этим вызовом на нормальную карту).

Что же происходит когда мы делаем это свойство множественным? Битрикс подключает этот компонент несколько раз. Несколько раз подключается и этот шаблон. Несколько раз грузится google js api. Несколько раз вызывается инициализация (что само по себе вроде аварию не создаёт, но неправильно). Чтобы устранить дублирование загрузки, в код поставлено несколько "костылей", посмотрим код:




 window.arGoogleMapCallbacks = {};
 function initAllGoogleMaps()
 {
  for(var i in window.arGoogleMapCallbacks)
  {
   window.arGoogleMapCallbacks[i]();
  }
 }



function BXMapLoader_(MAP_KEY)
{
 if (null == window.bGoogleMapScriptsLoaded)
 {
  if (window.google && window.google.maps)
  {
   window.bGoogleMapScriptsLoaded = true;
   BX.ready(init_);
  }
  else
  {
   
   
   BX.loadScript(
    'http://www.google.com/jsapi?rnd=' + Math.random(), 
    function () {
     if (BX.browser.IsIE())
      setTimeout("window.google.load('maps', , {callback: init_, other_params: 'sensor=false&language='})", 1000);
     else
      google.load('maps', , {callback: initAllGoogleMaps, other_params: 'sensor=false&language='});
    }
   );
   
   window.arGoogleMapCallbacks['init_'] = init_;
  }
 }
 else
 {
  init_();
 }
}

Внимание! Данные правки можно сделать без вмешательства в ядро, достаточно создать свой шаблон в папке /bitrix/templates/.default/components/bitrix/map.google.system/.default/

Логика поправки такова - грузим код подгрузки google js-api (и его карт) лишь 1 раз, сколько бы не подключался шаблон. В callback'е указываем свою js-функцию, которая призвана запустить не как ранее инициализацию одного блока карт, а инициализацию всех блоков карт на странице. Для того чтобы наша функция могла инициализировать все нужные карты создаём дополнительный js-массив arGoogleMapCallbacks в который помещаем все что ранее передавалось в callback. Вот казалось бы и все, ан нет... Следующая проблема оказывается в том в /bitrix/modules/fileman/properties.php уникальный идентификатор блока карты генерируется так:


$MAP_ID = 'map_google_'.$arProperty['CODE'].'_'.$arProperty['ID'];

Так, свойство у нас одно. Код у него один, ID один. Значит все блоки одного свойства будут иметь одинаковый MAP_ID. А так как инициализация идёт по определённому ID будет инициализирована только первая карта (хорошо что хоть какая-то). Исправить это можно "подмешав" в MAP_ID соль:


$MAP_ID = 'map_google_'.randString().'_'.$arProperty['CODE'].'_'.$arProperty['ID']; // multiple maps bugfix

Увы, эта правка является не рекомендуемой, так делается в ядре продукта (напомню, это файл /bitrix/modules/fileman/properties.php). Но другого варианта я не нашёл. Можно так же создать своё собственное свойство, скопировав весь стандартный код и внеся нужные правки, но я не стал.

Для ознакомления с кодом решения выкладываю готовые файлы. Но все же из за разницы версий рекомендую делать правки мануально.

Что ж, вот и все. Надеюсь помог. Будем ждать нативную правку от 1С-Битрикс.

1 комментарий:

  1. Сделал все как вы написали. Ничего не помогло. За исключением того, что исчезла ошибка в файрбаге, которая была связана с вызовом скрипта api. Остальные карты как были с надписью "загрузка карты" так и остались. Задолбался уже. Дебильный битрикс :(

    ОтветитьУдалить