Привет, ребята,
Это, возможно, довольно простой вопрос, я больше бэкенд-разработчик. Сейчас я пытаюсь подключить JavaScript-код к элементу фронтенда. Проблема в том, что мой window.onload (и document.onload, я пробовал оба варианта) никогда не срабатывает. Мой JavaScript находится в папке инициализации плагина ([plugin]/assets/javascripts/initializers/[plugin].js.es6):
export default {
name: "meritmoot",
initialize() {
// моя функция инициализации
function initializeMeritmoot(api) {
console.log("inside initializeMeritmoot")
// функция на событие keyup
function repInputKeyUp() {
inputBox = document.getElementById("rep-input")
console.log("in rep input key up")
ajax("/reps/search/" + inputBox.value +".json", {type: 'GET'}).then((result) => {
console.log(result)
result = JSON.parse(result)
repList = document.getElementById("rep-list")
repList.innerHTML = ""
result.forEach(op => {
var x = document.createElement("INPUT");
x.setAttribute("info-tag-id", op.id)
x.setAttribute("value", op.mm_reference_str)
repList.appendChild(x)
});
console.log(repList)
});
};
console.log("Past Function Def");
// загрузка окна (не происходит)
window.onload = () => {
console.log("PageLoaded") <-----------------------------------это никогда не выводится
document.getElementById('rep-input').onkeyup = repInputKeyUp;
};
console.log('leaving initializeMeritmoot');
}
console.log("MeritMoot Javascript In Default")
withPluginApi("0.8.37", api => initializeMeritmoot(api));
}
};
Есть ли у кого-то идеи, почему это может происходить? Правильно ли настроен этот JavaScript в контексте Discourse? Или это более общая проблема JavaScript?
Редактирование: пытаюсь добавить addEventListener…
Редактирование: заменил onload на:
window.addEventListener('onload', function() {
console.log("PageLoaded")
document.getElementById('rep-input').onkeyup = repInputKeyUp;
}, false);
это тоже не сработало
Вы работаете с EmberJS, а не с чистым JavaScript. Поведение будет отличаться.
Лучше следовать лучшим практикам EmberJS.
Я бы рассмотрел возможность встроить вашу логику в существующий компонент или добавить его в слот плагина, используя хук didInsertElement.
Прочитайте руководство EmberJS
Спасибо! Я видел, что Ember играет важную роль в Discourse, но не понимал, что он заменяет стандартный функционал. Я выделю время и изучу его.
edit: Я использую плагин element discovery-list-container-top и подключаюсь к архитектуре плагинов на Ruby.
edit: Какая связь между ember-rails и Discourse? Сам по себе Ember кажется полноценной средой разработки. Посмотрите на GitHub - emberjs/ember-rails: Ember for Rails 3.1+ · GitHub
ember-rails — это Ruby-гем, который фактически используется в Discourse.
Сотрудники Discourse могут дать более точные комментарии, но в целом EmberJS отвечает за фронтенд, а Ruby on Rails — за бэкенд. Конечно, в архитектуре Discourse есть уникальные элементы, и точная конфигурация, как и в любом крупном приложении, в той или иной степени индивидуальна.
Хорошее описание того, как всё устроено, можно найти здесь: Creating Routes in Discourse and Showing Data
Документация по API доступна здесь: https://docs.discourse.org
За последнее время я многому научился в Ember.js, но, похоже, использовал неправильную версию. Насколько я могу судить, Discourse использует Ember.js 1.9 (судя по документации ember-rails и синтаксису исходного кода). Текущая версия Ember.js — 3.17. Поэтому руководствоваться следует этим руководством. Синтаксис довольно отличается, но я разобрался с основами. Когда закончу, опубликую приведенный выше код, переделанный под Ember.js.
Запуск dev-инстанса в браузере показывает следующее в консоли JavaScript:
DEBUG: -------------------------------
DEBUG: Ember : 3.12.2
DEBUG: jQuery : 3.4.1
DEBUG: -------------------------------
Но вы правы, некоторые соглашения Discourse не отражают самый последний синтаксис в руководствах 
Спасибо за помощь, Роберт! Немного времени я чувствовал себя не в своей тарелке. В любом случае, вот что у меня в итоге получилось, как и обещал. Я решил использовать функцию onload, которая срабатывает после загрузки DOM. Сначала я пробовал использовать jQuery, но потом узнал, что Ember.js отказывается от него.
import { ajax } from 'discourse/lib/ajax';
// Можно было бы обновить подсветку, чтобы она работала и при split(" "). Если, конечно, захочется.
export default Ember.Component.extend({
runOnceRan: false,
myAws: "",
subbedReps: [],
// Обновляем предлагаемые варианты для представителей в поле ввода
updatePossibles: function (substr) {
var compContext = this; // контекст компонента
if (substr == "") {
return;
}
// Получаем подсказки
substr = encodeURIComponent(substr);
ajax(`meritmoot/reps/search/${substr}.json`, { type: "GET" }).then( result => {
result = result.api;
let pv = []; // возможные значения
for(let i = 0; i < result.length; i++) {
let newItem = {
label: result[i].mm_reference_str,
value: result[i].id,
id: result[i].id,
}
pv.push(newItem);
}
console.log(pv)
compContext.myAws.list = pv;
// Обновляем внутреннюю логику Awesomplete
compContext.myAws.evaluate();
// Показываем подсказки Awesomplete
compContext.myAws.open();
});
},
runOnce: function () {
// Сообщаем, что функция выполнилась...
console.log("in runOnce")
const substrInput = document.getElementById("rep-input");
const compContext = this;
// Создаём кастомный Awesomplete (список опций) для substrInput (rep-input).
this.myAws = new Awesomplete(substrInput);
console.log(substrInput)
// Все элементы списка должны отображаться, так как фильтрация по значению substr уже не применяется
this.myAws.filter = function (text, input) {
return true
}
// Показывать всегда, включить автодополнение.
this.myAws.minChars = 0;
this.myAws.autocomplete = "on";
// Обработка выбора опции.
document.addEventListener('awesomplete-selectcomplete', function(e) {
if(e.srcElement == substrInput) {
let id = e.text.value;
substrInput.value = "";
// Отправляем выбор на бэкенд
let uriid = encodeURIComponent(id)
ajax(`meritmoot/reps/${uriid}`, {type: "PUT" }).then( result => {
console.log("put passed back:");
console.log(result);
});
// Обновляем выбор на фронтенде
let l = compContext.get("subbedReps");
l.pushObject(id) // нужен pushObject вместо push (https://github.com/emberjs/ember.js/issues/10405)
compContext.set("subbedReps", l);
// 1. DONE создать таблицу, сопоставляющую ID пользователя с подписанными представителями.
// 2. DONE создать способ добавления подписанных представителей в эту таблицу. в процессе (нужны GET, PUT, DELETE)
// 3. отображать представителей рядом с substrInput
// 3. создать способ отображения голосов рядом с темами.
// 4. после всего этого обновить механизм отображения голосов здесь.
}
}, false);
// Получаем сохранённых пользователем представителей и отображаем их.
ajax(`meritmoot/reps`, {type: "GET"}).then( result => {
console.log("get passed back:");
console.log(result);
compContext.set("subbedReps", result.mmfollows);
console.log("subbedReps")
console.log(compContext.get("subbedReps"));
});
// При вводе обновляем подсказки
document.addEventListener('input', function(e) {
if(e.explicitOriginalTarget == substrInput) {
compContext.updatePossibles(substrInput.value);
}
}, false)
console.log(this.myAws);
},
didRender() {
this._super(...arguments);
if( ! this.runOnceRan ) {
this.runOnce();
this.set("runOnceRan", true);
}
}
});