Получение событий для кастомизации интерфейса Битрикс 24
Эта статья, посвящена перехвату подписывания и инициализации событий через библиотеку BX
.
BX.onCustomEvent
Выброс события производится через BX.onCustomEvent
и происходит в любом случае, вне зависимости от того, есть ли слушатели события или нет. Для нас — разработчиков — это является информацией о том, в каком месте существуют точки входа, на которые при необходимости можно было бы подписаться и реагировать.
Код для выполнения в консоли:
let originalBxOnCustomEvent = BX.onCustomEvent;
// глобальный объект, в который будет собираться статистика
hardcoreBXOnEventFrontLog = {
events: {},
};
BX.onCustomEvent = function (objOrEvent, eventIHope, eventParams, secureParams) {
if (!objOrEvent) {
objOrEvent = null;
}
if (!eventIHope) {
eventIHope = null;
}
if (!eventParams) {
eventParams = null;
}
if (!secureParams) {
secureParams = null;
}
let info = {};
let realEvent, realObj;
if (typeof objOrEvent === 'string') {
realEvent = objOrEvent;
} else if (typeof eventIHope === 'string') {
realEvent = eventIHope;
}
if (typeof objOrEvent === 'object') {
realObj = objOrEvent;
} else if (typeof eventIHope === 'object') {
realObj = eventIHope;
} else if (typeof eventParams === 'object') {
realObj = eventParams;
}
let err = new Error();
info.trace = err.stack;
info.event = realEvent;
info.obj = realObj;
info.params = eventParams;
info.arguments = arguments;
// live! =)
hardcoreBXFrontPrintOnEvent(info, true);
// регистрируем в глобальном объекте
let eventNameList = realEvent.split(' ');
eventNameList.forEach(function (evt) {
if (!hardcoreBXOnEventFrontLog.events[evt]) {
hardcoreBXOnEventFrontLog.events[evt] = [];
}
hardcoreBXOnEventFrontLog.events[evt].push(info);
});
// пинаем оригинальный метод
return originalBxOnCustomEvent.call(this, objOrEvent, eventIHope, eventParams, secureParams);
};
// метод для поиска среди собранной статистики информации по названию события
hardcoreBXOnEventLookingByEvent = function (event) {
for (let e in hardcoreBXOnEventFrontLog.events) {
if (
!hardcoreBXOnEventFrontLog.events.hasOwnProperty(e)
|| e !== event
) {
continue;
}
for (let ins = 0; ins < hardcoreBXOnEventFrontLog.events[e].length; ins++) {
hardcoreBXFrontPrintOnEvent(hardcoreBXOnEventFrontLog.events[e][ins]);
}
}
};
// вывод в консоль
hardcoreBXFrontPrintOnEvent = function (info, live) {
let localInfo = Object.assign({}, info);
console.log(
'BX.on%c%s',
'background: #fa8544; color: #fff; ' +
'font-weight: bold; padding: 3px 9px;' +
'border-radius: 30px 0 0 30px;' +
'border-left: 7px solid #1d1b57',
localInfo.event
);
if (localInfo.obj) {
console.log(localInfo.obj);
}
console.groupCollapsed('trace');
if (live) {
console.trace();
delete (localInfo.trace);
} else {
console.log(localInfo.trace);
}
console.groupEnd();
console.groupCollapsed('info');
for (let i in localInfo) {
if (localInfo.hasOwnProperty(i)) {
console.log(i + ':%o', localInfo[i]);
}
}
console.groupEnd();
};
Статистика
В консоли будет накапливаться информация о каждом событии, которое было проинициализировано через BX.onCustomEvent
, с трейсингом вызова, что позволит нам понять, откуда именно это было запущено:
Также вся информация будет накапливаться в глобальный объект hardcoreBXOnEventFrontLog
, отсортированная по событиям. К сожалению, полноценный трейсинг в переменную не запомнить, но часть цепочки сохраняется, через объект Error
. Это хотя бы частично позволяет сориентироваться в том, откуда пришёл сигнал.
Собранную на текущий момент статистику по событиям получаем через функцию hardcoreBXOnEventLookingByEvent("название_события")
.
Упрощенный вариант
Код для выполнения в консоли:
let originalBxOnCustomEvent = BX.onCustomEvent;
BX.onCustomEvent = function (eventObject, eventName, eventParams, secureParams)
{
let realEventName = BX.type.isString(eventName) ?
eventName : BX.type.isString(eventObject) ? eventObject : null;
if (realEventName) {
console.log(
'%c' + realEventName,
'background: #222; color: #bada55; font-weight: bold; padding: 3px 4px;'
);
}
console.dir({
eventObject: eventObject,
eventParams: eventParams,
secureParams: secureParams
});
originalBxOnCustomEvent.apply(
null, arguments
);
};
После чего будут логироваться все события которые вызываются например при клике на кнопку!
Далее вешаем обработчики через:
BX.addCustomEvent()
BX.addCustomEvent
По аналогии с тем, как устроена работа с событиями в jQuery
, методы BX-библиотеки являются функциями-аккумуляторами. Подписывание на событие фактически явлется регистрацией символьного кода и колбэк-функции в глобальном объекте, а выброс события — выполнение колбэк-функции.
Регистрация события производится через функцию
BX.addCustomEvent
Как правило регистрацию события сопровождают:
- Событие в виде произвольного символьного кода
click
,load
,on-location-search-focus
- Колбэк-функция, которая должна быть вызвана при наступлении события
Как и в случае с jQuery
, переопределяем исходный метод и переопределяем его своим.
Переопределение метода
Предлагается сделать следующее:
- Ставим в девтулзах глобальный брекпоинт на событие
document.onDOMContentLoaded
, перезагружаем страницу - На первом срабатывании брекпоинта убеждаемся, что объект
BX
уже доступен и переопределяем ему методaddCustomEvent
- Снимаем брекпоинт и отпускаем выполнение скрипта
Код для выполнения в консоли:
let originalBxAddCustomEvent = BX.addCustomEvent;
// глобальный объект, в который будет собираться статистика
hardcoreBXFrontLog = {
events: {},
};
/**
* eventOrObj - example: BX.addCustomEvent(opener, 'onOpenerMenuClose', ...)
*/
BX.addCustomEvent = function (eventOrObj, handlerOrEvent, arParams, handlerContextObject) {
let info = {};
let realEvent, realCallback, someObj;
if (typeof eventOrObj === 'string') {
realEvent = eventOrObj;
} else if (typeof handlerOrEvent === 'string') {
realEvent = handlerOrEvent;
}
if (eventOrObj instanceof Function) {
realCallback = eventOrObj;
} else if (handlerOrEvent instanceof Function) {
realCallback = handlerOrEvent;
} else if (arParams instanceof Function) {
realCallback = arParams;
}
if (typeof eventOrObj === 'object') {
someObj = eventOrObj;
} else if (typeof handlerOrEvent === 'object') {
someObj = handlerOrEvent;
} else if (typeof arParams === 'object') {
someObj = arParams;
}
let err = new Error();
info.trace = err.stack;
info.event = realEvent;
info.callback = realCallback;
info.obj = someObj;
info.arguments = arguments;
// live! =)
hardcoreBXFrontPrintResult(info, true);
// регистрируем в глобальном объекте
let eventNameList = realEvent.split(' ');
eventNameList.forEach(function (evt) {
if (!hardcoreBXFrontLog.events[evt]) {
hardcoreBXFrontLog.events[evt] = [];
}
hardcoreBXFrontLog.events[evt].push(info);
});
// пинаем оригинальный метод
if (!arParams) {
arParams = [];
}
if (!handlerContextObject) {
handlerContextObject = false;
}
return originalBxAddCustomEvent.call(this, eventOrObj, handlerOrEvent, arParams, handlerContextObject);
};
// метод для поиска среди собранной статистики информации по названию события
hardcoreBXAddEventLookingByEvent = function (event) {
for (let e in hardcoreBXFrontLog.events) {
if (
!hardcoreBXFrontLog.events.hasOwnProperty(e)
|| e !== event
) {
continue;
}
for (let ins = 0; ins < hardcoreBXFrontLog.events[e].length; ins++) {
hardcoreBXFrontPrintResult(hardcoreBXFrontLog.events[e][ins]);
}
}
};
// вывод в консоль
hardcoreBXFrontPrintResult = function (info, live) {
let localInfo = Object.assign({}, info);
console.log(
'BX.add%c%s',
'background: #1d1b57; color: #fff; ' +
'font-weight: bold; padding: 3px 9px;' +
'border-radius: 0 30px 30px 0;' +
'border-right: 7px solid #fa8544',
info.event
);
if (localInfo.obj) {
console.log(localInfo.obj);
}
console.groupCollapsed('trace');
if (live) {
console.trace();
delete (localInfo.trace);
} else {
console.log(localInfo.trace);
}
console.groupEnd();
console.groupCollapsed('info');
for (let i in localInfo) {
if (localInfo.hasOwnProperty(i)) {
console.log(i + ':%o', localInfo[i]);
}
}
console.groupEnd();
};
Статистика
В консоли будет накапливаться информация о каждом событии, которое было проинициализировано через BX.addCustomEvent
, с трейсингом вызова, что позволит нам понять, откуда именно это было запущено:
Также вся информация будет накапливаться в глобальный объект hardcoreBXFrontLog
, отсортированная по событиям. К сожалению, полноценный трейсинг в переменную не запомнить, но часть цепочки сохраняется, через объект Error
. Это хотя бы частично позволяет сориентироваться в том, откуда пришёл сигнал.
Собранную на текущий момент статистику по событиям получаем через функцию
hardcoreBXAddEventLookingByEvent("название_события")
.