0.00
84 читателя, 77 топиков

[EVO] Виртуальные сниппеты и чанки для комфортной работы в IDE

Способ о котором я поведу речь не для всех. А только для тех
  • Кого не устраивает текущая работа плагина FileSource
  • Кто хочет подключить свой проект к системе контроля версий, но не может это сделать полноценно из-за того, что чанки хранятся в базе
  • Кому надоело подключение чанков в стиле:
    [[include? &file=`assets/template/head.html`]]

Читать дальше →

Добавляем кнопку "ВЫБРАТЬ" в KCFinder для работы на тачскринах

Чтобы хоть как-то можно из КСФайндера поместить картинку на планшетах – слегка можно поправить скрипт KCFinder. И появится кнопка вставки картинки

1. В файле manager/media/browser/mcpuk/js/browser/files.js:
после строки 90 (перед закрывающим /div) вставляем
'<div class="selectThis">' + "Выбрать" + '</div>' +

2. после строки 36 вставляем
$('.selectThis').click(function() {
    _.unselect();
    browser.returnFile($(this).parent('.file'));
});

3. В файле стиля (в любом месте) manager/media/browser/mcpuk/themes/oxygen/style.css
.selectThis {
	padding: 6px 0;
	border-radius: 2px;
	background: #EEE;
	color: #4EA94E;
	cursor: pointer;
	text-transform: uppercase;
}
.selectThis:hover {
	background-color: #fff;
}


evoBabel - мультиязычные сайты на MODx EVO - теперь это легко и просто

Как обычно бывает — встала задача, неразрешимая средствами YAMS и очень неудобно рарзешимая другими средствами — создать мультиязычный сайт, чтобы
  • заказчик мог сам добавлять языки
  • переводы не были разбросаны по шаблонам, а содержались в одном месте
  • чтобы переключалка языков отправляла на нужный ресурс на другом языке
  • чтобы нормально без бубна работали сниппеты вроде

Читать дальше →

[EVO] EVO Альтернатива любой галереи

Не раз натыкался на сообщения о том, какую галерею поставить. Не хочу быть навязчивым, но я отказался от всех видов галерей в пользу multiTV
github.com/Jako/multiTV#readme
Почему?
1. Один инструмент на все случаи жизни, единые источники
2. Можно создать любой тип галереи
3. Размещается на целевой странице
Как пример, вот –
www.expotec.ru/vyistavochnyie-stendyi/eksklyuzivnyie-stendyi

Зачем это?

Я использую multiTV вместо галерей не потому, что они “плохие” а потому, что:
  1. Огромные галереи с пагинацией встречаются нечасто (тут уместна Евогалерея).
  2. Чаще нужны компактные минигалереи или слайдеры.
  3. Хранить и управлять галерей файлов мне (и заказчикам) удобнее на целевой странице.
  4. Возможность гибко настраивать чанк юнита галереи дает полную свободу в настройках.
  5. В любой момент галерею можно перенастроить под другую задачу.

Туториал по созданию галереи на multiTV. Полный текст можно прочитать здесь

[EVO] Социальный замок на контент

Заплати лайком уже известно что такое на примерах под Рево и еще каких то, но уже не очень хороших цмсках 8-). Суть, в кратце состоит в том, что продать тяжело что- то не очень оцениваемое в денежных знаках, а вот за ссылку почему бы и не поделиться аля «секретом» если юзер нажмет Like или что-то из это же серии социальных кнопок и сылка попадет к юзеру на стену.

социальный замок

До сих пор на модэкс эво такого не было по-моему и переделать тут написано как было.
Поэтому без особых сложностей было сделано:

-параметры настроек сниппета выводящего кнопки и обрабатывающего call-back'и от соц.сетей перенесены из modPropertySet просто в переменные с которыми снип дергался в нужном месте. т.е. из [[SocialLocker? &options=`ИМЯНАБОРАПАРАМЕТРОВ` &tpl=`lockshare` &unlockUrl=`103` &like=`fb,vk,twit,subscribe`]] убрано &options=`ИМЯНАБОРАПАРАМЕТРОВ`

