Максим Кузнецов

Максим Кузнецов

Был в сети 04 августа 2021, 21:51
Заказы принимаю
Приведу пример через сниппет (самый удобный вариант):

Пишем сниппет sendRedirect:
<?php
	$id = intval($id);
	if ($modx->getCount('modResource', array('id' => $id))) {
		$modx->sendRedirect($modx->makeUrl($id), array('responseCode' => 'HTTP/1.1 301 Moved Permanently'));
	}
	else {
		return;
	}

И вызываем его в чанке tpl.msOrder.success
[[!sendRedirect? &id=`айди_страницы`]]
1. Для чего вам дублировать логику работы уже встроенного сниппета Тикетсов — getComments?
Просто создаете свой сниппет, в котором заполняете требуемый набор параметров:

widget.getComments:
<?php
	$params = array();

	//Настроить по вкусу
	$params['limit'] = '4';
	$params['fastMode'] = '0';
	$params['includeContent'] = '0';
	$params['tpl'] = 'шаблон';

	return $modx->runSnippet('getComments', $params);

Далее создаете виджет типа «сниппет» и указываете в содержимом название свежесозданного сниппета (widget.getComments), после чего подключаете данный виджет к панели.

2. Вам нужно перенести ваш вопрос из раздела «компоненты MODX» в раздел «Вопросы».
Может, с такими хотелками стоит обратиться к тем разработчикам, которые «сидят и ждут»?)
Думаю, им всем не терпится Вам что-нибудь доказать…

UPD: Впрочем, если необходима помощь именно с моей стороны — присылайте тз на почту, посмотрю. Ценник — 900 рублей/час.
UPD: если у вас в тикетах присутствует возможность дозагрузки изображений при редактировании, то условие $mode=='new' не требуется, но в таком случае (да и вообще, для большей целенаправленности) стоит ограничивать работу плагина по:

Категории
$resource->get('parent')

Шаблону
$resource->get('template')

Тикетам в принципе
$resource->get('class_key') == 'Ticket'

— и тому подобное)
Если в общих чертах, то реализовать это можно следующим образом:
Пишем плагин на событие создания ресурса:
<?php
	if ($modx->event->name == 'OnDocFormSave') {
		if($mode == 'new') {  
			//...
		}
	}

Как правило, загружаемые изображения имеют следующую структуру:
/путь_до_загрузки/
~/id/
~~(список папок для миниатюр)
~~(список оригинальных изображений)

=> в вышеописанном плагине формируем путь до созданной для изображений директории:
$path = $_SERVER['DOCUMENT_ROOT'] . '/путь_до_директории_загрузки/' . $resource->get('id') . '/';
//при желании можно указать источник файлов и динамически получать его путь до директории загрузки

И далее циклом находим и удаляем все файлы на 1 уровень вглубь внутри $path.

Минус этого решения: если вы в этих же папках храните что-то еще, помимо оригинальных изображений (подгруженные вручную файлы, например), то скрипт затрет и их тоже.

Решается или дополнительной проверкой на расширение файла (удалять только картинки) или вклиниваться/перехватывать процесс загрузки изображений тикетами.
Вообще, правильнее бы для такой задачи все-таки редактировать js.

Но можно попробовать вклинить на событие загрузки/переключения страницы свой принудительный скролл до верха страницы:
$('html, body').animate({
	scrollTop: $('html').offset().top
}, 0 );
В своем сниппете примерно вот так:
$pdoParams = array();

	//если нужно получить определенный набор параметров
	$pdoPropertySet = $modx->getObject('modPropertySet', array ('name' => 'pagination'));
	$pdoParams = $pdoPropertySet->getProperties();
	
	//перечисляем набор параметров
	$pdoParams['limit'] = '8';
	$pdoParams['depth'] = '1';

	//запускаем сниппет
	$result = $modx->runSnippet('pdoPage', $pdoParams);
	
	//возвращаем результат
	return $result;

Выборка по дополнительным условиям реализуется при помощи параметра &where (в формате JSON).
Соответственно в случае с выборкой по желаемым временным промежуткам, вам необходимо в &where прописать сравнение параметра createdon с нужным диапазоном (в unix-формате).
Access-Control-Allow-Origin — если коротко, что-то в вашем сайте пытается получить ответ (динамически) от внешнего сайта, не имея на это полномочия.

Проблема может быть в стороннем скрипте (начиная от виджета погоды и заканчивая какой-нибудь уязвимостью), которая выполняется до скрипта тикетов, получает ошибку и ломает весь последующий функционал. Еще порой похожую ошибку выдают русскоязычные домены, но это вряд ли ваш случай.
По своему опыту реализации такой задачи, опишу главную особенность его интеграции: единожды инициализировав редактор на форме и, впоследствии, при попытке переместить ее, используя, допустим, кнопку «ответить», редактор будет умирать. Тоже самое с ним случается при добавлении им комментария через ajax.
Данная проблема актуальна для данного редактора и решается последовательным уничтожением в dom-e и последующей повторной инициализацией.

Соответственно — необходимо вынести процесс создания/удаления редактора, написать свою логику работы при нажатии на кнопку «ответить» (до уничтожения формы сохранять уже введенные данные и вставлять в свежесозданную форму) и отредактировать tickets/js/web/default.js, вклинив в него нужные процессы.

Для наглядности, приведу пример часть своего кода, которым решал данную задачу.

Функция создания/удаления формы:
var editor, editorText;
	
