Как заменить встроенные обработчики событий (onmousedown, onmouseover, onmouseout, …), содержащие параметры для соответствия правилам CSP?

#javascript #content-security-policy #geonames

#javascript #content-security-policy #геонимы

Вопрос:

Я пытался весь день и везде искал решение. Это не было действительно успешным, и, честно говоря, после нескольких лет просмотра stackoverflow я впервые отправляю сообщение в поисках помощи. 🙂

Недавно я внедрил строгий CSP. Я раздвоил класс JSONscriptRequest Джейсона Левитта, чтобы больше защитить динамический тег (http://www.geonames.org/export/jsr_class.js ) с одноразовым номером. Я ценю это, потому что я действительно настраивал и часто использовал его (от него зависит множество модулей).

Первоначально скрипт выводил это в HTML :

 <div class="suggestions" id="pcId0" onmousedown="suggestBoxMouseDown(0)" onmouseover="suggestBoxMouseOver(0)" onmouseout="suggestBoxMouseOut(0)">...</div>
<div class="suggestions" id="pcId1" onmousedown="suggestBoxMouseDown(1)" onmouseover="suggestBoxMouseOver(1)" onmouseout="suggestBoxMouseOut(1)">...</div>(and so on, depending on the number of results.)
...
 

Все они имеют один и тот же класс (предложения). Я знаю, что могу сделать это, чтобы заменить встроенные обработчики событий, но без каких-либо параметров :

 document.getElementById("placeInput").addEventListener("input", postalCodeLookup)
 

Я попытался сделать это

 document.getElementById("placeInput").addEventListener("change", function() {

var suggestions = document.getElementsByClassName('suggestions');  

console.log(suggestions);

for (i = 0; i < suggestions.length; i  ) {
suggestions[i].addEventListener("mousedown", suggestBoxMouseDown([i]));
suggestions[i].addEventListener("mouseover", suggestBoxMouseOver([i]));
suggestions[i].addEventListener("mouseout", suggestBoxMouseOut([i]));
}

});`
 

И снова это был полный сбой.

Я не знаю, как передать переменную в мои функции так же легко, как мы могли раньше.

Соответствующие функции :

 // remove highlight on mouse out event
function suggestBoxMouseOut(obj) {
    document.getElementById('pcId'  obj).className = 'suggestions';
} 
// the user has selected a place name from the suggest box  
function suggestBoxMouseDown(obj) {
    closeSuggestBox();
    var postalcodeInput = document.getElementById("postalcodeInput");
    var placeInput = document.getElementById("placeInput");
    var latitude = document.getElementById("latitude");
    var longitude = document.getElementById("longitude");
    postalcodeInput.value = postalCodes[obj].postalCode;
    placeInput.value = postalCodes[obj].placeName   " ("   postalCodes[obj].postalCode   ", "   postalCodes[obj].countryCode   ")";
    latitude.value = postalCodes[obj].lat;
    longitude.value = postalCodes[obj].lng;  
}
// function to highlight places on mouse over event
function suggestBoxMouseOver(obj) {
    document.getElementById('pcId'  obj).className = 'suggestionMouseOver';
}
 

У кого-нибудь есть идея?

Ответ №1:

Итак, быстрые идеи по рефакторингу кода:

  1. Реализовать правила для классов .suggestions и suggestionMouseOver с .sugestions помощью и :hover селектора псевдоклассов в CSS:
      .suggestions {
         ... rules for mouse not over ...
     }
     .suggestions:hover { 
         ... rule changes for when when hovering over *.suggestions ...
     }
     

    Это должно устранить необходимость мониторинга mouseenter и mouseleave событий для .suggestion элементов класса просто для изменения стиля. (Обратите mouseover внимание, и mouseout может срабатывать при наведении курсора мыши на дочерние элементы класса hover.)

  2. Создайте data- атрибут для элементов HTML для записи номера индекса предложения. В настоящее время это реализовано как числовой суффикс значения id атрибута, который, оставаясь возможным, не является самым чистым решением:
     <div class="suggestions" data-num="0">...</div>
    <div class="suggestions" data-num="1">...</div> <!-- and so on -->
     
  3. Хотя обработка событий может быть делегирована путем предоставления одного события для общего родительского элемента и просмотра target атрибута запущенных событий, прямой подход все равно может заключаться в том, чтобы оставаться с прослушивателем событий для каждого div элемента:
     function sugestionMouseDown( event) {
        let suggestionDiv = event.currentTarget;
        let suggestionNumber = suggestionDiv.dataset.num;
        // process parameters suggestionDiv and suggestionNumber
        // ...
    }
    Array.from( document.getElementsByClassName('suggestions') )
    .forEach( div => div.addEventListener("mousedown", suggestionMouseDown));
     

Комментарии:

1. Большое спасибо @traktor53. Следуя вашим советам, все работает нормально!

Ответ №2:

Благодаря хорошим советам @traktor53, это то, что я придумал.

Примечание для будущих исследователей stackoverflow: цель состоит в том, чтобы заменить встроенные обработчики событий javascript, содержащие аргумент (например: onmouseout(0) , …). Причина заключается в соблюдении политики безопасности контента (CSP), которая по понятным причинам не разрешает встроенный скрипт. Я применяю приведенный ниже код к пользовательскому jsr_class.js получение результатов по API GeoNames.

HTML

Он динамически генерируется следующим образом :

 <div class="suggestions" id="pcId0" data-num="0"> Vannes - (56000) amp;nbsp;FR</div>
<div class="suggestions" id="pcId1" data-num="1"> Vannes - (56001 CEDEX) amp;nbsp;FR</div>
<div class="suggestions" id="pcId2" data-num="2"> Vannes - (56002 CEDEX) amp;nbsp;FR</div>
<div class="suggestions" id="pcId3" data-num="3"> Vannes - (56003 CEDEX) amp;nbsp;FR</div>
 

CSS

Цель здесь — заменить старые функции onmouseover и onmouseout

 .suggestions { 
    font-size: 14;
    background-color: #fff; 
    border-radius: 5px; 
}

.suggestions:hover { 
    font-size: 14;
    background: #456ae7; 
    color: white; 
    cursor: pointer; 
    border-radius: 5px;
}
 

Javascript

Я не хотел изменять свою исходную функцию по практическим соображениям, я знаю, что можно использовать более чистые методы.

 function triggerMouseDown( event) {
let suggestionDiv = event.currentTarget;
let suggestionNumber = suggestionDiv.dataset.num;

suggestBoxMouseDown(suggestionNumber);
}

document.getElementById("placeInput").addEventListener("change", function() {

Array.from( document.getElementsByClassName('suggestions') )
.forEach( div => div.addEventListener("click", triggerMouseDown));
});