Блок трясогузки streamfield: внедрение jQuery в админку трясогузки

Я создаю блок для потоков Wagtail, который показывает подсветку синтаксиса кода в реальном времени с использованием библиотеки Prism JS. частично работает; когда у меня выбран язык и код на существующей странице, код отображается, выделенный, как и ожидалось:

Это работает для уже заполненного кода.

Однако, когда я пытаюсь создать новую страницу трясогузки с новым блоком кода, я получаю ошибку JavaScript:

Ошибка JavaScript при запуске новой страницы с новым блоком кода.

Похоже, что библиотека загружается с задержкой, когда в ней нет контента, который можно было бы выделить. Я пробовал и $(document).ready, и $(window).load, но это другая ситуация, поскольку шаблон, содержащий библиотеку Prism, загружается динамически, когда вы нажимаете кнопку «Кодовый фрагмент». Вот расширение ошибки, которую я получаю:

VM730:2 Uncaught ReferenceError: Prism is not defined
    at prism_repaint (eval at globalEval (jquery-2.2.1.js:338), <anonymous>:2:5)
    at populate_target_code (eval at globalEval (jquery-2.2.1.js:338), <anonymous>:9:5)
    at HTMLDocument.eval (eval at globalEval (jquery-2.2.1.js:338), <anonymous>:2:29)
    at fire (jquery-2.2.1.js:3182)
    at Object.add [as done] (jquery-2.2.1.js:3241)
    at jQuery.fn.init.jQuery.fn.ready (jquery-2.2.1.js:3491)
    at eval (eval at globalEval (jquery-2.2.1.js:338), <anonymous>:1:13)
    at eval (<anonymous>)
    at Function.globalEval (jquery-2.2.1.js:338)
    at domManip (jquery-2.2.1.js:5285)

Вот код Django Wagtail, который я использую для блока Wagtail:

class CodeBlock(StructBlock):
    """
    Code Highlighting Block
    """

    WCB_LANGUAGES = get_language_choices()

    language = ChoiceBlock(choices=WCB_LANGUAGES)
    code = TextBlock()

    class Meta:
        icon = 'code'
        template = 'wagtailcodeblock/code_block.html'
        form_template = 'wagtailcodeblock/code_block_form.html'

...и код шаблона формы для администратора Трясогузки:

<script>
function prism_repaint(target_class) {
    Prism.highlightElement($(target_class)[0]);
}
function populate_target_code(label) {
    target_class = '#target-element-' + label;
    code_text = $('#' + label).val();
    $(target_class).text(code_text);
    prism_repaint(target_class);
}
</script>
{% with prism_version="1.6.0" %}
    {% block extra_css %}
    <link href="https://cdnjs.cloudflare.com/ajax/libs/prism/{{ prism_version }}/themes/prism.min.css" rel="stylesheet" />
    {% endblock extra_css %}
    {% block extra_js %}
    <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/{{ prism_version }}/prism.min.js"></script>
    {% endblock extra_js %}
    <div class="{{ classname }}">
        {% if help_text %}
            <div class="object-help help">{{ help_text }}</div>
        {% endif %}

        <ul class="fields">
            {% for child in children.values %}
                <li{% if child.block.required %} class="required"{% endif %}>
                    {% if child.block.label %}
                        <label{% if child.id_for_label %} for="{{ child.id_for_label }}"{% endif %}>{{ child.block.label }}:</label>
                    {% endif %}
                    {{ child.render_form }}
                </li>
                {% if child.block.label == "Language" %}
                    {# As we loop through, load each language dialect #}
                    {% for language_choice, language_name in child.block.field.choices %}
                        {% if language_choice|length %}
                            <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/{{ prism_version }}/components/prism-{{ language_choice }}.min.js"></script>
                        {% endif %}
                    {% endfor %}

                    <script>
                        $(document).ready(function() {
                            // Set initial language class on load
                            target_class = '#target-element-{{ child.id_for_label }}'.replace('language', 'code');
                            {% if child.id_for_label|length %}
                                $(target_class).addClass('language-' + $('#{{ child.id_for_label }}').val());
                            {% endif %}
                            // Change language being highlighted when dropdown is changed
                            $('#{{ child.id_for_label }}').bind('input propertychange', function() {
                                language_class = 'language-' + $('#{{ child.id_for_label }}').val();
                                $(target_class).removeClass().addClass(language_class);
                                prism_repaint(target_class);
                            });
                        });
                    </script>
                {% endif %}
                {% if child.block.label == "Code" %}
                    <script>
                        $(document).ready(function() {
                            populate_target_code('{{ child.id_for_label }}');
                            $('#{{ child.id_for_label }}').bind('input propertychange', function() {
                                populate_target_code('{{ child.id_for_label }}');
                            });
                        });
                    </script>
                    <li>
                        <pre><code id="target-element-{{ child.id_for_label }}"></code></pre>
                    </li>
                {% endif %}
            {% endfor %}
        </ul>
    </div>
{% endwith %}

Я убедился, что CSS и JS правильно внедряются в код, используя блоки шаблонов extra_css и extra_js. Я также пытался использовать функцию ".getScript", но безуспешно. Я ни в коем случае не являюсь экспертом по JavaScript, поэтому буду признателен за любую помощь. Весь исходный код проекта можно найти на GitHub, если это поможет:

https://github.com/FlipperPA/wagtailcodeblock

Любая помощь в отслеживании исправления будет оценена по достоинству! Спасибо за ваше время.


person FlipperPA    schedule 22.04.2017    source источник


Ответы (1)


Блоки StreamField заимствуют Django form media API для связывания файлов JS/CSS. с блоками — это рекомендуемый способ импорта библиотек JS/CSS. Ваш код станет:

from django import forms

class CodeBlock(StructBlock):
    """
    Code Highlighting Block
    """

    # ...

    @property
    def media(self):
        prism_version = "1.6.0"
        return forms.Media(
            js=["https://cdnjs.cloudflare.com/ajax/libs/prism/%s/prism.min.js" % prism_version],
            css={'all': ["https://cdnjs.cloudflare.com/ajax/libs/prism/%s/themes/prism.min.css" % prism_version]}
        )

Такое определение JS/CSS означает, что импорт будет отображаться на любой странице редактирования, которая потенциально может включать ваш блок, а не просто вставляться при добавлении вашего блока.

person gasman    schedule 22.04.2017