— плейсхолдеры переписаны в стиле эво, например с [[+twitlike]] на [+twitlike+]

-в эво я не нашел как сделать чтоб страница выводила ответ типом json и из за этого сервисная страница в этом случае выдавала текст, что потребовало часть скрипта поменять…

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

Итак в нужном месте для кнопок,
[[SocialLocker? 
&optionsTpl=`response` 
&tpl=`lockshare` 
&unlockUrl=`192` 
&like=`fb,twit,subscribe,vk,plus1` 
&id=`[*id*]` 
&desc=`[*pagetitle*]` 

]]


где [*id*] и [*pagetitle*] это то что попадать на соц сеть будет.
Затем, unlockUrl это айди страницы где отзыв с соц.сетей обрабатывается снипетом с вызовом
[[!SocialLocker? &mode=`response`]]

Далее, SocialLocker, сам снипет:
pastie.org/8434715
в нем 4 параметра хардкодом: $subscribeGroup='5289142';
$ttwitUser='modxdeveloper'; $vkApiid='3922874' их поменяйте на свои айдишки :-)
а вот 4-й, rightSide это чанк в котором будет хранится ваша секретная инфа, которой будет делиться локер если успешно ссылочка запостилась.

Ну и напоследок, сам темплейт локера и темплейты кнопок:
lockshare
pastie.org/8434718

в нем тут 2 жс файлика:
lockershare.js
pastie.org/8434724

и unlock.js
pastie.org/8434725

fb это чанк fblike и остальные по этому же принципу названы: имя кнопки + like
<div class="sl_facebook_like"> 
<div class="fb-like" data-href="[+SharePage+]" data-send="false" data-width="90" data-show-faces="false" data-layout="button_count"></div>
</div>
<script>
function facebook_init() {
        if ('undefined' === typeof(FB)) {
                setTimeout(facebook_init, 500);
        } else {  
                FB.Event.subscribe('edge.create', function(response) { sl_unlock('facebook', 'like'); });
        } 
}
</script>

twit
<div class="sl_twitter_tweet">
        <a href="http://twitter.com/share" class="twitter-share-button" data-url="[+SharePage+]" data-counturl="[+SharePage+]" data-text="[+SharePageDesc+]" data-count="none" data-related="[+ttwit.user+]" data-lang="ru">tweet</a>
</div>
<script>
function twitter_init() {
        if (0 == $j('.sl_twitter_tweet iframe').length) {
                twttr.widgets.load();
                twitter_timeout_id = setTimeout(twitter_init, 4000); 
        } 
}
</script>

subscribe
<div id="sl_vkontakte_subscribe" class="sl_vkontakte_subscribe"></div>

vk
<div id="sl_vkontakte_like" class="sl_vkontakte_like"></div>
<script>
function vkontakte_init() { 
        if ('undefined' == typeof(VK) || 'undefined' === typeof(VK.init)) { 
                setTimeout('vkontakte_init', 500); 
        } else { 
                if (null == VK._apiId) {
                        VK.init({apiId: [+vk.apiid+], onlyWidgets: true}); 
                }                                         
                VK.Widgets.Like("sl_vkontakte_like", {type: 'button', height: 20, pageUrl: '[+SharePage+]', verb: 1});
                VK.Observer.subscribe('widgets.like.liked', function() {  sl_unlock('vkontakte', 'like'); });
                VK.Widgets.Subscribe("sl_vkontakte_subscribe", {mode: 2, soft: 0}, [+subscribe.group+]);
                VK.Observer.subscribe('widgets.subscribed', function() {  sl_unlock('vkontakte', 'subscribe'); });                                               
        } 
}
</script>


plus1
<script type="text/javascript" src="http://apis.google.com/js/plusone.js">
{"lang": "ru"}
</script>
<div class="sl_google_plus1"><g:plusone callback="sl_unlock" size="medium" href="[+SharePage+]"></g:plusone></div>


