Программирование

’рубрика’

Удобный сервис онлайн-парсинга JSON

Октябрь 21, 2012

Очень интересовал JSON декодер в онлайне по функционалу равный функции PHP json_decode. Оказалось сервис существует:

Нравится, что у парсера есть разные режимы работы. Режим "JS eval" позволяет видеть русские символы в структуре JSON.

Сохранил ссылку также к себе в блог на страницу ссылок.

Tags: , ,
Записано в PHP, Программирование    |    Постоянная ссылка

Зацикливаем галерею на Lightbox 2

Август 26, 2012

Встала задача зациклить галерею на Lightbox 2. Задача откладывалась, поэтому над собственным решением не думаю. Выдалась минутка, нашел решение:

Когда же время дошло до практики, данный метод сразу откинул.

Алгоритм зацикливания элементарный:

  • когда галерея доходит до краев – перематываем ее;
  • всегда отображаем кнопки прокрутки, если более 1-го изображения.
Открываем на редактирование файл lightbox.js. Находим следующий код:
$lightbox.find('.lb-prev').on('click', function(e) {
  _this.changeImage(_this.currentImageIndex - 1);
  return false;
});
$lightbox.find('.lb-next').on('click', function(e) {
  _this.changeImage(_this.currentImageIndex + 1);
  return false;
});

Заменяем его на:

$lightbox.find('.lb-prev').on('click', function(e) {
	// cay
	if(_this.currentImageIndex == 0)
		_this.changeImage(_this.album.length - 1);
	else
		_this.changeImage(_this.currentImageIndex - 1);
	return false;
});
$lightbox.find('.lb-next').on('click', function(e) {
	// cay
	if (_this.currentImageIndex == _this.album.length - 1)
		_this.changeImage(0);
	else
		_this.changeImage(_this.currentImageIndex + 1);
	return false;
});

Эта замена позволит по достижении пользователем краев галереи двигаться далее.

В завершение находим следующий код:

Lightbox.prototype.updateNav = function() {
  var $lightbox;
  $lightbox = $('#lightbox');
  $lightbox.find('.lb-nav').show();
  if (this.currentImageIndex > 0) $lightbox.find('.lb-prev').show();
  if (this.currentImageIndex < this.album.length - 1) {
    $lightbox.find('.lb-next').show();
  }
};

Заменяем его:

Lightbox.prototype.updateNav = function() {
	var $lightbox;
	$lightbox = $('#lightbox');
	// cay -block-
	if ( this.album.length > 1 )
	{
		$lightbox.find('.lb-nav').show();
		$lightbox.find('.lb-prev').show();
		$lightbox.find('.lb-next').show();
	}
	//~ if (this.currentImageIndex > 0) $lightbox.find('.lb-prev').show();
	//~ if (this.currentImageIndex < this.album.length - 1) {
	//~ $lightbox.find('.lb-next').show();
	//~ }
	// cay -block- #
};

Эта модификация позволит отображать кнопки навигации только если в галерее более 1-го изображения.

Tags: ,
Записано в JavaScript, Программирование    |    Постоянная ссылка

Если array.length в JavaScript возвращает undefined

Август 26, 2012

Уже не в 1-й раз в своей практике программирования в стиле PHP + JavaScript сталкиваюсь с проблемой, что когда посредством AJAX PHP возвращает массив в формате JSON, узнать его длину в JavaScript невозможно. Речь идет об неассоциативном массиве. Например:

<?php
$array = array( 1, 2, 3 ); // неассоциативный массив
?>

Данный массив без заданных ключей (индексов). Доступ к элементу получается через порядковый номер $array[ 0 ].

Интересный факт заключается в том, что если пересортировать массив, а точнее собрать на основе 1-го – 2-й и сделать замену, то функция JavaScript "length" работать не будет. Выглядит это примерно так:

<?php
$array_1 = array( 1, 2 );
$array_2 = array();

$array_2[ 1 ] = $array_1[ 0 ];
$array_2[ 0 ] = $array_1[ 1 ];

$array_1 = $array_2;
?>

После возвращения массива $array_1 функция JavaScript "length" вернет "undefined".

Для избежания проблемы, сначала массив нужно пересортировать, а затем составить новый:

<?php
asort( $array_1 );

foreach ( $array_1 as $value ) {
	$array_2[] = $value;
}

$array_1 = $array_2;

Итог

Все сводится к тому, что элементы в массиве должны идти от 0 элемента без разрыва и числовые ключи не должны задаваться явно.

Записано в JavaScript, Программирование    |    Постоянная ссылка

Что делать, если json_decode возвращает пустую строку

Июль 19, 2012

