Подменю TinyMce не придерживается панели инструментов при использовании fixed_toolbar_container и абсолютной позиции

Мы хотели бы иметь больший контроль над тем, где и как мы позиционируем панель инструментов tinymce. Мы нашли эту опцию fixed_toolbar_container, которая многое для нас решает, но приносит нам неприятную проблему. В документах говорится, что fixed_toolbar_container (http://www.tinymce.com/wiki.php/Configuration:fixed_toolbar_container) можно использовать для фиксированной панели инструментов. Но мы на самом деле хотели бы использовать его как абсолютный, чтобы мы могли позиционировать его относительно контейнера.

Я создал JS Fiddle, чтобы продемонстрировать проблему: http://jsfiddle.net/ronfmLym/2/. Когда вы открываете панель инструментов, нажимая на текст, панель инструментов позиционируется абсолютно. Когда вы откроете подменю (то есть, нажав на "файл"), откроется подменю. Теперь, когда вы начнете прокручивать, подменю не будет привязываться к панели инструментов. Это связано с тем, что эти подменю получают класс mce-fixed, поскольку мы устанавливаем свойство fixed_toolbar_container.

<div class="element">
    <div class="toolbar-container"></div>
    <div class="content">
        <p>Text</p>
    </div>
</div>

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

Мы подумали, что, возможно, сможем исправить это, изменив элемент контейнера подменю, используя приведенный ниже фрагмент кода и переписав верхнюю позицию подменю и установив абсолютный позиционер с помощью css. Но это, кажется, испортило всплывающие подсказки, и tinymce не пересчитывает свойство "left" css подменю, поэтому позиция все еще не активна.

tinymce.ui.Control.prototype.getContainerElm = function() {
    return document.getElementById('toolbar-container');
};

Единственный соответствующий вопрос, который я смог найти в stackoverflow, был следующий: TinyMCE, выпадающий вниз по подменю с использованием fixed_toolbar_container, ответов там нет.

Ответ 1

Попытался обернуть панель инструментов в div и использовать position:relative;, чтобы попытаться взломать ее вместе, но на этот раз не сотрудничал.

Похоже, что на самом деле панель инструментов учитывает свою позицию в момент нажатия. Таким образом, ваш единственный конфликт - это если открытая панель инструментов position:absolute, а затем меняется на position:fixed или наоборот.

Лучшей [ручной] ставкой будет вызов функции одновременно с изменением позиции панели инструментов, которая:

  1. Определяет, открыты ли какие-либо меню.
  2. Изменяет положение панели инструментов.
  3. Открывает открытые меню.

Ленивое (обескураженное) исправление будет заключаться в закрытии всех подменю всякий раз, когда позиция изменяется. Это исправит макет, но потребует от пользователя еще раз щелкнуть, чтобы вернуть меню.

Извините, это не ответ серебряной пули :(

Ответ 2

Этот ответ следует предложению Брайана Джона:

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

   positionTinyMceDropdowns() {
        // TODO: You'll need to replace all occurrences 
        // of this.mceWrapperElement with whatever is
        // wrapping your TinyMCE. If you have only a 
        // single instance, you can just replace it
        // with document
        const button = <HTMLElement> this.mceWrapperElement.getElementsByClassName('mce-opened').item(0);
        const items = document.getElementsByClassName('mce-floatpanel');

        let wrapperNode: HTMLElement;
        for (let i = 0; i < items.length; i++) {
            const currentItem = <HTMLElement> items.item(i);
            if (currentItem.style.display !== 'none') {
                wrapperNode = currentItem;
                break;
            }
        }

        if (!wrapperNode || !button) {
            return;
        }

        const styles = wrapperNode.style;
        styles.display = 'block';
        styles.position = 'absolute';

        const bodyRect = document.body.getBoundingClientRect();
        const buttonRect = button.getBoundingClientRect();

        // get absolute button position:
        let y   = buttonRect.top - bodyRect.top;
        y += 33; // toolbar line height;

        styles.top = '${Math.floor(y)}px';
    }

Обнаруженные мной экземпляры, в которых он должен быть вызван:

  • при прокрутке окна (или если редактор помещен в контейнер прокрутки, то всякий раз, когда он прокручивается)
  • при изменении размера окна (или если редактор помещен в контейнер, размер которого изменяется без изменения размера окна, то при каждом изменении размера контейнера)

Итак, вот пример для простейшего случая в angular (опять же, адепт того, какой js-фреймворк вы используете):

import { HostListener } from '@angular/core';

// ...

    @HostListener('window:resize', ['$event'])
    @HostListener('window:scroll', ['$event'])
    public onResize() {
        this.positionTinyMceDropdowns();
    }

Интересно, что на устройствах iOS (и, возможно, на других мобильных устройствах?) mce-floatpanel даже не был правильно расположен после того, как его открыли. Поэтому я должен был добавить это:

tinymceConfig.setup = (editor: TinyMceEditor) => {
    editor.on('init', () => {
        const panel = this.mceWrapperElement.querySelector('.mce-tinymce.mce-panel');
        if (panel) {
            panel.addEventListener('touchend', () => {
                this.positionTinyMceDropdowns();
            });
        }
    });
};