вот так, может и пригодится. *постараюсь отвечать на вопросы или коменты на баги.

Изменение дерева документов в админке с большим количеством дочерних документов (очередной хак)

В сборке Дмитрия 1.0.12-d6, есть отличная реализация вывода списка дочерних документов не в дереве. Но есть одна заковырка, это нужно зайти в каждый раздел и убрать галочку, а бывает что в разделе есть как и папки так и простые документы.

Подумал и решил немного доработать этот алгоритм, чтобы ничего не нужно было делать.
Так же переделал событие по нажатию на название пункта меню (ранее было редактирование или обзор, что по умолчанию установлено).
Стало:
1. По нажатию на пункт, при условии если это «папка» содержащая папки и документы, меню раскрывается и открывается обзор ресурса
2. Если это «папка» с документами не являющимися папками, то открывается обзор ресурса.
3. Если это «папка» с вложенными папками, только открывается меню.

Всё тестировал на MODx 1.0.12 (заменил файлы на сборке 1.0.12-d6 — полёт нормальный, но не тестировал)

Установка: заменить файлы из архива, очистить кеш браузера.
GitHub

UPD: решена проблема с выбором родительской категории. После обновления добавить в Настройках на вкладке Интерфейс и представление, Режим щелчка мышью на ресурсе — Обзор ресурса

Чуть-чуть подправляем редактирование документа через ManagerManager

Вставляю этот код на всех сайтах в чанк «mm_rules», может кому пригодится:
global $mm_fields, $modx;
$e = &$modx->Event;
	
if ($e->name=='OnDocFormRender') {
	$e->output(includeCSS($modx->config['base_url'] .'assets/js/select2/select2.css'));
	$e->output(includeJs($modx->config['base_url'] .'assets/js/select2/select2.min.js'));
	
	$e->output('
		$j(".tab-page table").attr("width", "100%");
		$j("#content_header").before($j("#tv_body"));
		$j("#tv_body").before($j("#tv_header"));
		$j("span.warning").parent("td").css({"width":"190px"});
		$j("#tv_body span.warning").parent("td").css({"width":"170px"});
		$j("input.inputBox").css({"width":"600px"});
		$j("input[name^=tv]").css({"width":"600px"});
		$j(".tab-page textarea").css({"width":"600px"});
		$j(".tab-page textarea#ta").css({"width":"100%"});
		$j("input[name=menuindex].inputBox").css({"width":"50px", "text-align":"right", "margin-right":"10px"});
		$j("input.imageField").css({"width":"525px"});
		$j("input.DatePicker").css({"width":"150px"});
		$j("textarea[name=introtext]").css({"height":"150px"});

		$j("#content_header.sectionHeader").append("<div id=\"editor_choice\" style=\"float:right;font-weight:normal\"> </div>");
		$j("#editor_choice").append($j("#which_editor").prev("span.warning")).append(" ").append($j("#which_editor"));
		
		{ // этот кусок, если вы использыете плагин content_history
			if ($historycount) {
				$historycount = $historycount.match(/\|\s+(\d+)\s+\]/i);
				if ($historycount) $historycount = $historycount[1]; else $historycount = 0;
			} else $historycount = -1;
			'.mm_createTab("История изменений документа <span id=history-count></span>", "history").'
			$j("#table-history").hide();
			$j("#tab-intro-history").after($j("#section-ch"));
			$j("span.ch_toggle_entries").parent().hide();
			$j("#ch-body").show();
			if ($historycount!=-1) $j("#history-count").html("("+$historycount+")");
			$j(".ch_view_limit").parent().before($j(".ch_record").parent());
		}
	');
	
	// select2 - http://ivaynberg.github.io/select2/
	$e->output('$j(".sectionBody select").select2({minimumResultsForSearch:20,width:"element"});');
	if (is_array($mm_fields) && count($mm_fields)>0) {
		foreach (array_keys($mm_fields) as $field) {
			if ($mm_fields[$field]['fieldtype']=='select' && $mm_fields[$field]['tv']) {
				$e->output('$j("'.$mm_fields[$field]['fieldtype'].'[name=\''.$mm_fields[$field]['fieldname'].'\']").select2({minimumResultsForSearch:5,width:"608px"});'."\n");
			}
		}
	}
}