Недавно столкнулся с проблемой. Решил продолжить разработку вне работы, дома, чтобы успеть сдать проект в срок. Однако, скопированный проект не стал работать на локальном сервере. Причина заключалась в том, что определенная команда вместе с параметрами отправляется на сервер с помощью POST запроса из JavaScript jQuery. Параметры передаются в отдельной переменной в формате JSON:

config.params = '{"products":"454,103,505","category":"7"}';

На стороне сервера происходит прием параметров:

$params = $_POST[ 'params' ];

Для использования параметров их нужно перекодировать:

$params = json_decode( $params );

На данном этапе и возникла проблема. После обработки переменной $params с помощью json_decode() она становилась пустой.

В процессе отладки я обратил внимание, что к отправляемой строке с параметрами в формате JSON к кавычкам добавлены обратные слэши.

Оказалось, что на локальном сервере параметр magic_quotes_gpc установлен в true, поэтому функция json_decode() не могла обработать строку.

Решение проблемы:

public function decode_params( & $params ) {
	if ( ! empty( $params ) ) {
		if ( get_magic_quotes_gpc() ) {
			$params = stripslashes( $params );
		}
		$params = json_decode( $params );
	}
}

Tags: ,
Записано в JavaScript, Программирование    |    Постоянная ссылка

Вывод списка записей через класс JModelList в Закрытой части сайта в Joomla 1.7

Июнь 6, 2012

Буду разбираться как в Закрытой части сайта вывести список записей из базы данных посредством класса JModelList с тем отличием от Открытой части сайта, что будут доступны элементы редактирования записей, такие как выделение, публикация и другие по желанию.

За основу беру компонент com_simple Открытой части сайта.

Файл simple.php

<?php
defined( '_JEXEC' ) or die;

jimport('joomla.application.component.controller');

$controller = JController::getInstance('Simple');
$controller->execute(JRequest::getCmd('task'));
$controller->redirect();

Подключаем класс SimpleController.

Файл контроллера controller.php

<?php
defined( '_JEXEC' ) or die;

jimport('joomla.application.component.controller');

class SimpleController extends JController
{
}

Функционал без изменений наследуется из класса JController.

Файл модели users.php

<?php
defined( '_JEXEC' ) or die;

jimport('joomla.application.component.modellist');

class SimpleModelUsers extends JModelList
{
	public function getListQuery()
	{
		$query = parent::getListQuery();

		$query->select('*');
		$query->from('#__users');

		return $query;
	}

	public function getItems()
	{
		$items = parent::getItems();

		foreach ($items as &$item) {
			$item->url = 'index.php?option=com_simple&amp;task=user.edit&amp;id=' . $item->id;
		}

		return $items;
	}
}

Принцип работы модели компонента

Вновь идет задействование класса JModelList, как это было при получении и выводе списка записей в компоненте Открытой части сайта:

Сначала через метод getListQuery() класса JModelList формируется запрос, который в последствии вызывается через метод getItems(), который в свою очередь обращается к методу _getListQuery().

Таким образом, в переменную $items помещается список объектов, которые возвращает метод _getList() класса JModel.

Главная особенность и отличие метода getItems() класса SimpleModelUsers Закрытой части сайта заключается в цикле, в котором составляются ссылки на редактирование для каждой записи:

foreach ($items as &$item) {
	$item->url = 'index.php?option=com_simple&amp;task=user.edit&amp;id=' . $item->id;
}

Интересно также, что массив $items перебирается по ссылке и дополняет сам себя новой записью url.

Как видно, задача task в ссылке указывается как user.edit. Это означает, что через класс контроллера SimpleControllerUser будет обращение к методу edit().

Файл шаблона компонента default.php

<?php defined( '_JEXEC' ) or die; ?>
<form action="index.php?option=com_simple&amp;view=users" method="post" name="adminForm" id="adminForm">
	<table class="adminlist">
		<thead>
			<tr>
				<th width="10">
					<input type="checkbox" name="checkall-toggle" value="" onclick="checkAll(this)" />
				</th>
				<th><?php echo JText::_('COM_SIMPLE_USER_NAME_LABEL'); ?></th>
				<th><?php echo JText::_('COM_SIMPLE_USER_BLOCK_LABEL'); ?></th>
			</tr>
		</thead>
		<tbody>
			<?php foreach ($this->items as $i => $item) : ?>
				<tr class="row<?php echo $i % 2 ?>">
					<td class="center">
						<?php echo JHtml::_('grid.id', $i, $item->id); ?>
					</td>
					<td>
						<a href="<?php echo $item->url; ?>"><?php echo $this->escape($item->name); ?></a>
					</td>
					<td class="center">
						<?php echo JHtml::_('jgrid.published', $item->block, $i, 'users.', true, 'cb'); ?>
					</td>
				</tr>
			<?php endforeach; ?>
		</tbody>
	</table>
</form>

