Артем

Артем

С нами с 15 октября 2017; Место в рейтинге пользователей: #167
Артем
18 июля 2020, 21:56
+2
Поля unpublished у тикетов нет, они же наследуются от обычных ресурсов.
'where' => ['published' => 0]
Артем
14 июля 2020, 02:27
+2
Hi Julien! I think you should take a look on a manual. There is a separate section about that you are looking for. Keyword is «Сообщения».
Btw, Quiz is a paid component. That means you have a one year tech support provided by author of this component. Please, sign in to your Modstore account and use Support tab to directly contact the author.
Артем
04 июля 2020, 18:39
+1
Думаю, вряд ли ты найдешь что-то готовое, поскольку задача решается в 10-20 строк кода:
— ловишь нажатие кнопки, отправляешь ajax запрос на сервер с каким-нибудь экшном типа modal/show
— на сервере проверяешь, что это ajax запрос и сравниваешь экшн, если это modal/show, то рендеришь свой чанк с модалкой через pdoTools::getChunk() или modX::getChunk(), а затем возвращаешь ответ на фронт
— на фронте достаешь из ответа html и вставляешь на страницу через append/innerHTML.
Артем
02 июля 2020, 17:58
+1
А за итоговое число лет отвечает $diff, правильно?
Не совсем, в $diff находится объект, который содержит в себе всю информацию об интервале между текущей датой и той, которая указана в from. Ты можешь распечатать его через print_f и посмотреть, что там есть. Оттуда можно достать даже точное количество дней между этими датами.
Подробнее можно почитать тут и тут.

Пытался подставить в функцию format_by_count, но не работает
вместо
return $diff->format('%Y');
пишешь
$output = $diff->format('%Y');
return format_by_count($output);
Артем
02 июля 2020, 16:53
1
+1
$from = $modx->getOption('from', $scriptProperties);
try {
    $date = new DateTime($from);
    $diff = (new DateTime())->diff($date);
    return $diff->format('%Y');
} catch (Exception $e) {
    return 'An error occurred while calculating experience: ' . $e->getMessage();
}
На вход принимает один параметр — from, где ты должен указать полную дату (02.06.1990, например), от которой нужно отсчитывать опыт.
На выходе получаешь точное количество лет опыта.
Артем
01 июля 2020, 21:21
0
Правильно выше сказали — достаточно просто динамически подсчитывать стаж на основе даты заполнения.
Т.е. у каждого преподавателя должна быть дата, от которой нужно отсчитывать стаж, а затем нужно банально вычесть эту дату из текущей, округлив до лет.

Подсчитывать такие вещи через крон на сервере — лишняя головная боль.
Артем
29 июня 2020, 17:36
+1
Напишу продолжение, как время будет.
С нетерпением ждем!

P.S. Закинул небольшую спасибку
Артем
29 июня 2020, 16:56
+2
Вот за что люблю твои заметки, так это за то, что они читаются на одном дыхании и всегда до жути интересные, даже если на уже знакомую тему. Знакомую потому, что лично я уже успел прошерстить исходники Vesp Core задолго до заметки. В общем, подача 11/10, как обычно.
Спасибо за еще одну отличную заметку!