function createCommentEditor() {
	if (!editor) {
		editor = CKEDITOR.replace('comment-editor', {
			customConfig: 'comments.config.js'
		});
		CKEDITOR.instances['comment-editor'].setData(editorText);
	}
}
function removeCommentEditor() {
	if (editor) {
		editorText = editor.getData();

		editor.destroy();
		editor = null;
	}
}

Первичное создании формы и логика для кнопки «ответить»:
//первичное подключение редактора
	createCommentEditor();

	//при нажатии на кнопку "ответить"
	$('.comment-reply > a.reply').click(function(){
		//replyMe - класс, навешивающийся на кнопку "ответить" при первом нажатии
		
		//если пользователь нажал на уже активную кнопку "ответить" - возвращаем редактор на место
		if($(this).hasClass('replyMe')) {
			removeCommentEditor();
			//#formWillReturn - контейнер, где по умолчанию находится форма (в дефолтном состоянии)
			//#comment-form - айди формы редактора
			$("#comment-form").appendTo("#formWillReturn");
			createCommentEditor();
			//#returnEditor - id кнопки "вернуть редактор на место"
			$("#returnEditor").hide();
		}
		else {
			//здесь переносим редактор под комментарий, на который пользователь хочет ответить
			//кнопка "ответить" находится внутри элемента li с классом ticket-comment и атрибутом data-id=[[+id]]
			var place = $(this).parents('li.ticket-comment').data('id');
			removeCommentEditor();
			
			//у каждого элемента li.ticket-comment есть по умолчанию пустой контейнер для редактора вида <div id="comments-tree-[[+id]]"></div>
			//вставляем в него редактор
			$("#comment-form").appendTo("#comments-tree-"+place);
			
			createCommentEditor();
			
			//показываем кнопку "вернуть редактор на место"
			$("#returnEditor").show();
		}
	});
	
	//при нажатии на кнопку "вернуть редактор"
	$('#returnEditor').click(function(){
		//удаляем все выделенные кнопки "ответить"
		$('.comment-reply a').removeClass('replyMe');
		removeCommentEditor();
		$("#comment-form").appendTo("#formWillReturn");
		createCommentEditor();
		//возвращаем скрытому полю параметр родителя, к которому комментарий будет привязываться в случае успешного добавления
		$('#comment-form input[name="parent"]').val(0);
		
		//прячем кнопку "вернуть редактор"
		$("#returnEditor").hide();
	});

tickets/js/web/default.js
var Tickets = {
	...
	,ticket: {
		...
		,save: function(form, button)  {
			$(form).ajaxSubmit({
				...
				,success: function(response) {
					$(button).removeAttr('disabled');
					if (response.success) {
						//Если комментарий успешно добавлен - реинициализируем форму
						removeCommentEditor();
						Tickets.forms.comment(false);
						$('#comment-preview-placeholder').html('').hide();
						//и очищаем ее
						$('#comment-editor',form).val('');
						
						//после инициализации мы возвращаем форму на место, так что прячем кнопку "вернуть редактор", если она была
						$("#returnEditor").hide();
						$('.ticket-comment-body').removeClass('antwortComment');

						// autoPublish = 0
						if (!response.data.length && response.message) {
							Tickets.Message.info(response.message);
						}
						else {
							Tickets.comment.insert(response.data.comment);
							Tickets.utils.goto($(response.data.comment).attr('id'));
						}
						
						editorText = '';
						

						Tickets.comment.getlist();
						prettyPrint();
						createCommentEditor();
						
						...

Данное решение было выполнено довольно давно (~начало 2014), поэтому не исключаю, что в редакторе/коде тикетсов что-то поменялось, но не уверен, что это в значительной степени изменит логику работы.

Возможно, забыл добавить какой-то кусок кода — в случае чего пишите.

UPD: плюс, насколько я помню, у тикетсов была проблема с подхватыванием введенных пользователем данных в форму ckeditor, но затрудняюсь сказать точнее.
Для данной задачи сниппет if не нужен. (если серьезно, сниппет if вообще никогда не нужен, но об этом далее)

Вот как можно решить вашу задачу
встроенными фильтрами модкса:
[[*id:is=`8`:then=`вызов1`:else=`вызов2`]]

Теперь по поводу сниппета if и процесса обработки тегов модкса в целом: в отличие от чистого php, принцип работы тегов модкса такой, что вначале выполняются вложенные функции, а уже после — внешние.

Например, возьмем пример реализации одной и той же задачи при помощи php и функционала modx'a:

Php
if ($pageId == 1) { //выполняем функцию 1 }
else { //выполняем функцию 2}


Теги modx
[[*id:is=`1`:then=`сниппет 1`:else=`сниппет 2`]]

Если с примером на php логика работы понятна, то последовательность выполнения второго примера следующая:
— выполняем сниппет 1
— выполняем сниппет 2
— проверяем страницу и показываем нужный результат

Из-за такой особенности в свое время сайты на modx'e становились жутко тормозными. И заслуга сниппета if в этом деле далеко не на последнем месте…

Надеюсь, объяснил достаточно понятно)
Пишите свой фильтр, который применяете к требуемому полю с тегами. В самом сниппете выполняете замену символов "[]" на аналогичные мнемоники и возвращаете результат.

Если необходимо реализовать совсем аналогично тому, как это сделано здесь, то еще оборачиваете в
<pre>
	<code></code>
</pre>
и любым подходящим javascript-дополнением реализуете подсветку синтаксиса.
Просто создайте плагин, срабатывающий на сохранение формы (если у ms2form нет своих событий, то на OnDocFormSave с проверкой, новый ли ресурс и относится ли он к нужной категории) и пропишите в нем принудительное обновление кэша через $modx->cacheManager->refresh.