Читать дальше →

[EVO] BR вместо P в TinyMCE

Возможно это обсуждалось у нас, но я не нашел. Решил поделиться.
Иногда нужно чтобы в TinyMCE при нажатии enter у нас появлялось
<br />
а не
<p>&nbsp;</p>


Да, br можно поставить нажав shift+enter, но в самом начале кода редактора мне это не удалось сделать. Обязательно br заменялось на
<p>&nbsp;</p>


Для этого идем assets/plugins/tinymce/js/
Открываем файл mce_init.js.inc

находим строку 18
force_p_newlines                 : [+force_p_newlines+],

Закомментируем ее (или удаляем)

вместо нее добавляем три новых строки

force_br_newlines: true,
force_p_newlines: false,
forced_root_block: '',

Не забываем почистить кэш браузера!
Был рад кому-нибудь помочь.

ShopKeeper, сохраняем сессию с товарам в базе. Чтобы корзина не отчищалась.

Итак, для чего это нужно?
Много работаю с ШК, и много приходится допиливать всяких мелочей.
Представляю на Ваш суд плагин для сохранения сессии с товарами в БД, чтобы можно было продолжить наполнять корзину на следующий день, или когда захочется.
У меня заказчики оптовики, и там набирают по много позиций. Возможно для кого-то это тоже будет актуально.

Работает только для авторизованных пользователей сайта!

Для начала идем в PhpMyAdmin и создаем новое поле в таблице modx_web_users (у вас префикс может быть другой в базе).
Имя поля sksession, тип LONGTEXT (так как данных у меня например здесь бывает очень много).

Далее нам необходимо создать событие в ШК для плагина. Сам автор ШК рекомендует это делать.

Открываем class.shopkeeper.php и находим примерно строку 277, там должно быть
$_SESSION['addit_params'] = $addit_paramsStr;

и после этого добавляем
$evtOut = $this->modx->invokeEvent('OnSHKaddItem');


Теперь нам необходимо добавить в БД сайт это событие, выполняем следующий запрос в базу
INSERT INTO `modx_system_eventnames` VALUES (NULL, 'OnSHKaddItem', '6', 'Shopkeeper');
(повторюсь, что префикс у вас может быть другой, и надо будет исправить его на ваш.)
Далее создаем плагин SkSaveSession и ставим ему события OnSHKaddItem, OnSHKbeforeSendOrder, OnWebLogin
код плагина
$e = &$modx->Event;
$id = $modx->getLoginUserId();

if (($e->name == 'OnSHKaddItem')) {
$ses = $_SESSION['purchases'];
$addit = $_SESSION['addit_params'];
$res = $ses."|||".$addit;  
$modx->db->query( "UPDATE modx_web_users SET sksession='".$res."'  WHERE id='".$id."'");

}

if (($e->name == 'OnSHKbeforeSendOrder')) {
  $ses = '';
  $modx->db->query( "UPDATE modx_web_users SET sksession='".$ses."' WHERE id='".$id."'");

}

if (($e->name == 'OnWebLogin')) {

$query = $modx->db->query( "SELECT sksession FROM modx_web_users WHERE id='".$id."'");
$data = mysql_fetch_array($query);


if ($data['sksession']!='') 
{
  $res = explode("|||", $data['sksession']);
  $_SESSION['purchases']=$res[0];
  $_SESSION['addit_params']=$res[1];
}

}


Вот как бы и все. При каждом добавлении товара в корзину сессия пишется в базу. При отправке заказа база подчищается. При авторизации пользователя сессия принимает значение поля из базы.

П.С. Сильно не пинать, ибо в кодерстве не силен я :)

UPD 26.08.2013 исправил пару ошибок.