Конечно, было бы интересно почитать про JWT авторизацию, поскольку она кажется в разы более гибкой и интересной, нежели сессии и вот это все, особенно в контексте полного разделения фронтенда от бэкенда.
Артем
20 июня 2020, 15:33
+1
Обычная ajax подгрузка данных, примерно как с пагинацией, только подгружается не список, а одна конкретная новость. URL меняется через history.pushState.
Артем
06 июня 2020, 23:32
0
тогда можно написать свой простенький скрипт, который будет итеративно проходиться по всей таблице, выискивать старые сессии по колонке access, а затем их удалять
ну и потом на крон его повесить, разумеется
Артем
06 июня 2020, 23:14
0
я же кинул ссылку с объяснением и решением проблемы, лень открыть и прочитать?
Артем
03 июня 2020, 19:58
0
'where' => ['class_key:!=' => 'CollectionContainer', 'work:IN' => [1, 2, 3, 4, 5, 6]],
ну или если включена поддержка php, то можно упростить последний массив до range(1, 6)
Артем
01 июня 2020, 15:19
+1
querySelector настолько быстрый, что нет никакого смысла юзать getElementById ради скорости. В реальных сценариях в 99.9% случаев между ними не будет никакой разницы, потому что ощутить ее можно только при десятках тысяч операций. Более того, querySelector(All) — универсальный, поэтому можно ограничиться только им для всех сценариев, что в целом сделает твой код чуточку читабельнее.
Артем
31 мая 2020, 15:08
+1
Например, вот тут они достаточно хорошо описаны.
Практически всю нужную тебе инфу можно смотреть в рамках этого сайта. Просто пишешь прямо там в поиске нужный метод или фразу, а потом смотришь результаты.
Артем
31 мая 2020, 15:04
0
Но как определить, что этот инпут именно из той формы, за которой мы хотим следить?
Опять же, через closest.
Он поднимается вверх по DOM и ищет указанного родителя.
У тебя может быть хоть 150 одинаковых форм, но измененный инпут принадлежит только одной из них.
Поэтому ты делаешь, например, вот так
if (target.closest('.formClass') !== null) {}
и узнаешь, что измененный инпут принадлежит форме с классом formClass.
Более того, ты можешь сразу сохранить эту форму в переменную и в дальнейшем работать с ней, если есть такая необходимость.
const form = target.closest('.formClass');
if (form !== null) {}
если наш листенер повешен на весь объект документ, то он будет следить за всеми элементами всех форм и единственный способ решить задачу, который я вижу, это всем input задавать определенный класс и проверять на его наличие.
Верно, он будет следить за всеми элементами всех форм, в этом и есть его плюс, который называется делегирование.
Например, если у тебя на странице появятся еще 2 формы с таким же классом, то они автоматически подхватятся и в них тоже будут отслеживаться изменения.
И нет, не нужно задавать всем инпутам определенный класс.

Твоя задача
let form = document.getElementById('formtest');
 form.addEventListener('change', function (event) {}
решается вот так
document.addEventListener('change', e => {
    const target = e.target;
    if (target.closest('#formtest') !== null) {}
});
Это будет точно так же срабатывать, если изменения происходят только в рамках конкретной формы.
Твоя форма может быть присвоена переменной, как я уже показал выше, чтобы ты мог с ней работать и собирать из нее данные через FormData, например.

К слову, getElementById('formtest') уже практически не используется в новом коде, поэтому рекомендую заменять его на querySelector('#formtest').
Артем
30 мая 2020, 22:18
+2
Хорошая практика — вешать обработчик на document, а затем разруливать его таргет через обычный if.

document.addEventListener('change', e => {
    const target = e.target;

    if (target.matches('.some-selector')) { /* code */}
    // или можно прям на наличие класса проверять
    if (target.classList.contains('имя класса без точки')) { /* code */ }
});

Если тебе нужно отслеживать изменения внутри какой-то конкретной формы, то просто проверяешь ее наличие среди родителей через closest.
if (target.closest('.form') !== null) {}

Данные из формы удобнее всего собирать через FormData, как уже выше сказали. Иногда может потребоваться дополнительная обработка всяких чекбоксов, потому что по умолчанию неотмеченные чекбоксы вообще не собираются, например.
К слову, FormData — итерируемый объект, поэтому ты можешь легко по нему пройтись через цикл и поменять то, что тебе нужно:
for (const [key, value] of formDataInstance) {
    console.log(key, value);
}

fetch лично мне не зашел, слишком много телодвижений требуется для обычных ajax-запросов. Чтобы принять json на сервере, нужно лезть в php://input и оттуда его доставать, что может быть не всегда удобно по разным причинам. Тут либо написать свой простенький асинхронный метод-обертку для запросов, который будет построен на старом XMLHttpRequest, либо посылать данные в multipart/form-data, тогда проблем не будет.
Помимо этого, fetch до сих пор не умеет отслеживать прогресс загрузки, поэтому если нужна такая фича, можно смело от него отказываться.
Артем
26 мая 2020, 16:27
+1
2 варианта:
1. Убрать оплату из заказа и вернуть json_response в конфиг, тогда exit не будет вызываться, а в ответе будет номер заказа.
2. Брать номер заказа из сессии — он добавляется туда сразу после создания заказа.
Артем
26 мая 2020, 16:05
+1
это происходит, если в конфиге установлен json_response
Артем
16 мая 2020, 23:16
0
ну так я еще вчера описал проблему и подкрепил ссылкой для ознакомления, этого мало?