В данной форме в 1-ю очередь следует обратить внимание на следующие параметры:

  1. action="index.php?option=com_simple&amp;view=users"
  2. name="adminForm"

Оба параметра обязательны. 1-й образуется от текущего вида, 2-й постоянный.

Поле для ввода checkall-toggle при нажатии вызывает функцию JavaScript checkAll(), которая является частью CMS Joomla 1.7. Однако, в таком виде, в каком находится сейчас компонент, данная функция не будет работать.

Для работы функции необходимо обязательное подключение Панели с кнопками в верхней части экрана через класс JToolBarHelper из вида компонента.

Классы строк чередуются как row0 и row1, цвет их ячеек будет отличаться. Стили заданы в стандартном CSS Закрытой части Joomla 1.7:
/administrator/templates/bluestork/css/template.css 

table.adminlist tbody tr.row1 td {
	background: #f0f0f0;
	border-top: 1px solid #FFF;
}

Но это все мелочи, по сравнению с возможностями, которые предоставляет Joomla для отображения данных. Речь идет про эту строчку:

<?php echo JHtml::_('grid.id', $i, $item->id); ?>

и эту:

<?php echo JHtml::_('jgrid.published', $item->block, $i, 'users.', true, 'cb'); ?>

Вызывается статический метод _() класса JHtml. Данный метод подгружает дополнительный класс и его метод. В обоих случаях идет обращение к классу JHtmlJGrid.

Параметры, которые передаются в метод _() обрабатываются внутри метода следующим образом:

list($key, $prefix, $file, $func) = self::extract($key);

Строка с точкой ".", которая передается в метод _() обрабатывается следующим образом:

$prefix = (count($parts) == 3 ? array_shift($parts) : 'JHtml');
$file	= (count($parts) == 2 ? array_shift($parts) : '');
$func	= array_shift($parts);

prefix – имя префикса подгружаемого файла.

file – имя подгружаемого файла.

По-другому, в метод extract() передается строка вида (prefix).(class).function, где prefix и class передавать необязательно. Если они не будут переданы, то будет вызван метод класса JHtml.

При строке jgrid.published, подключается класс JHtmlJGrid и вызывается метод published().

Таким образом, следующий код в файле шаблона вида users Закрытой части сайта default.php:

<?php echo JHtml::_('jgrid.published', $item->block, $i, 'users.', true, 'cb'); ?>

превращается в:

<a class="jgrid" href="javascript:void(0);" onclick="return listItemTask('cb0','users.publish')" title="Publish Item">
	<span class="state unpublish">
		<span class="text">Unpublished</span>
	</span>
</a>

Как видно, при нажатии на ссылку сработает функция JavaScript listItemTask().

Следующий код:

<?php echo JHtml::_('grid.id', $i, $item->id); ?>

превращается в:

<input type="checkbox" id="cb0" name="cid[]" value="42" onclick="isChecked(this.checked);" title="Checkbox for row 1" />

В следующих записях я по возможности рассмотрю доступные методы класса JHtml и его подклассов.

Tags: , , , , , , , , , , , , , ,
Записано в Joomla, Программирование    |    Постоянная ссылка

Определение нахождения на Главной странице в Joomla 2.5

Июнь 5, 2012

Задача тривиальная. Решение беру из официальной документации по Joomla:

Думаю, что лучший способ, который подойдет для любого сайта следующий:

<?php
$app = JFactory::getApplication();
$menu = $app->getMenu();
$lang = JFactory::getLanguage();
if ( $menu->getActive() == $menu->getDefault( $lang->getTag() ) ) {
	echo 'Главная страница';
}
else {
	echo 'Второстепенная';
}
?>

Решение работает, начиная с версии 1.6.

Tags: , , ,
Записано в Joomla, Программирование    |    Постоянная ссылка

Лечим SyntaxHighlighter Evolved от удаления новой строки при смене редактора в WordPress 3.3.2

Июнь 5, 2012

Вчера, после того, как я добавил кнопку сохранения на панель Альтернативного Полноэкранного редактора TinyMCE, я отметил, что после сохранения в тегах <pre></pre>, которые по сути даже не должны форматироваться, удаляются новые строки и многострочный код выводится в последствии в одну строку.

Проблема, как я выяснил, заключается в плагине SyntaxHighlighter Evolved, а именно в замене им стандартной функции WordPress pre_wpautop на pre_wpautop2. Происходит это в следующем файле:

/wp-content/plugins/syntaxhighlighter/syntaxhighlighter_mce.js

В самом конце файла находится:

switchEditors._pre_wpautop = switchEditors.pre_wpautop;
switchEditors._wpautop = switchEditors.wpautop;
switchEditors.pre_wpautop = pre_wpautop2;
switchEditors.wpautop = wpautop2;

