Задать вопрос
  • Как правильно организовать код в плане модульности и иниции модулей?

    @ksnk
    Список виджетов нужен только в админке и только и исключительно для вывода этого списка. Дальше - клик на страницу параметров, или клик для вставки виджета (рамка/иконка) на страницу в редакторе. На странице сайта виджет сидит по своему имени и со своим списком локальных параметров. Удобно вставлять виджет на страницу в виде шорткода. Хотя тут бывают разные случаи, возможно список виджетов страницы придется кэшировать отдельно, для скорости.
    В админке логично использовать glob с поиском в спец каталоге для получения списка виджетов. В 2 шага. Выводим сначала сохраненный ранее в базе список, одновременно запускаем ресканирование списка виджетов и, если изменился, подгружаем новый список со значками обновления.
    Хранить список в базе удобно тем, что там можно отключить виджет без физического его удаления с сайта, и редактирования статей сайта, да и глобальные параметры бывает полезно хранить там же. Заодно решается проблема с поиском файлов - при рескане можно сохранять абсолютный (относительно рута сайта) адрес файла в базу.

    То есть - список нужных виджетов хранит выводимая статья (страница сайта) и только она. Если с виджетом косяк - удален или отключен - это видно в админке при редактировании страницы сайта. Сами виджеты на сайте нигде не прописываются, только сохраняется их список, автоматически перегенерируемый админкой при изменении, для быстроты и удобства.
    Написано
  • Как синхронизировать анимацию и движение объекта (персонажа)?

    @ksnk
    К примеру - есть передвижение ног, обоих. Скорость (циклическая) смены кадров анимации передвижения - 1 секунда, к примеру. За это время персонаж перемещается на расстояние (которое видно по картинке персонажа) равное двойной длине шага - расстояние от начала одной ступни, до начала другой в кадре с максимальной шириной шага. Ну а там уже можно +- подрегулировать скорости
    Написано
  • Как синхронизировать анимацию и движение объекта (персонажа)?

    @ksnk
    dom12, В смысле ? Не "дерганная" анимация - пропуск кадров, а движение ног на совпадает со скоростью перемещения самого персонажа ? Ну дык скорость анимации самого персонажа нужно увеличить. Ну или скорость уменьшить.
    Написано
  • Как синхронизировать анимацию и движение объекта (персонажа)?

    @ksnk
    Где-то во глубине своего кода я использую вот такое
    - setInterval(10) - смотря насколько будет тормозить сам компьютер
    - window.requestAnimationFrame - вызов функции реальной перерисовки канваса когда броузер этого сам желает

    _draw - реальная перерисовка канваса

    В твоем случае, возможно, нужно один раз включить permanentdraw
    { // ...
        /**
         * Инициирует непрерывную перерисовку контента. Для плавной анимации.
         */
        permanentdraw: function () {
            if (!!this._interval) return;
            this._interval = setInterval(() => anima.draw(), 10);
        },
        /**
         * останавливает анимацию
         */
        clearpermanent: function () {
            if (!this._interval) return;
            clearInterval(this._interval);
            this._interval = null;
        },
    
        /**
         * отложенный draw - заявка на перерисовку. Можно частить, все равно не должно тормозить
         */
        draw: function () {
            if (!this._TO) {
                let that = this;
                this._TO = window.requestAnimationFrame(function () {
                    that._TO = false;
                    that._draw();
                });
            }
        },
    
    
    }


    Ну а так - нет кода - не будет и решения...
    Написано
  • Как реализовать реакции для сайта?

    @ksnk
    Если будут разные сущности для реагирования - комментарии, видео, статьи, новости и т.д, то логично формировать "уникальный индекс записи" в таблице, одно поле с содержимым 'comment:4723', 'news:235',... вместо имеющихся сейчас 3-х. Как вариант - префикс идентификатора это имя обрабатывающего класса. Или "роль" этого класса в системе + идентификатор записи. Так можно обойтись одним полем для идентификации записи о реакции в таблице.
    Поля в таблице - user_id, created - время , RECORD_ID - тот самый уникальный индекс, code- текстовый код реакции. created, как правило, не выводится нигде, но полезно (наверное) иметь для статистики
    Написано
  • Как сделать кривую линию между двумя блоками диаграммы?

    @ksnk
    Сама блоксхема чем нарисована? Просто ДОМ разметка?
    Написано
  • Почему не работает javascript после ajax?

    @ksnk
    Вообще-то ...validate сам устанавливает обработчик отправки формы. Так что вручную его устанавливать не надо. Тем более бессмысленно его устанавливать, когда кнопка уже нажата.
    Просто оставить вызов $('form[action="#"]').validate(...) с прежними параметрами
    https://jqueryvalidation.org/validate/
    Написано
  • Как это повторить на html&css?

    @ksnk
    Посмотри наложенные в фигме эффекты.
    Написано
  • Как реализовать анимацию линии?

    @ksnk
    Проще канвасом, наверное. В теге img нужно хранить точку назначения - якорь в тексте справа. При наведении на это img вычислить координаты откуда и куда вести стрелку и рисовать его. элемент canvas накладывается на картинку (поиграть с z-index?) и имеет в стилях pointer-events: none;
    Так можно развесистую логику накрутить - когда показывать, когда убирать...

    Нужно только подумать, что будет в мобильном разрешении экрана, когда картинка и текст будут друг над другом.
    Написано
  • Проблема при прохождении теста node?

    @ksnk
    Из всех полученных значений найди минимальный. Вот забор такой глубины, очевидно , и будет тем, что надо. будут использованы "дорожный" участок забора и кусок забора от этого участка.
    Написано
  • Как реализовать мультивызов функции с генерацией содержимого в один контейнер?

    @ksnk
    В общем - да. Хотя register_shutdown_function сейчас, вроде как, работает достаточно корректно и всегда вызывается в разумных случаях, так что можно навесить вывод на него. Получится что-то такое. Можно было бы и дальше украшать, навесив стили и накрутив скриптовые свистелки-показывалки, но если функция занимает больше 100 строк - значить что-то идет не так :)
    <?php
    
    class debug
    {
        /**
         * Функция оставляет человекочитаемый вывод функции в html потоке
         * Работоспособна в режиме cli
         * @param mixed $msg - вывод информации
         * @param string $title - иногда удобно подписывать что тут выводится
         * @param array $options - статически сохраняемый массив параметров.
         * - root - корень проекта, минимизируем название файла, обрезая корень default: SERVER['DOCUMENT_ROOT'] или __DIR__
         * - type - [var_dump|print_r|var_export:default]
         * @return void
         */
        static function _($msg, $title = '', $options = [])
        {
            static $notafirsttime, $debug_options = [], $debug_dump = [];
            if (!empty($options)) {
                $debug_options = array_merge($debug_options, $options);
            }
            if (!empty($msg)) {
                $raw_backtrace = debug_backtrace();
    
                if (!isset($debug_options['root'])) {
                    if (isset($_SERVER) && isset($_SERVER['DOCUMENT_ROOT']) && !empty($_SERVER['DOCUMENT_ROOT'])) {
                        $debug_options['root'] = $_SERVER['DOCUMENT_ROOT'];
                    } else {
                        $debug_options['root'] = __DIR__;
                    }
                }
                $backtrace = [];
                foreach ($raw_backtrace as $bt) {
                    $line = str_replace($debug_options['root'], '~', $bt['file']) . ':' . $bt['line'];
                    if (isset($bt['class'])) {
                        $backtrace[] = $bt['class'] . '::' . $bt['function'] . ' ' . $line;
                    } elseif (isset($bt['function'])) {
                        $backtrace[] = $bt['function'] . ' ' . $line;
                    }
                }
                if (isset($debug_options['type']) && $debug_options['type'] == 'var_dump') {
                    ob_start();
                    var_dump($msg);
                    $msg = ob_get_clean();
                } elseif (isset($debug_options['type']) && $debug_options['type'] == 'print_r') {
                    $msg = print_r($msg, true);
                } else {
                    $msg = var_export($msg, true);
                }
                $debug_dump[] = [$title, implode("\n", $backtrace), $msg];
            }
            if (empty($notafirsttime)) {
                $notafirsttime = true;
                register_shutdown_function(function () use (&$debug_dump) {
                    if (!empty($debug_dump)) {
                        $headers = headers_list();
                        if (empty($headers)) {
                            $method = 'plain';
                        } else {
                            $method = 'none';
                        }
                        if (isset($_SERVER) && isset($_SERVER['HTTP_ACCEPT']) && preg_match('~text/html~', $_SERVER['HTTP_ACCEPT'])) {
                            $method = 'html';
                        }
                        foreach ($headers as $h) {
                            if (preg_match('~Content\-type\: text/html~')) $method = 'html';
                        }
                        if ($method == 'plain') {
                            foreach ($debug_dump as $dl) {
                                echo $dl[0] . ' ' . $dl[1] . ': ' . "\n" . $dl[2] . "\n";
                            }
                            // var_export($debug_dump);
                        } else {
                            $tpl = <<<'HTML'
    <style>
    div.mc__debugger {
        position:fixed; top:0;right:0;
        width:40%; height:100%;
        background: lightgray;
        overflow:auto;
    }
    div.mc__debugger.hidden {
        width:2em; height:1.5em;
        overflow: hidden;
    }
    div.control-button {
        position:fixed; top:0;right:0;
        width:2em; height:1.5em;
        background: red;
    }
    </style>
    <script>
        const $container = document.createElement(`div`);
        const $debugEntry = document.createElement(`div`);
        const $button = document.createElement(`div`);
        $container.classList.add(`mc__debugger`);
        $container.classList.add(`hidden`);
        $debugEntry.classList.add(`debug-entry`);
        $button.classList.add(`control-button`);                    
        $container.appendChild($button);
        for (let x of {{json_data}}){
            let $pre = document.createElement(`pre`);
            $pre.innerText=x;
            $debugEntry.appendChild($pre);
        }
        $container.appendChild($debugEntry);
        document.body.appendChild($container);
        $button.addEventListener("click", () => {
            $container.classList.toggle("hidden");
        });
    </script>
    HTML;
                            echo preg_replace_callback('/{{\s*([^}]+)\s*}}/', function ($m) use ($debug_dump) {
                                switch ($m[1]) {
                                    case 'json_data':
                                        return json_encode($debug_dump, JSON_UNESCAPED_UNICODE);
                                }
                                return '';
                            }, $tpl);
                        }
                    }
                    $debug_dump = [];
                });
            }
        }
    }

    ну и пример использования
    <?php
    
    include 'debug.php';
    
    // тестируем
    class testclass
    {
        function testfunc()
        {
            debug(4, 'step4');
        }
    }
    
    $x = 1;
    echo $x;
    debug($x, 'step1', ['type' => 'var_export', 'root'=>__DIR__]); // root=>$_SERVER['DOCUMENT_ROOT']
    $x++;
    echo $x;
    debug([1,2,3,[4,5,6,[7,8,9]]], 'step2');
    $t = new testclass();
    $t->testfunc();
    die();
    $x++;
    echo $x;
    debug($x, 'step3');
    Написано
  • Как реализовать мультивызов функции с генерацией содержимого в один контейнер?

    @ksnk
    Алексей Уколов, Не совсем лучше. Этот дебуг будет вызываться в случайном месте генерации html (шаблонизатор же мы не используем, правда?) Так что не факт, что мы не выведем скрипты с дивами при генерации атрибута или имени класса.
    Так что более разумно выводить код чем-то, типа ob_ функций, сохранять отладочный вывод в статике php, хотя бы в статике функции debugEntries, и вставлять отладочный вывод в нужное место при отдаче кода наружу.
    Написано
  • Как реализовать мультивызов функции с генерацией содержимого в один контейнер?

    @ksnk
    Ну, типа, debugEntry можно вызвать много раз, не правда ли? Каждый раз будет добавляться новый элемент и новый Скрипт? Надо бы статической переменной ограничить вывод debug-entry и генерировать в какой-нибудь глобальной переменной броузера нужный дамп
    Написано
  • Есть ли в PHP готовый инструмент для получения элемента массива вложенность которого хранится в другом массиве?

    @ksnk
    Евгений Николаев, приведение к массиву не работает рекурсивно вглубь, так что придется внутри цикла приводить, а это значит менять код. Почему бы сразу не написать без всяких приведений?
    Написано
  • Есть ли в PHP готовый инструмент для получения элемента массива вложенность которого хранится в другом массиве?

    @ksnk
    Все функции, которые приводятся в "рессурсе" не работают с объектом или со смесью массиво-объектов, которые забавным образом получаются из разнообразных api. Так что вот еще один велосипед, который получше (imho) того, что там.
    function val($rec, $disp = '', $default = '')
        {
            if (empty($disp) && $disp !== '0') {
                if (empty($rec)) return $default;
                return $rec;
            }
            $x = explode('|', $disp);
            $v = $rec;
            foreach ($x as $xx) {
                if (is_object($v) && property_exists($v, $xx)) {
                    $v = $v->$xx;
                } elseif (is_array($v) && array_key_exists($xx, $v)) {
                    $v = $v[$xx];
                } else {
                    $v = $default;
                    break;
                }
            }
            return $v;
        }

    В отличии от тех - умеет работать со смешанным (массив-объект) содержимым без особых проблем. Ну и выдает значение по умолчанию, которого не хватает в "тех" решениях. Примеры
    val($x, 'EMAIL|0|VALUE')
    val($founded, 'result', [])
    Мне удобно объявить это статической функцией общего класса и использовать по мере необходимости. Указание смещения строкой, а не массивом объясняется тем, что иногда такое смещение приходит из конфига, да и оформлять массивом по сравнению со строкой сложнее...
    Написано
  • Как улучшить написанный код создания глобального объекта?

    @ksnk
    Ты уж определись, тебе нужно в глобальной константе window.Tools функцию или глобальный объект с уже инициированными параметрами. Пока у тебя остается именно функция. Зато ее можно где-то там на стороне переопределить с новыми параметрами. А если выдавать объект - параметры взять, вроде как , и неоткуда...
    Слегка поубирал ненужные скобки-functions. Не это нужно ? https://jsfiddle.net/p49hjquv/
    Написано
  • Как реализовать корректную работу кнопки назад в браузере?

    @ksnk
    Подгрузил контент - history.replaceState({loaded:4},'') -- типа уже 4 страницы товаров сгрузил с сайта
    При возврате на прежнюю страницу срабатывает событие popstate и там можно попытаться понять, сколько страниц тебе надо дозагрузить с сайта
    https://developer.mozilla.org/en-US/docs/Web/API/H...
    Написано