Нас интересует 1-я и 3-я строки, в которых происходит замена функции. Однако, взглянем на нее, она находится в том же файле:

var syntaxHLlast = 0;
function pre_wpautop2(content) {
	var d = new Date(), time = d.getTime();

	if ( time - syntaxHLlast < 500 )
		return content;

	syntaxHLlast = time;

	content = content.replace(new RegExp('<pre>\\s*\\[(' + syntaxHLcodes + ')', 'gi'), '[$1');
	content = content.replace(new RegExp('\\[\\/(' + syntaxHLcodes + ')\\]\\s*<\\/pre>', 'gi'), '[/$1]');

	content = this._pre_wpautop(content);

	content = content.replace(new RegExp('\\[(' + syntaxHLcodes + ')[^\\]]*\\][\\s\\S]+?\\[\\/\\1\\]', 'gi'),
	function(a) {
		return a.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&').replace(/<%%KEEPWHITESPACE%%>/g, '');
	});

	return content;
}

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

Для того, чтобы решить проблему неверного форматирования кода в тегах <pre></pre> достаточно заменить переопределение. Возвращаемся к 4-м строкам, показанным ранее и заменяем их на:

// cay 1 switchEditors._pre_wpautop = switchEditors.pre_wpautop;
switchEditors._wpautop = switchEditors.wpautop;
// cay 2 switchEditors.pre_wpautop = pre_wpautop2;
switchEditors.wpautop = wpautop2;

Теперь при работе и сохранении в Альтернативном Полноэкранном режиме редактора TinyMCE, форматирование кода сохраняется.

Примечание

В своих поисках я пришел к изучению следующего файла:

/wp-includes/js/tinymce/plugins/wordpress/editor_plugin.js

При сохранении в Полноэкранном режиме срабатывает следующий код:

ed.onSaveContent.add(function(ed, o) {
	if ( ed.getParam('wpautop', true) && typeof(switchEditors) == 'object' ) {z
		if ( ed.isHidden() )
			o.content = o.element.value;
		else
			o.content = switchEditors.pre_wpautop(o.content);
	}
});

Несмотря на мои попытки внести изменения в эту функцию, код все равно форматировался неверно.

При сохранении, чтобы было понятно, исполняется данная строчка:

o.content = switchEditors.pre_wpautop(o.content);

Удивительно то, что если округлить эту строку в с помощью функции alert(), чтобы посмотреть на содержание переменной o.content до и после ее вызова, то видно, как неправильно форматируется текст. Однако, сам код в последствии имеет верное форматирование. Это скорее всего связано с тем, что добавляется задержка перед сохранением файла. Видимо TinyMCE не успевает проверить и изменить код до начала сохранения.

Tags: , , , , , , , , ,
Записано в WordPress, Программирование    |    Постоянная ссылка

Автосохранение без перезагрузки в Альтернативном Полноэкранном режиме редактора TinyMCE в WordPress 3.3.2

Июнь 4, 2012

После того, как я добавил Альтернативный Полноэкранный режим редактора TinyMCE и стал использовать его вместо Стандартного WordPress, единственное, чего мне не хватало, это отображение того, что Черновик текущей записи сохраняется и самой кнопки Сохранения.

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

Что же касается Альтернативного Полноэкранного режима TinyMCE, то я проверял, что автосохранение при написании записи успешно запускается, но понять это визуально никак нельзя.

О чем запись

Я расскажу, как добавить кнопку сохранения к Альтернативному Полноэкранному режиму TinyMCE, сделаю, чтобы эта кнопка затемнялась при автосохранении и добавлю в нижней части индикатор со временем последнего сохранения Черновика. Сохранение также будет доступно при использовании сочетания горячих клавиш Ctrl+S без перезагрузки страницы.

Подключаем дополнительный плагин TinyMCE

К данной задаче меня подтолкнула другая необходимость, которая возникла ранее: хотел добавить на панель с кнопками редактора TinyMCE кнопку вставки в запись текущего времени. В поисках наткнулся на эту страницу:

С нее все и началось. Сверху я увидел ссылку на стандартные плагины TinyMCE и понял, что их довольно много и что к редактору WordPress подключена лишь часть:

Стал смотреть все по очереди и случайно увидел плагин "Save":

Скачать все плагины можно со следующей страницы:

После загрузки "Full Package" распаковываем архив и перемещаемся в следующую папку:

/tinymce/jscripts/tiny_mce/plugins

После этого копируем папку "save" на хостинг в папку:

/wp-includes/js/tinymce/plugins

О том, как изменить настройки редактора TinyMCE, заданные по умолчанию я писал в записи про добавление списка с классами на панель Визуального редактора.

По аналогии, переходим в Закрытой части блога во "Внешний вид", затем выбираем "Редактор" и файл functions.php. Вставляем следующий код:

function my_mce_before_init( $init ) {
	$init['theme_advanced_buttons3'] .= ',save';
	$init['plugins'] .= ',save';
	return $init;
}
add_filter('tiny_mce_before_init', 'my_mce_before_init');

Графическая кнопка "Сохранение" появится в 3-й сверху строчке Визуального редактора. Для того, чтобы она была в 1-й достаточно поменять порядковый номер в "theme_advanced_buttons3" на "theme_advanced_buttons1", думаю это понятно.

Теперь, если открыть Визуальный редактор, то на панели будет видна кнопка Сохранения, которая также будет отображаться в Альтернативном Полноэкранном режиме.

После нажатия на кнопку запись обновляется и страница перезагружается.

В описании к плагину "save" по ссылке выше видно, что в плагине можно задавать дополнительные параметры. К примеру, можно сделать, чтобы кнопка Сохранения была неактивна до тех пор, пока в запись не будут внесены изменения. За это отвечает параметр "save_enablewhendirty".

Для добавления в настройки TinyMCE нового параметра перед вызовом tinyMCE.init(), дополняем код, который добавили в functions.php:

function my_mce_before_init( $init ) {
	$init['theme_advanced_buttons3'] .= ',save';
	$init['plugins'] .= ',save';
	$init['save_enablewhendirty'] = true;
	return $init;
}
add_filter('tiny_mce_before_init', 'my_mce_before_init');

В 4-й строке в массив был добавлен желаемый параметр и значение установлено в "true". При первоначальном открытии записи на редактирование кнопка Сохранения будет неактивна.

Отключаем горячие клавиши в плагине save

В дополнительном плагине "save" для TinyMCE задаются горячие клавиши для сохранения записи "Ctrl+S". К сожалению, они переопределяют горячие клавиши редактора, заданные в WordPress и вместо автосохранения без перезагрузки страницы, вызывается обновление записи с перезагрузкой.

Для решения этой проблемы идем в папку:

/wp-includes/js/tinymce/plugins/save

И открываем на редактирование файл "editor_plugin.js". Находим следующий текст:

a.addShortcut("ctrl+s",a.getLang("save.save_desc"),"mceSave")

и заменяем его на:

/* cay 1 a.addShortcut("ctrl+s",a.getLang("save.save_desc"),"mceSave")*/

Таким образом, путем комментирования мы удаляем переопределение горячих клавиш. Страница теперь перезагружаться не будет.

Выводим сообщение о последнем сохранении

В нижней части Альтернативного Полноэкранного режима редактора TinyMCE есть "Путь". Я решил в этот путь справа добавить выводимое в обычном редакторе сообщение "Черновик сохраняется..." и "Черновик сохранён в ...".

Из папки:

/wp-includes/js

открываем файл autosave.js. Находим следующий текст:

function autosave_loading(){

и заменяем его (дополняем) на:

function autosave_loading(){if(!jQuery('#save-message').length){jQuery('#mce_fullscreen_tbl .mceStatusbar').append('<div id="save-message"></div>');}

Как видно я просто добавил новый элемент div с id равным save-message с помощью JQuery, если его ранее не существовало.

Теперь добавим запись в созданный элемент сообщения о результате сохранения Черновика. В том же файле находим следующий текст:

jQuery(".autosave-message").html(autosaveL10n.savingText)

и заменяем его на:

jQuery(".autosave-message, #save-message").html(autosaveL10n.savingText)

Видно, что я просто добавил новый элемент #save-message к выборке JQuery.

Далее находим:

if(e){jQuery(".autosave-message").html(e)}else{if(autosaveOldMessage&&d){jQuery(".autosave-message").html(autosaveOldMessage)}

и заменяем на:

if(e){jQuery(".autosave-message, #save-message").html(e)}else{if(autosaveOldMessage&&d){jQuery(".autosave-message, #save-message").html(autosaveOldMessage)}

Сохраняем файл autosave.js и загружаем его обратно на сервер. Теперь при автосохранении в Альтернативной версии Полноэкранного режима в самом низу появится желаемое – вывод сообщения "Сохранение черновика..." и "Черновик сохранен в ...".

Единственное, чего не хватает, так это выравнивания по правому краю и отступа. Идем в Закрытой части сайта во "Внешний вид", затем выбираем "Редактор" и файл functions.php. Добавляем альтернативные стили CSS для администратора с помощью следующего кода:

function fullscreen_editor_styles() {
	global $user_level;
	// только для администратора
	if ($user_level > 9) {
		echo '<style type="text/css">
#save-message {
	float: right;
	margin-right: 8px;
}
</style>';
	}
}
add_action('admin_head', 'fullscreen_editor_styles');

Сохраняем файл и смотрим редактор в Полноэкранном режиме. Теперь сообщение о статусе сохранения Черновика отображается как надо.

Затемнение кнопки сохранения

Осталась последняя нереализованная задача – для наглядности затемнять кнопку "Сохранение" на панели Визуального редактора при автосохранении и выводить из затемнения после завершения автосохранения.

Возвращаемся к редактированию файла autosave.js. Находим следующий текст:

function autosave_enable_buttons(){setTimeout(function(){jQuery(":button, :submit","#submitpost").removeAttr("disabled");jQuery(".ajax-loading").css("visibility","hidden")},500)}function autosave_disable_buttons(){jQuery(":button, :submit","#submitpost").prop("disabled",true);setTimeout(autosave_enable_buttons,5000)}

и заменяем его на следующий:

function autosave_enable_buttons(){setTimeout(function(){jQuery(":button, :submit","#submitpost").removeAttr("disabled");jQuery(".ajax-loading").css("visibility","hidden");jQuery("#content_save, #mce_fullscreen_save").removeClass("mceButtonDisabled").addClass("mceButtonEnabled");},500)}function autosave_disable_buttons(){jQuery("#content_save, #mce_fullscreen_save").removeClass("mceButtonEnabled").addClass("mceButtonDisabled");jQuery(":button, :submit","#submitpost").prop("disabled",true);setTimeout(autosave_enable_buttons,5000)}

Я сделал вставки кода, содержащие "#content_save, #mce_fullscreen_save". С помощью JQuery для кнопки сохранения в Обычном режиме и для кнопки сохранения в Полноэкранном режиме в зависимости от ситуации либо добавляю класс mceButtonEnabled и удаляю mceButtonDisabled, либо наоборот. После сохранения файла все кнопка должна затемняться. Можно попробовать с помощью горячих клавиш "Ctrl+S".

Для справки

Пока я копался в исходных кодах, не могу не отметить, что за переход в Полноэкранный режим редактора отвечает файл editor_plugin.js в следующей папке:

/wp-includes/js/tinymce/plugins/wordpress

При нажатии на кнопку перехода в Полноэкранный срабатывает код после следующей строчки:

if ( 'mceFullScreen' == cmd ) {

Также не могу не отметить, что в папке:

/wp-includes/js/tinymce/plugins

есть две интересные подпапки:

  • fullscreen
  • wpfullscreen

которые отвечают видимо за Полноэкранный режим. Странно, что я пока еще не вносил в них ни одного изменения.

Думаю, это может пригодиться.

Примечание

Изменения, которые вносится в данной статье с новым обновлением WordPress (текущая версия 3.3.2) нужно будет проходить заново. Поэтому если после обновления что-то не работает, об этом нужно помнить в первую очередь.

Ошибки сохранения

В ходе написания данной записи я решил нажать на саму кнопку "Сохранить", чтобы вызовет перезагрузку страницы естественно. Все успешно сохранилось, но за исключением форматирования исходного кода, который я добавил в запись в тегах <pre></pre>. Слетел переход на новую строчку.

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

Возвращаюсь в папку:

/wp-includes/js/tinymce/plugins/save

и редактирую файл editor_plugin.js. Находим следующий код:

if(a.onsubmit==null||a.onsubmit()!=false){a.submit()}c.nodeChanged()}

и заменяем его на:

if(a.onsubmit==null||a.onsubmit()!=false){/* cay 2 a.submit() */}c.nodeChanged()}

Теперь кнопка при нажатии не сработает и будет служить исключительно, как индикатор автосохранения.

Tags: , , , , , , , , , ,
Записано в WordPress, Программирование    |    Постоянная ссылка

Добавляем список с CSS классами на панель Визуального редактора в WordPress 3.3.2

Июнь 3, 2012

Понадобился функционал в редакторе TinyMCE для добавления заданного класса к текущему параграфу. Нужной кнопки на панели Визуального редактора не оказалось, поэтому начал искать решение.

Задача состоит в том, чтобы после выделения параграфа был доступен список с классами, из которого я бы выбрал необходимый. Главное не переключаться в HTML режим. Например, текущий текст:

<p>Текст параграфа.</p>

после выбора класса "stars" становится следующим:

<p class="stars">Текст параграфа.</p>

Думаю, что идея и ранее была понятна.

Мне помогла следующая статья:

Для добавления списка с классами требуется открыть в Закрытой части блога "Внешний вид", затем "Редактор" и файл functions.php.

Решением задачи становится добавление следующего кода в файл:

function my_mce_before_init( $init ) {
	$init['theme_advanced_buttons2'] .= ',styleselect';
	$init['theme_advanced_styles'] = 'Stars=stars';
	return $init;
}
add_filter('tiny_mce_before_init', 'my_mce_before_init');

Можно добавить сразу несколько классов, разделив их с помощью ";". Это список в конце концов. Для меня это было не нужно.

Автор указанной выше статьи предлагал использовать следующую строчку вместо моей 2-й:

$init['theme_advanced_buttons2_add'] = 'styleselect';

Хотя метод и рабочий, но мой вариант мне более нравится.

Также есть еще одно решение в официальной документации по WordPress:

Код выглядит так:

// Add the Style selectbox to the second row of MCE buttons
function my_mce_buttons_2($buttons)
{
	array_unshift($buttons, 'styleselect');
	return $buttons;
}
add_filter('mce_buttons_2', 'my_mce_buttons_2');

function my_mce_before_init($init_array)
{
	// add classes using a ; separated values
	$init_array['theme_advanced_styles'] = "First Class=first-class;Other class=other-class";
	return $init_array;
}
add_filter('tiny_mce_before_init', 'my_mce_before_init');

Получается, что 2 раза вызывается функция add_filter(). Возможно это сделано для демонстрации возможностей. Я предпочту опять же свой вариант.

Tags: , , , , , , ,
Записано в WordPress, Программирование    |    Постоянная ссылка

Применение preg_replace и preg_replace_callback в программировании на PHP

Июнь 2, 2012

Решил вчера написать плагин для своего блога на WordPress. Он заключается в замене содержимого, которое в коде выделено тегом <var>.

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

Сначала я решил, что функция должна вернуть строку, в которой будут заменены все символы на звездочки "*". Рассмотрим следующий код:

preg_replace('/<var>(.*?)<\/var>/', '*', $content);

Содержимое переменной $content:

Строка для замены с секретным кодом <var>836-72</var> и секретной строкой <var>"секрет 2"</var>.

После обработки содержимого переменной $content все найденные совпадения будут заменены на один символ "*", а мне нужно, чтобы звезд было столько же, сколько символов между тегами <var></var>:

Строка для замены с секретным кодом * и секретной строкой *.

Я сразу догадался, что нужно воспользоваться функцией str_repeat() совместно с strlen() с использованием 2-го вхождения $1. Код получился следующий:

preg_replace('/<var>(.*?)<\/var>/', str_repeat("*", strlen("$1")), $content);

Естественно ничего не стало работать и тогда я стал искать решение в Интернете. Приведу одну из страниц, которая мне помогла:

Теперь я понял, что 2-й аргумент функции preg_replace() необходимо брать в кавычки:

preg_replace('/<var>(.*?)<\/var>/e', 'str_repeat("*", strlen("$1"))', $content);

Данный код работает. Но если 1-й момент с кавычками понятен, то почему используется в маске символ "e" после косой черты – нет.

Оказывается добавление данного символа позволяет исполнить код PHP, который содержится в строке. Это та же функция eval().

В процессе изучения вопроса я нашел в официальной документации PHP дополнительную информацию по регулярным  выражениям:

Отлично, символы прекрасно заменяются:

Строка для замены с секретным кодом ****** и секретной строкой ****************.

Но мне этого стало мало. Я захотел, чтобы теперь не все символы заменялись, а только цифры и буквы. Я понял, что нужно использовать функцию preg_replace() в preg_replace().

Сначала у меня ничего не работало (видимо путался в двойных и одинарных кавычках) и тогда я наткнулся на функцию preg_replace_callback(). Данная функция вторым аргументом может принять create_function(). Таким образом, мне просто было легче прописать еще один вызов preg_replace().

В итоге, код стал следующий:

preg_replace_callback('/<var>(.*?)<\/var>/', create_function('$matches', '$matches[1] = preg_replace("/[\w]/", "*", $matches[1]); return "<span class=\"stars\">" . $matches[1] . "</span>";'), $content);

2-й выглядит довольно просто:

preg_replace("/[\w*?]/", "*", $matches[1]);

Несмотря на видимую правильность кода, он не работает с русскими символами. Простая задача превратилась в большую для меня сложность. Текст стал следующим:

Строка для замены с секретным кодом ***-** и секретной строкой "секрет *".

Русские буквы попросту не заменились.

Стал искать ответ в Интернете. Очень помог данный ресурс:

Особенно помогли комментарии под записью. Оказалось, что можно вместо "\w", который в UTF-8 не распознает русские символы воспользоваться "\p{L}".

Но и с "\p{L}" проблема – на локальном компьютере у меня все заработало, в на хостинге нет. Вместо русских символов в некоторых местах появились знаки вопросов и количество звезд увеличилось.

Пошел далее искать в Интернете. По очереди быстро просмотрел 2 следующие страницы и на последней нашел решение:

На всякий случай копирую в запись код, который привел автор статьи:

<?
	print "Локаль: " . setLocale(LC_ALL, 0) . "\n";

	/**
	 * Выводит результаты функции preg_match_all
	 * @param string $comment  Комментарий
	 * @param string $pattern  Паттерн для preg_match_all
	 * @param bool   $usePatch Использовать ли патч
	 * @return void
	 */

	function preg_test($comment, $pattern, $usePatch = false) {

		$test = "one два два three";

		print "\n<strong>{$comment}:</strong> <u>{$pattern}</u>\n";

		if ($usePatch) mb_preg_match_all($pattern, $test, $matches, PREG_OFFSET_CAPTURE);
		else preg_match_all($pattern, $test, $matches, PREG_OFFSET_CAPTURE);

		foreach ($matches[0] as $v) print "  Подстрока: «{$v[0]}», смещение: {$v[1]}\n";

	}

	/**
	 * Патч для устранения проблемы с оффсетами, осуществляет только их пересчет
	 */

	function mb_preg_match_all(
		$ps_pattern,
		$ps_subject,
		&$pa_matches,
		$pn_flags = PREG_PATTERN_ORDER,
		$pn_offset = 0,
		$ps_encoding = NULL
	) {

		// WARNING! - All this function does is to correct offsets, nothing else:
		//(code is independent of PREG_PATTER_ORDER / PREG_SET_ORDER)

		if (is_null($ps_encoding)) $ps_encoding = mb_internal_encoding();

		$pn_offset = strlen(mb_substr($ps_subject, 0, $pn_offset, $ps_encoding));
		$ret = preg_match_all($ps_pattern, $ps_subject, $pa_matches, $pn_flags, $pn_offset);

		if ($ret && ($pn_flags & PREG_OFFSET_CAPTURE))
			foreach($pa_matches as &$ha_match)
				foreach($ha_match as &$ha_match)
					$ha_match[1] = mb_strlen(substr($ps_subject, 0, $ha_match[1]), $ps_encoding);

		return $ret;

	}

	preg_test("«В лоб» — не ловятся русские буквы", "/[\w]+/i");
	preg_test("Character range — ловится все, что нужно, но кривые offset'ы", "/[а-яa-z]+/i");
	preg_test("«В лоб» с ключем «/u» — снова не ловятся русские буквы", "/[\w]+/ui");
	preg_test("Character range с ключем «/u» — ловится все, что нужно, но кривые offset'ы", "/[а-яa-z]+/ui");
	preg_test("Модификатор «\pL», можно даже без «/u» — ловится все, что нужно, но кривые offset'ы", "/[\pL]+/i");
	preg_test("Модификатор «\p{Cyrillic}», можно тоже без «/u» — ловится все, что нужно, но кривые offset'ы", "/[\p{Cyrillic}]+/i");
	preg_test("(!) Модификатор «\pL» с патчем — ловится все, правильные offset'ы — ЭТО ПРАВИЛЬНЫЙ СПОСОБ", "/[\pL]+/i", true);

	$source = highlight_file(__FILE__, true);
?>

На хостинге у меня заработал вариант "/[а-яa-z0-9]/ui". Однако, автор пишет, что правильный способ: "/[\pL]+/i", который мне выдал знаки вопросов. И тогда я понял, что решение заключается в модификаторе "u". Смотрим в документацию:

и читаем:

u (PCRE_UTF8) – этот модификатор включает дополнительную функциональность PCRE, которая не совместима с Perl: шаблоны обрабатываются как UTF-8 строки. Модификатор u доступен в PHP 4.1.0 и выше для Unix-платформ, и в PHP 4.2.3 и выше для Windows платформ. Валидность UTF-8 в шаблоне проверяется начиная с PHP 4.3.5.

Именно это и было нужно для моего хостинга. Итоговый и работающий вариант выглядит следующим образом:

preg_replace_callback('/<var>(.*?)<\/var>/', create_function('$matches', '$matches[1] = preg_replace("/[\pL]/ui", "*", $matches[1]); return "<span class=\"stars\">" . $matches[1] . "</span>";'), $content);

На экран выводится следующая строчка:

Строка для замены с секретным кодом ***-** и секретной строкой "****** *".

Спасибо тем, кто до меня копал в этой теме, я знаю, как это сложно и сколько отнимает времени.

Кстати также рабочий вариант прописать полностью русский алфавит в квадратных скобках. Замена произойдет без знаков вопросов, русские символы будут обработаны. Только одна исключение – звезд вновь будет больше, чем должно быть.

Переставил последнюю строчку кода в 1-й preg_replace() и все также заработало:

preg_replace('/<var>(.*?)<\/var>/e', 'preg_replace("/[\pL]/ui", "*", "$1")', $content);

Tags: , , , , , , , , ,
Записано в PHP, Программирование    |    Постоянная ссылка