Уважаемые пользователи!
C 7 ноября 2020 года phpBB Group прекратила выпуск обновлений и завершила дальнейшее развитие phpBB версии 3.2.
С 1 августа 2024 года phpBB Group прекращает поддержку phpBB 3.2 на официальном сайте.
Сайт официальной русской поддержки phpBB Guru продолжит поддержку phpBB 3.2 до 31 декабря 2024 года.
С учетом этого, настоятельно рекомендуется обновить конференции до версии 3.3.

[BETA] extender: конструктор слушателей событий

Здесь авторы могут постить бета-версии своих расширений для phpBB. Внимание! Не устанавливайте бета-версии расширений на работающие форумы!
Правила форума
Местная Конституция | Шаблон запроса | Документация (phpBB3) | Мини [FAQ] по phpBB3.1.x/3.2.x | FAQ | Внимание! Прежде чем создать тему - прочти! | Как задавать вопросы | Как устанавливать расширения

Ваш вопрос может быть удален без объяснения причин, если на него есть ответы по приведённым ссылкам (а вы рискуете получить предупреждение ;) ).

Внимание! Не устанавливайте бета-версии расширений на работающие форумы!
Аватара пользователя
c61
phpBB 2.0.6
Сообщения: 506
Стаж: 11 лет 3 месяца
Благодарил (а): 42 раза
Поблагодарили: 251 раз
Контактная информация:

[BETA] extender: конструктор слушателей событий

Сообщение c61 »

Extender: core and template event listeners constructor
phpBB 3.1 extension

copyright (c) 2014 c61 c61@yandex.ru
license http://opensource.org/licenses/gpl-license.php GNU Public License
ext_adm5.gif
Extender: Конструктор слушателей событий ядра и шаблонов

Создано по мотивам расширения Empennage http://c61.su/forum/viewtopic.php?f=11&t=108

Расширение позволяет добавлять слушателей событий ядра и шаблонов, в редультате Вы можете конструировать собственные расширения без необходимости создания их файлов в соответствии с правилами phpBB.

В обработчике событий Вы можете добавлять код и контент на страницы (css, html, javascript) для всех стилей и в слушатели событий ядра, модифицировать любые переменные шаблонов, добавлять свои переменные и т.п., то есть создавать свои расширения. Это может быть использовано, например, для добавления объявлений, счетчиков, информеров, отладки собственных стилей и скриптов.

Слушатели событий ядра, использование:

<!-- EVENT [Priority] PHP_Event[, PHP_Event[, HP_Event]] -->
PHP-код
<!-- ENDEVENT -->
Где:
• Priority - приоритет (отрицательное число), чем больше по абсолютному знгачению число, тем меньше приоритет обработчика события;
• PHP_Event - идентификатор события ядра (см. phpBB Wiki: Event List Event List).

Любой текст вне блока EVENT рассматривается как комментарий и не обрабатывается.

Пример:
<!-- EVENT core.page_footer_after -->
$this->rootref['SITE_LOGO_IMG'] = '<img src="http://mysite.ru/forum/styles/prosilver/site-logo.gif" style="max-width: 100%; height:auto; width:auto;">'
<!-- ENDEVENT -->

Слушатели событий шаблонов, использование

<!-- EVENT [PRE] Template_Event -->
здесь какой-либо код
<!-- ENDEVENT -->
Где:
• [PRE] - префикс, указывающий на необходимость компиляции шаблона для события перед обработкой шаблона ядром; если префикс опущен, компиляция выполняется ядром phpBB;
• Template_Event - идентификатор события шаблона (см. phpBB Wiki: Event List: Template Events Event List: Template Events и phpBB Wiki: Event List: ACP Template Events Event List: ACP Template Events).

Любой текст вне блока EVENT рассматривается как комментарий и не обрабатывается.

Примеры использования:
<!-- EVENT PRE overall_header_stylesheets_after -->
здесь какой-либо код
<!-- ENDEVENT -->
<!-- EVENT overall_footer_body_after -->
здесь какой-либо код
<!-- ENDEVENT -->

Внутри блока EVENT используйте:
• для JavaScript <script type="text/javascript">...</script>
• для StyleSheet <style type="text/css">...</style>
• для PHP <!-- PHP --> PHP-код <!-- ENDPHP -->

В событиях с префиксом PRE допустимы все конструкции для шаблонов phpBB 3.0.13 (кроме включений файлов, например, INCLUDE и т.п.), код PHP выполняется безусловно.

В событиях без префикса PRE допустимы все конструкции для шаблонов phpBB 3.1, код PHP выполняется только при условии разрешения PHP в шаблонах.

Вне кода PHP можно использовать:
• любые языковые переменные из языковых файлов (например, {L_<STRINGNAME>}, где <STRINGNAME> — это имя переведённой строки); так, {L_WROTE} будет отображено как «wrote» или переведено в зависимости от выбранного пользователем языка
• любые переменные, определённые для основного шаблона, например, {SCRIPT_NAME}; для локальных переменных, определённых посредством DEFINE, используйте {$VARNAME}.


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

PHP в слушателях событий ядра и шаблонов с префиксом PRE

Вы можете использовать:
• $this->event[] для доступа к данным события
• $this->rootref[] для доступа к переменным общего шаблона
• $this->tpldata[] для доступа к переменным шаблона
• $this->userlang[] для доступа к языковым переменным
• и др., см. исходный код расширения.

Все локальные переменные, определённые в уже обработанных событиях, доступны в новых событиях.

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

При наличии блокировки и включенном режиме выдачи отладочной информации внизу экрана выдаётся листинг и сообщение о блокировке.

Если фатальная ошибка произошла вне кода расширения, вместо пустой страницы выдаётся информация об ошибке, расширение не блокируется.

Для справки - коды ошибок, безусловно (*) или при определённых условиях (**) являющихся фатальными (условия отличаются от представленных в руководствах по PHP, поскольку в расширении для исполнения кода используется функция eval() с дополнительным обрамлением):
• [E_ERROR = 1] (*) Фатальные ошибки времени выполнения. Это неустранимые средствами самого скрипта ошибки, такие как ошибка распределения памяти и т.п. Выполнение скрипта в таком случае прекращается.
• [E_PARSE = 4] (**) Ошибки на этапе компиляции. Должны генерироваться только парсером.
• [E_CORE_ERROR = 16] (*) Фатальные ошибки, которые происходят во время запуска РНР. Такие ошибки схожи с E_ERROR, за исключением того, что они генерируются ядром PHP.
• [E_COMPILE_ERROR = 64] (**) Фатальные ошибки на этапе компиляции. Такие ошибки схожи с E_ERROR, за исключением того, что они генерируются скриптовым движком Zend.
• [E_USER_ERROR = 256] (**) Сообщения об ошибках сгенерированные пользователем. Такие ошибки схожи с E_ERROR, за исключением того, что они генерируются в коде скрипта средствами функции PHP trigger_error().
• [E_RECOVERABLE_ERROR = 4096] (**) Фатальные ошибки с возможностью обработки. Такие ошибки указывают, что, вероятно, возникла опасная ситуация, но при этом, скриптовый движок остается в стабильном состоянии. Если такая ошибка не обрабатывается функцией, определенной пользователем для обработки ошибок (см. set_error_handler()), выполнение приложения прерывается, как происходит при ошибках E_ERROR. Начиная с PHP 5.2.0

Все сообщения о фатальных ошибках либо в листинге выдаются на английском языке в связи с возможными ошибками заголовка страницы.


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


Дополнительные переменные основного шаблона

Extender создаёт переменные с префиксами 'S_EXTENDER_' затем идентификатором события шаблона (большими буквами) и суффиксом '_HASH', в которых содержится crc32 (hex) соответствующего исходного кода.

Создаётся также S_EXTENDER_COOKIENAME - имя cookie для использования в javascript.


Для разработчиков

Для подсветки всех событий шаблонов на всех страницах для любого пользователя (на страницу настройки этого расширения в панели администратора опция не распространяется) достаточно добавить в конец текста окна

Код: Выделить всё

<!-- ALLEVENTS -->
<!-- ENDALLEVENTS -->
Не забудьте удалить блок ALLEVENTS вместе с автоматически добавленным в него содержимым после завершения поиска нужного события.


Установка

Копировать содержимое каталога root в корневую папку конференции с сохранением структуры каталогов (расширения phpBB 3.1 располагаются в /ext).


Особые условия

В настройках PHP требуется 'register_globals = off' (по умолчанию начиная с PHP v.5.3).


Примеры:

Свой логотип

Core:

Код: Выделить всё

<!-- EVENT core.page_footer_after -->
$this->rootref['SITE_LOGO_IMG'] = '<img src="http://mysite.ru/forum/styles/prosilver/site-logo.gif" style="max-width: 100%; height:auto; width:auto;">'
<!-- ENDEVENT -->
Template:нет

Объявление для гостей (боты и зарегистрированные пользователя игнорируются)

Core:нет
Template:

Код: Выделить всё

<!-- EVENT PRE  overall_header_content_before -->
<!-- IF not S_IS_BOT -->
<!-- IF not S_REGISTERED_USER -->
<div id="announcement" style="display:none;"></div>
<script type="text/javascript">
// <![CDATA[
function EXsetCookie(hide) {
	var date = new Date;
	date.setDate(date.getDate() + 1000);
	document.cookie = "{S_EXTENDER_COOKIENAME}=" + hide + "; path=/; expires=" + date.toUTCString();
}
function EXgetCookie()
{
	var eqname = "{S_EXTENDER_COOKIENAME}=";
	var cookies = document.cookie.split(";");
	for ( var i = 0; i < cookies.length; i++ ) {
		var cookie = cookies[i];
		while ( cookie.charAt(0) == " " ) cookie = cookie.substring(1, cookie.length);
		if ( !cookie.indexOf(eqname) ) {
			var d = parseInt(cookie.substring(eqname.length, cookie.length));
			return d;
		}
	}
	return 0;
}
var announcement = document.getElementById("announcement");
if ( announcement ) {
	var announcement_title="{L_VIEW_TOPIC_ANNOUNCEMENT}";
	var announcement_text="Текст объявления";
	if ( EXgetCookie() != {S_EXTENDER_OVERALL_HEADER_CONTENT_BEFORE_HASH} ) {
		announcement.style.display="block";
	}
	announcement.innerHTML='<font color="darkred" size="+0.5em"><div><input type="button" value="&nbsp;&times;&nbsp;" style="background: transparent; border: 1px solid lightgray; margin: 0; padding: 0; font-weight: bolder; vertical-align: top;" onclick="announcement.style.display='+"'"+'none'+"'"+'; EXsetCookie({S_EXTENDER_OVERALL_HEADER_CONTENT_BEFORE_HASH});" />&nbsp;<b style="vertical-align: bottom;">'+announcement_title+'</b> </div> <div> <div style="display: block;">'+announcement_text+'<hr></hr></div></div></font><br />';
}
// ]]>
</script>
<!-- ENDIF -->
<!-- ENDIF -->
<!-- ENDEVENT -->
Установить иконку сайта (например, не favicon.ico в корне)

Core:нет
Template:

Код: Выделить всё

// favicon для конференции
<!-- EVENT overall_header_head_append -->
<link rel='icon' href='/myfavicon.png' type='image/x-icon'>
<link rel='shortcut icon' href='/myfavicon.png' type='image/x-icon'>
<!-- ENDEVENT -->
// favicon для админки
<!-- EVENT acp_overall_header_head_append -->
<link rel='icon' href='/myfavicon.png' type='image/x-icon'>
<link rel='shortcut icon' href='/myfavicon.png' type='image/x-icon'>
<!-- ENDEVENT -->
Установка счётчиков и информеров на страницы конференции

На примере Яндекса; замените XXXXXXXX на свой идентификатор.

Core:нет
Template:

Код: Выделить всё

<!-- EVENT overall_footer_copyright_append -->
<!-- Yandex.Metrika counter -->
<script type="text/javascript">
(function (d, w, c) {
    (w[c] = w[c] || []).push(function() {
        try {
            w.yaCounterXXXXXXXX = new Ya.Metrika({id:XXXXXXXX,
                    clickmap:true,
                    trackLinks:true,
                    accurateTrackBounce:true});
        } catch(e) { }
    });

    var n = d.getElementsByTagName("script")[0],
        s = d.createElement("script"),
        f = function () { n.parentNode.insertBefore(s, n); };
    s.type = "text/javascript";
    s.async = true;
    s.src = (d.location.protocol == "https:" ? "https:" : "http:") + "//mc.yandex.ru/metrika/watch.js";

    if (w.opera == "[object Opera]") {
        d.addEventListener("DOMContentLoaded", f, false);
    } else { f(); }
})(document, window, "yandex_metrika_callbacks");
</script>
<!-- <noscript><div><img src="//mc.yandex.ru/watch/XXXXXXXX" style="position:absolute; left:-9999px;" alt="" /></div></noscript> -->
<!-- /Yandex.Metrika counter -->
<!-- ENDEVENT -->
<!-- EVENT overall_footer_after -->
<div width="100%" align="center">
<!-- Yandex.Metrika informer -->
<a href="http://metrika.yandex.ru/stat/?id=XXXXXXXX&from=informer"
target="_blank" rel="nofollow"><img src="//bs.yandex.ru/informer/XXXXXXXX/3_0_373738FF_171718FF_1_pageviews"
style="width:88px; height:31px; border:0;" alt="Яндекс.Метрика" title="Яндекс.Метрика: данные за сегодня (просмотры, визиты и уникальные посетители)" onclick="try{Ya.Metrika.informer({i:this,id:XXXXXXXX,lang:\'ru\'});return false}catch(e){}"/></a>
<!-- /Yandex.Metrika informer -->
</div>
<!-- ENDEVENT -->
Установка своих языковых переменных

Core:

Код: Выделить всё

<!-- EVENT core.user_setup -->
switch ($this->event['user_lang_name']) {
	case 'ru': {
		$this->userlang += array(
			'MYLANGVAR1'	=> 'Моя первая языковая переменная',
			'MYLANGVAR2'	=> 'Моя вторая языковая переменная',
		);
		break;
	}
	default: {
		$this->userlang += array(
			'MYLANGVAR1'	=> 'My first language var',
			'MYLANGVAR2'	=> 'My second language var',
		);
		break;
	}
}
<!-- ENDEVENT -->
Template:

Код: Выделить всё

// Проверка установки языковых переменных
<!-- EVENT overall_footer_copyright_append -->
{L_MYLANGVAR1} {L_MYLANGVAR2}
<!-- ENDEVENT -->
Удаление Re: в заголовках тем и дубликатов subject в темах (аналог расширения c61\postsubject)

Core:

Код: Выделить всё

<!-- EVENT core.page_footer_after -->
if ( (($this->rootref['SCRIPT_NAME'] == 'viewtopic')
  || ($this->rootref['SCRIPT_NAME'] == 'posting')
     )
 && isset($this->rootref['TOPIC_TITLE']) ) {
	$tt = $this->rootref['TOPIC_TITLE'];
	$indexes = array('postrow','topic_review_row');
	foreach ( $indexes as $index ) {
		if ( !isset($this->tpldata[$index]) ) continue;
		foreach ( $this->tpldata[$index] as $key => $val ) {
			if ( isset($this->tpldata[$index][$key]['POST_SUBJECT']) ) {
				$ps = $this->tpldata[$index][$key]['POST_SUBJECT'];
				if ( !empty($ps) ) {
					if ( ($ps == $tt)
					  || ($ps == 'Re: '.$tt)
					  || ($ps == 'Re:'.$tt)
					  || ($ps == 'Re: '.substr($tt,0,-4))
					  || ($ps == 'Re:'.substr($tt,0,-3))
					   ) $ps = $this->tpldata[$index][$key]['POST_SUBJECT'] = '';
					else if ( preg_match('/^Re:\s*(.*)/isu',$ps,$matches) ) $ps = $this->tpldata[$index][$key]['POST_SUBJECT'] = $matches[1];
				}
			}
		}
	}
	if ( isset($this->rootref['L_POST_SUBJECT']) ) {
		$this->rootref['L_POST_SUBJECT'] = '<span class="postsubject_remove">&nbsp;</span>';
	}
}

<!-- ENDEVENT -->
<!-- EVENT core.display_forums_modify_template_vars -->
$forum_row = $this->event['forum_row'];
$modified = false;
if ( isset($forum_row['LAST_POST_SUBJECT']) ) {
	if ( preg_match('/^Re:\s*(.*)/isu',$forum_row['LAST_POST_SUBJECT'],$matches) ) {
		$forum_row['LAST_POST_SUBJECT'] = $matches[1];
		$modified = true;
	}
}
if ( isset($forum_row['LAST_POST_SUBJECT_TRUNCATED']) ) {
	if ( preg_match('/^Re:\s*(.*)/isu',$forum_row['LAST_POST_SUBJECT_TRUNCATED'],$matches) ) {
		$forum_row['LAST_POST_SUBJECT_TRUNCATED'] = $matches[1];
		$modified = true;
	}
}
if ( $modified ) $this->event['forum_row'] = $forum_row;
<!-- ENDEVENT -->
<!-- EVENT core.viewforum_modify_topicrow -->
$topic_row = $this->event['topic_row'];
$modified = false;
if ( isset($topic_row['LAST_POST_SUBJECT']) ) {
	if ( preg_match('/^Re:\s*(.*)/isu',$topic_row['LAST_POST_SUBJECT'],$matches) ) {
		$topic_row['LAST_POST_SUBJECT'] = $matches[1];
		$modified = true;
	}
}
if ( $modified ) $this->event['topic_row'] = $topic_row;
<!-- ENDEVENT -->
Template:

Код: Выделить всё

<!-- EVENT overall_header_head_append -->
<style type="text/css">
span.postsubject_remove {
	padding: 0px;
	margin: 0px;
	visibility: hidden;
}
</style>
<!-- ENDEVENT -->
<!-- EVENT overall_footer_after -->
<script type="text/javascript">
// <![CDATA[
function PShide() {
	var ps = document.getElementsByClassName("postsubject_remove");
	for ( var i=0; i<ps.length; i++ ) {
		var p = ps[i].parentNode;
		if ( p ) {
			p.style.display = "none";
		}
	}
}
PShide();
// ]]>
</script>
<!-- ENDEVENT -->
Расширение "Detailed viewonline by rxu" (rxu/DetailedViewonline)

Core:

Код: Выделить всё

<!-- EVENT core.user_setup -->
switch ($this->event['user_lang_name'])
{
	case 'ru':
	{
		$this->userlang['READING_THE_TOPIC']		= 'Просматривает тему <strong>%1$s</strong> в форуме %2$s';
		$this->userlang['READING_THE_TOPIC_PAGE']	= 'Просматривает страницу %3$s темы <strong>%1$s</strong> в форуме %2$s';
		$this->userlang['READING_THE_NEW_POSTS']	= 'Просматривает непрочитанные сообщения темы <strong>%1$s</strong> в форуме %2$s';
		$this->userlang['READING_THE_POST']			= 'Просматривает сообщение темы <strong>%1$s</strong> в форуме %2$s';
		break;
	}
	default:
	{
		$this->userlang['READING_THE_TOPIC']		= 'Reading the topic <strong>%1$s</strong> in %2$s';
		$this->userlang['READING_THE_TOPIC_PAGE']	= 'Reading page %3$s of the topic <strong>%1$s</strong> in %2$s';
		$this->userlang['READING_THE_NEW_POSTS']	= 'Reading new posts of the topic <strong>%1$s</strong> in %2$s';
		$this->userlang['READING_THE_POST']			= 'Reading the post in the topic <strong>%1$s</strong> in %2$s';
		break;
	}
}
<!-- ENDEVENT -->
<!-- EVENT core.viewonline_overwrite_location -->
$forum_data = $this->event['forum_data'];
$on_page = $this->event['on_page'];
$location = $this->event['location'];
$location_url = $this->event['location_url'];
$row = $this->event['row'];

switch ($on_page[1])
{
	case 'viewtopic':

		preg_match('#[\?&]t=([0-9]+)#i', $row['session_page'], $topic_id);
		$topic_id = (sizeof($topic_id)) ? (int) $topic_id[1] : 0;

		preg_match('#[\?&]p=([0-9]+)#i', $row['session_page'], $post_id);
		$post_id = (sizeof($post_id)) ? (int) $post_id[1] : 0;

		preg_match('#[\?&]start=([0-9]+)#i', $row['session_page'], $start);
		$start = (sizeof($start)) ? (int) $start[1] : 0;
		$page = ($start) ? ($start / $this->config['posts_per_page']) + 1 : 0;

		$view = (preg_match('#[\?&]view=unread#i', $row['session_page'])) ? true : false;

		if ($post_id)
		{
			$sql_ary = array(
				'SELECT'	=> 't.topic_id, t.topic_title, t.forum_id',
				'FROM'		=> array(
					POSTS_TABLE		=> 'p',
					TOPICS_TABLE	=> 't',
				),
				'WHERE'		=> 't.topic_id = p.topic_id
					AND p.post_id = ' . $post_id,
			);
		}
		else
		{
			$sql_ary = array(
				'SELECT'	=> 't.topic_title, t.forum_id',
				'FROM'		=> array(
					TOPICS_TABLE	=> 't',
				),
				'WHERE'		=> 't.topic_id = ' . $topic_id,
			);
		}

		$result = $this->db->sql_query($this->db->sql_build_query('SELECT', $sql_ary));
		if ($topicdata = $this->db->sql_fetchrow($result))
		{
			$topic_id = ($topic_id) ? : (int) $topicdata['topic_id'];
			$forum_id = (int) $topicdata['forum_id'];
			if ($forum_id && $this->auth->acl_get('f_list', $forum_id))
			{
				$topic_title = $topicdata['topic_title'];
				if ($post_id)
				{
					$location = sprintf($this->userlang['READING_THE_POST'], $topic_title, $forum_data[$forum_id]['forum_name']);
					$location_url = append_sid("{$this->phpbb_root_path}viewtopic.$this->php_ext", "p=$post_id#p$post_id");
				}
				else if ($start)
				{
					$location = sprintf($this->userlang['READING_THE_TOPIC_PAGE'], $topic_title, $forum_data[$forum_id]['forum_name'], $page);
					$location_url = append_sid("{$this->phpbb_root_path}viewtopic.$this->php_ext", 'f=' . $forum_id . '&t=' . $topic_id . '&start=' . $start);
				}
				else if ($view)
				{
					$location = sprintf($this->userlang['READING_THE_NEW_POSTS'], $topic_title, $forum_data[$forum_id]['forum_name']);
					$location_url = append_sid("{$this->phpbb_root_path}viewtopic.$this->php_ext", 'f=' . $forum_id . '&t=' . $topic_id . '&view=unread#unread');
				}
				else
				{
					$location = sprintf($this->userlang['READING_THE_TOPIC'], $topic_title, $forum_data[$forum_id]['forum_name']);
					$location_url = append_sid("{$this->phpbb_root_path}viewtopic.$this->php_ext", 'f=' . $forum_id . '&t=' . $topic_id);
				}
			}
		}
		$this->db->sql_freeresult($result);
	break;

	case 'search';
		preg_match('#search_id=([a-z_]+)#i', $row['session_page'], $search_id);
		$search_id = (!empty($search_id[1])) ? $search_id[1] : '';
		$search_mode = array('egosearch' => 'SEARCH_SELF', 'unanswered' => 'SEARCH_UNANSWERED', 'unreadposts' => 'SEARCH_UNREAD', 'newposts' => 'SEARCH_NEW', 'active_topics' => 'SEARCH_ACTIVE_TOPICS');
		$location = $this->userlang['SEARCHING_FORUMS'] . (($search_id) ? ': <strong>' . $this->userlang[$search_mode[$search_id]] . '</strong>' : '');
		$location_url = append_sid("{$this->phpbb_root_path}search.$this->php_ext", ($search_id) ? 'search_id=' . $search_id : '');
	break;

	case 'memberlist';
		preg_match('#[\?&]u=([0-9]+)#i', $row['session_page'], $user_id);
		$user_id = (sizeof($user_id)) ? (int) $user_id[1] : 0;
		if ($user_id)
		{
			$sql = 'SELECT username, user_colour FROM ' . USERS_TABLE . '
				WHERE user_id = ' . $user_id;

			$result = $this->db->sql_query($sql);
			if ($userdata = $this->db->sql_fetchrow($result))
			{
				$username = get_username_string('no_profile', $user_id, $userdata['username'], $userdata['user_colour'], $userdata['username']);
				$location = $this->userlang['VIEWING_MEMBER_PROFILE'] . ' <strong>' . $username;
				$location_url = append_sid("{$this->phpbb_root_path}memberlist.$this->php_ext", "mode=viewprofile&u=$user_id");
			}
			$this->db->sql_freeresult($result);
		}
	break;

	case 'download/file':
		preg_match('#[\?&]id=([0-9]+)#i', $row['session_page'], $file_id);
		$file_id = (sizeof($file_id)) ? (int) $file_id[1] : 0;
		if ($file_id)
		{
			$sql = 'SELECT real_filename, post_msg_id FROM ' . ATTACHMENTS_TABLE . '
				WHERE attach_id = ' . $file_id;

			$result = $this->db->sql_query($sql);
			if ($filedata = $this->db->sql_fetchrow($result))
			{
				$location = $this->userlang['DOWNLOADING_FILE'] . ' <strong>' . $filedata['real_filename'] . '</strong>';
				$location_url = append_sid("{$this->phpbb_root_path}viewtopic.$this->php_ext", "p={$filedata['post_msg_id']}#p{$filedata['post_msg_id']}");
			}
			$this->db->sql_freeresult($result);
		}
	break;

	case 'feed';
		$location = $this->userlang['FEED'];
		$location_url = append_sid("{$this->phpbb_root_path}feed.$this->php_ext");
	break;

	default:
	break;
}

$this->event['location']= $location;
$this->event['location_url'] = $location_url;
<!-- ENDEVENT -->
Template:нет

Минипрофили слева в viewtopic для prosilver

Core:

Код: Выделить всё

<!-- EVENT core.page_header_after -->
if ( ($this->rootref['SCRIPT_NAME'] == 'viewtopic') && ($this->rootref['T_THEME_NAME'] == 'prosilver') ) {
	preg_match('/MSIE (.*?);/', $this->rootref['S_USER_BROWSER'], $matches);
	if ( count($matches) < 2 ) preg_match('/Trident\/\d{1,2}.\d{1,2}; rv:([0-9]*)/', $this->rootref['S_USER_BROWSER'], $matches);
	if ( !( (count($matches) > 1) && ($matches[1] < 9) ) ) $this->rootref['S_EXTENDER_MINIPROFILES'] = true;
}
<!-- ENDEVENT -->
Template:

Код: Выделить всё

<!-- EVENT overall_header_head_append -->
<!-- IF S_EXTENDER_MINIPROFILES -->
<style type="text/css">
.online {
	background-position: 0% 0;
	background-image: none;
	position: relative;
	overflow: hidden;
}
.online:before {
	position: absolute;
	content: url("{T_THEME_PATH}/{S_USER_LANG}/icon_user_online.gif");
	top: 0px;
	left: 0px;
	-webkit-transform: rotate(-90deg);
	-moz-transform: rotate(-90deg);
	-ms-transform: rotate(-90deg);
	-o-transform: rotate(-90deg);
	transform: rotate(-90deg);
}
.postprofile {
	border-width: 0 1px 0 0;
	float: left;
	text-align: right;
	padding-right: 10px;
}
.postprofile .avatar {
	float: right;
}
.postbody {
	float: right;
}
@media only screen and (max-width: 700px), only screen and (max-device-width: 700px)
{
	.online {
		position: relative;
		background-image: url("{T_THEME_PATH}/{T_THEME_LANG_NAME}/icon_user_online.gif");
		background-position: 100% 0;
		background-repeat: no-repeat;
	}
	.online:before {
		position: absolute;
		content: "";
		top: 0px;
		left: 0px;
	}
	.postprofile {
		border-width: 0 0 0 1px;
		float: none;
		text-align: left;
		padding-right: 0;
	}
	.postprofile .avatar {
		float: left;
	}
	.postbody {
		float: left;
	}
}
</style>
<!-- ENDIF -->
<!-- ENDEVENT -->
Список пользователей online на каждой странице

Core:

Код: Выделить всё

<!-- EVENT core.page_header -->
if ( !$this->event['display_online_list'] || $this->event['item_id'] ) {
	$this->event['display_online_list'] = true;
	$this->rootref['S_ALL_PAGES_ONLINE_LIST'] = 1;
	if ( $this->event['item_id'] ) {
		if ( !function_exists('obtain_users_online') ) {
			require($this->phpbb_root_path . 'includes/functions.' . $this->php_ext);
		}
		$online_users = obtain_users_online(0, '');
		$user_online_strings = obtain_users_online_string($online_users, 0, '');
		$this->rootref['S_ALL_PAGES_ONLINE_USERS_LIST'] = $user_online_strings['online_userlist'];
	}
}
<!-- ENDEVENT -->
<!-- EVENT core.page_header_after -->
if ( isset($this->rootref['S_ALL_PAGES_ONLINE_LIST']) && $this->rootref['S_ALL_PAGES_ONLINE_LIST'] ) {
	unset($this->rootref['S_DISPLAY_ONLINE_LIST']);
}
<!-- ENDEVENT -->
Template:

Код: Выделить всё

<!-- EVENT overall_footer_content_after -->
<!-- IF S_ALL_PAGES_ONLINE_LIST -->
<!-- IF SCRIPT_NAME ne 'viewonline' -->
	<div class="stat-block online-list">
		<!-- IF U_VIEWONLINE --><h3><a href="{U_VIEWONLINE}">{L_WHO_IS_ONLINE}</a></h3><!-- ELSE --><h3>{L_WHO_IS_ONLINE}</h3><!-- ENDIF -->
		<p>
			{TOTAL_USERS_ONLINE} ({L_ONLINE_EXPLAIN})<br />{RECORD_USERS}<br /> <br />
<!-- IF S_ALL_PAGES_ONLINE_USERS_LIST -->
{S_ALL_PAGES_ONLINE_USERS_LIST}<br/> <br />
<!-- ENDIF -->
{LOGGED_IN_USER_LIST}
		</p>
	</div>
<!-- ENDIF -->
<!-- ENDIF -->
<!-- ENDEVENT -->
Добавление навигационных ссылок

Core:Нет
Template:

Код: Выделить всё

<!-- EVENT navbar_header_quick_links_before -->
<li class="small-icon icon-search-self"><a href="http://mysite.ru" target="_blank" role="menuitem">Мой сайт</a></li> 
<li class="small-icon icon-search-self"><a href="http://old.mysite.ru" target="_blank" role="menuitem">Мой старый сайт</a></li> 
<li class="separator"></li> 
<!-- ENDEVENT -->
Добавление ссылки на ленту новостей

Core:Нет
Template:

Код: Выделить всё

<!-- EVENT overall_header_navigation_append  -->
<!-- IF T_THEME_NAME == 'prosilver' -->
<li class="small-icon icon-feed data-last-responsive="true"><a href="./feed.php" title="Atom Feed" role="menuitem">Лента новостей</a></li>
<!-- ENDIF -->
<!-- ENDEVENT -->
Добавление ссылки на ленту новостей в стилях от Artodia

Core:Нет
Template:

Код: Выделить всё

<!-- EVENT overall_header_stylesheets_after -->
<!-- IF T_THEME_NAME != 'prosilver' -->
<style type="text/css">
.icon-rss {
	position:relative;
	background-image:none;
}
.icon-rss:after {
	font-family: 'Glyphicons Regular','Glyphicons';
	content: '\E074';	// glyphicons
	width: 18px;
	text-align: center;
	color:#3462a0;
	position:absolute;
	top:50%;
	left:0;
	height:14px;
	margin-top:-7px;
	text-align:center;
	font-size:12px;
	line-height:14px;
	vertical-align:baseline;
	font-weight:normal;
	font-style:normal;
	text-transform:none;
	text-indent:0;
	pointer-events:none;
	-moz-transform: rotate(45deg);
	-o-transform: rotate(45deg);
	-webkit-transform: rotate(45deg);
	-ms-transform: rotate(45deg);
	transform: rotate(45deg);
}
.icon-rss:hover:after {
	color:#b93329;
}
</style>
<!-- ENDIF -->
<!-- ENDEVENT -->
<!-- EVENT secondary_navlinks_after -->
<!-- IF T_THEME_NAME != 'prosilver' -->
<li class="small-icon icon-rss responsive-cloned-item"><a href="./feed.php" title="Atom Feed">Лента новостей</a></li>
<!-- ENDIF -->
<!-- ENDEVENT -->
Подключение автоматической подсветки синтаксиса для ББ-кода code

Core:Нет
Template:

Код: Выделить всё

<!-- EVENT overall_header_stylesheets_after -->
<!-- IF (SCRIPT_NAME eq 'viewtopic') or (SCRIPT_NAME eq 'posting') -->
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.7/styles/default.min.css">
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.7/highlight.min.js"></script>
<!-- ENDIF -->
<!-- ENDEVENT -->
<!-- EVENT overall_footer_body_after -->
<!-- IF (SCRIPT_NAME eq 'viewtopic') or (SCRIPT_NAME eq 'posting') -->
<script type="text/javascript">
$('code').each(function(i, block) {
	hljs.highlightBlock(block);
});
</script>
<!-- ENDIF -->
<!-- ENDEVENT -->
Изменение/упрощение prosilver

Core:Нет
Template:

Код: Выделить всё

<!-- EVENT overall_header_stylesheets_after -->
<!-- IF T_THEME_NAME == 'prosilver' -->
<style type="text/css">
/* width & positions */
body {
	padding: 0;
}
#wrap {
	border-radius: 0;
	max-width: 32768px;
	min-width: 625px;
	padding: 0 15px;
}
@media only screen and (max-width: 1220px), only screen and (max-device-width: 1220px) {
	#wrap {
		margin: 0 auto;
	}
}
#page-body {
	max-width: 1220px;
	margin: 4px auto;
}
#page-header, #page-footer /*, .forabg, .forumbg, .post, .panel */{
	margin-right: -15px;
	margin-left: -15px;
}
@media only screen and (max-width: 700px), only screen and (max-device-width: 700px) {
	#page-header, #page-footer, .forabg, .forumbg, .post, .panel {
		margin-right: 0;
		margin-left: 0;
	}
}
/* no radiuses */
.headerbar {
	margin-bottom: 0;
	border-radius: 0;
}
.navbar {
	border-radius: 0;
}
.forabg {
	border-radius: 0;
}
.forumbg {
	border-radius: 0;
}
.panel {
	border-radius: 0;
}
.post {
	border-radius: 0;
}
.dropdown {
	border-radius: 0;
}
.dropdown .dropdown-contents {
	border-radius: 0;
}
.pagination li a, .pagination li span {
	border-radius: 0;
}
#loading_indicator {
	border-radius: 0;
}
.dropdown-extended .header {
	border-radius: 0;
}
.postbody .content::-webkit-scrollbar, #topicreview::-webkit-scrollbar, #post_details::-webkit-scrollbar, .codebox code::-webkit-scrollbar, .attachbox dd::-webkit-scrollbar, .attach-image::-webkit-scrollbar, .dropdown-extended ul::-webkit-scrollbar {
	border-radius: 0;
}
.postbody .content::-webkit-scrollbar-thumb, #topicreview::-webkit-scrollbar-thumb, #post_details::-webkit-scrollbar-thumb, .codebox code::-webkit-scrollbar-thumb, .attachbox dd::-webkit-scrollbar-thumb, .attach-image::-webkit-scrollbar-thumb, .dropdown-extended ul::-webkit-scrollbar-thumb {
	border-radius: 0;
}
.rtl .search-box .inputbox {
	border-radius: 0;
}
.rtl .search-box a.button {
	border-radius: 0;
}
.button {
	border-radius: 0;
}
#tabs .tab > a {
	border-radius: 0;
}
#minitabs .tab > a {
	border-radius: 0;
}
.cp-mini {
	border-radius: 0;
}
@media only screen and (max-width: 900px), only screen and (max-device-width: 900px)
{
	#navigation li:first-child a {
		border-top-left-radius: 0;
		border-top-right-radius: 0;
	}
	#navigation li:first-child a {
		border-top-left-radius: 0;
		border-top-right-radius: 0;
	}
}
.search-box .inputbox {
	border-radius: 0;
}
.search-box button.search-icon {
	border-radius: 0;
}
.search-box a.button {
	border-radius: 0;
}
.search-header {
	border-radius: 0;
}
/* colors */
.forabg {
	background-color: #ffffff;
	background-image: none;
}
.forumbg {
	border-top: 1px solid #eff5f9;
	border-bottom: 1px solid #eff5f9;
	background-color: #ffffff;
	background-image: none;
}
.forumbg .header a, .forabg .header a, th a {
	color: #000000;
}
.forumbg .header a:hover, .forabg .header a:hover, th a:hover {
	color: #D31141;
}
li.header dt, li.header dd {
	color: #000000;
}
li.row {
	border-top-color:  #FFFFFF;
	border-bottom-color: #ffffff;
}
/* no uppercase */
h3 {
	text-transform: none;
	font-size: 125%;
}
table.table1 thead th {
	text-transform: none;
}
.dropdown-extended .header {
	text-transform: none;
}
li.header dt, li.header dd {
	text-transform: none;
	font-size: 125%;
}
.codebox p {
	text-transform: none;
}
.attachbox dt {
	text-transform: none;
}
</style>
<!-- ENDIF -->
<!-- ENDEVENT -->
Тест локальных переменных

Core:

Код: Выделить всё

<!-- EVENT core.common -->
$myvar = 1;
<!-- ENDEVENT -->
<!-- EVENT core.page_footer_after -->
++$myvar;
<!-- ENDEVENT -->
Template:

Код: Выделить всё

<!-- EVENT PRE overall_footer_body_after -->
<!-- PHP -->
echo '$myvar = '.$myvar;
<!-- ENDPHP -->
<!-- ENDEVENT -->
Тест обработки ошибок PHP (см. http://habrahabr.ru/post/161483/)

Для тестрования снимите комментарий с ошибочного оператора.

Core:

Код: Выделить всё

<!-- EVENT core.user_setup -->
// NONFATAL - E_NOTICE
// echo $undefined_var;

// NONFATAL - E_WARNING
// array_key_exists("key", NULL);

// NONFATAL - E_DEPRECATED
// split("[/.-]", "12/21/2012"); // split() deprecated начиная с php 5.3.0

// NONFATAL - E_STRICT
// class c {function f(){}} c::f();

// NONFATAL - E_USER_DEPRECATED
// trigger_error("E_USER_DEPRECATED", E_USER_DEPRECATED);

// NONFATAL - E_USER_WARNING
// trigger_error("E_USER_WARNING", E_USER_WARNING);

// NONFATAL - E_USER_NOTICE
// trigger_error("E_USER_NOTICE", E_USER_NOTICE);

// FATAL, если не обработана функцией set_error_handler - E_RECOVERABLE_ERROR
// class b {function f(int $a){}} $b = new b; $b->f(NULL);

// FATAL, если не обработана функцией set_error_handler - E_USER_ERROR
// trigger_error("E_USER_ERROR", E_USER_ERROR);

// FATAL - E_ERROR
// undefined_function();

// FATAL - E_PARSE
// parse_error

// FATAL - E_COMPILE_ERROR
// $var[];
// require "missing_file.php";
<!-- ENDEVENT -->
Template:нет


Скриншоты
Вложение ext_adm1.gif больше недоступно
ext_adm1.gif
ext_adm2.gif
ext_adm3.gif
ext_adm4.gif

Тема на моей тестовой площадке тынц.

P.S. Если кому-то очень хочется потренироваться, но нет времени/возможности тестировать на своём хостинге, по запросу посредством ЛС могу предоставить тестик на халявном хостингере (тестовый админ + юзер).

P.P.S. На кривых и самопальных хостингах имеет право не завестись.
Последний раз редактировалось c61 15.11.2015 11:23, всего редактировалось 12 раз.
Аватара пользователя
c61
phpBB 2.0.6
Сообщения: 506
Стаж: 11 лет 3 месяца
Благодарил (а): 42 раза
Поблагодарили: 251 раз
Контактная информация:

Re: [BETA] extender: конструктор слушателей событий

Сообщение c61 »

Выпущена стабильная бета-версия 0.1.2 - 20150313.
Zigbert
phpBB 1.2.0
Сообщения: 16
Стаж: 18 лет 5 месяцев
Откуда: http://mysonata.ru
Благодарил (а): 5 раз
Поблагодарили: 2 раза
Контактная информация:

Re: [BETA] extender: конструктор слушателей событий

Сообщение Zigbert »

на обоих версиях расширения такая ошибка при активации выскакивает.
соотв. расширение не работает.
Вложения
bug.png
Аватара пользователя
c61
phpBB 2.0.6
Сообщения: 506
Стаж: 11 лет 3 месяца
Благодарил (а): 42 раза
Поблагодарили: 251 раз
Контактная информация:

Re: [BETA] extender: конструктор слушателей событий

Сообщение c61 »

Zigbert, спасибо, ошибка исправлена.
Zigbert писал(а): расширение не работает.
Вы не забыли включить обработку слушателей событий ? А также при переходе на новую версию нет необходимости удалять настройки расширения, достаточно его отключить, удалить на сервере файлы расширения, записать файлы новой версии, затем включить расширение и из настройки расширения нажать "Сохранить изменения".

Ну наконец-то дело дошло до испытаний расширения, а то скачивания есть, а сообщений об ошибках нет, но знаю точно: ошибки должны быть, без них никак ;)
Zigbert
phpBB 1.2.0
Сообщения: 16
Стаж: 18 лет 5 месяцев
Откуда: http://mysonata.ru
Благодарил (а): 5 раз
Поблагодарили: 2 раза
Контактная информация:

Re: [BETA] extender: конструктор слушателей событий

Сообщение Zigbert »

Может на Github закоммитить?

Отправлено спустя 17 минут 36 секунд:
Предыдущая ошибка исчезла.
Появилась новая - после включения обеих обработок Chrome говорит вот что -
Вложения
adm.png
Аватара пользователя
c61
phpBB 2.0.6
Сообщения: 506
Стаж: 11 лет 3 месяца
Благодарил (а): 42 раза
Поблагодарили: 251 раз
Контактная информация:

Re: [BETA] extender: конструктор слушателей событий

Сообщение c61 »

Zigbert писал(а):Может на Github закоммитить?
Пользуюсь только своими git-серверами :) Да и смысла не вижу. Этот ext весьма специфичный, широкого использования не предвидится.

На тестовом хостингере (c61.vv.si/phpBB31/index.php под apache), на домашнем мини-сервере (c61.su/phpbb/index.php под lighttpd), на локальных серверах (apache) ошибка не наблюдается, проверено под крайними версиями FF, Opera, Chrome. Может, у Вас какие-то ограничения на запись в каталог расширений ? Права доступа к папкам и файлам, например, или что-то такое в .htaccess... Extender манипулирует файлами в /ext/c61/styles/all/template/event и /ext/c61/adm/style/event. Если хотите, по запросу в личку дам админдоступ phpBB на хостингер для тестирования. Только этот хостингер кривой и тормозной, там бывает вылезают ошибки, имеющие отношения исклюбчительно к хостингу и высокой общей нагрузке на сервер, перезагрузка страницы решает проблемы.
Zigbert
phpBB 1.2.0
Сообщения: 16
Стаж: 18 лет 5 месяцев
Откуда: http://mysonata.ru
Благодарил (а): 5 раз
Поблагодарили: 2 раза
Контактная информация:

Re: [BETA] extender: конструктор слушателей событий

Сообщение Zigbert »

c61 писал(а): Права доступа к папкам и файлам
Сделайте тогда проверку на права доступа к папкам в настройках EXT
после изменения всей ветки на 777 заработало
Аватара пользователя
c61
phpBB 2.0.6
Сообщения: 506
Стаж: 11 лет 3 месяца
Благодарил (а): 42 раза
Поблагодарили: 251 раз
Контактная информация:

Re: [BETA] extender: конструктор слушателей событий

Сообщение c61 »

777 небезопасно. А проверка не нужна, лучше использовать phpbb_chmod когда надо. Плюс придется добавить .htaccess. Будет время - доделаю.

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

Из темы про список пользователей online (можно обсуждать здесь, поскольку пример также здесь опубликован):
Zigbert писал(а):c61, {LOGGED_IN_USER_LIST} не выводится. Выводится только статистика сколько всего
Посмотрите настройки прав пользователя: разрешено ли смотреть список пользователей online.
technolog
phpBB 1.4.2
Сообщения: 55
Стаж: 17 лет 8 месяцев
Благодарил (а): 12 раз
Контактная информация:

Re: [BETA] extender: конструктор слушателей событий

Сообщение technolog »

Уважаемый c61,
Огромное спасибо за детально отточенный и, в то же время, приятно изложенный материал, жаль тему на которую ссылаюсь закрыли...
Заголовок: Проверка на adblock у пользователя

Оверквотинг. Удалено!

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

Итак, у меня легко получилась первая часть (с всплывающим окном), а вот вторая - глючит (или скорее глючу Я ...)
Не зависимо от того, включён AdBlock или выключен упорно вылазит окно на JQuery...
Пытался спрятать его инициализацию под строкой

Код: Выделить всё

<script type="text/javascript" src="{BOARD_URL}advert.js"></script>
проверяющей статус AdBlock - игнорирует и вылазит...
Потом танцевал с бубном в разных вариациях и перестановках - не получается и всё!

Вернул изначальное всплывающее окно (без JQuery:

Код: Выделить всё

<!-- IF SCRIPT_NAME == 'viewtopic' -->
<script type="text/javascript" src="{BOARD_URL}advert.js"></script>
<script type="text/javascript">// <![CDATA[
if (!('adblock' in window)) {
	window.adblock = true;
}
if (window.adblock == true) {
	alert('Пожалуйста, отключите AdBlock');
}
// ]]></script>
<!-- ENDIF -->
снова заработало....

Подскажите пожалуйста, что делаю не так?

С уважением,
Вадим
Последний раз редактировалось Sheer 25.03.2018 16:53, всего редактировалось 1 раз.
Причина: Удален оверквотинг
Аватара пользователя
Sheer
Former team member
Сообщения: 12113
Стаж: 17 лет 1 месяц
Откуда: Калининград не Кенигсберг
Благодарил (а): 54 раза
Поблагодарили: 2752 раза
Контактная информация:

Re: [BETA] extender: конструктор слушателей событий

Сообщение Sheer »

Не подскажет.
Изображение
Общие ошибки новичков (07.11.2005) & Как задавать вопросы
Мини FAQ
Если ничто другое не помогает, прочтите, наконец, инструкцию!
"Никакая инструкция не может перечислить всех обязанностей должностного лица, предусмотреть все отдельные случаи и дать вперёд соответствующие указания, а поэтому господа инженеры должны проявить инициативу и, руководствуясь знаниями своей специальности и пользой дела, принять все усилия для оправдания своего назначения".
Циркуляр Морского технического комитета №15 от 29.11.1910 г.
Аватара пользователя
Sumanai
phpBB 3.0.0 RC5
Сообщения: 1668
Стаж: 9 лет 4 месяца
Благодарил (а): 267 раз
Поблагодарили: 216 раз
Контактная информация:

Re: [BETA] extender: конструктор слушателей событий

Сообщение Sumanai »

Да и вообще такие окошки зло, надеюсь, вообще никто подсказывать не будет.
technolog
phpBB 1.4.2
Сообщения: 55
Стаж: 17 лет 8 месяцев
Благодарил (а): 12 раз
Контактная информация:

Re: [BETA] extender: конструктор слушателей событий

Сообщение technolog »

а какие окошки не "зло" ?
И для кого делают и показывают контекстную рекламу?
не все сайты коммерческие, за хостинг надо чем-то платить, поэтому спрашиваю и прошу помощи.
Аватара пользователя
Татьяна5
Поддержка
Поддержка
Сообщения: 12372
Стаж: 12 лет 7 месяцев
Благодарил (а): 223 раза
Поблагодарили: 3517 раз
Контактная информация:

Re: [BETA] extender: конструктор слушателей событий

Сообщение Татьяна5 »

Которые функциональны и не отпугивают посетителей
Принуждающие выключить адблок нефункциональны и как раз всех распугивают
Аватара пользователя
Sumanai
phpBB 3.0.0 RC5
Сообщения: 1668
Стаж: 9 лет 4 месяца
Благодарил (а): 267 раз
Поблагодарили: 216 раз
Контактная информация:

Re: [BETA] extender: конструктор слушателей событий

Сообщение Sumanai »

technolog писал(а): 09.04.2018 22:57 а какие окошки не "зло" ?
Те, которые вызываются действиями пользователей и приносят ему пользу.
technolog писал(а): 09.04.2018 22:57 И для кого делают и показывают контекстную рекламу?
Понятия не имею, кто за это платит и кто кликает.
technolog писал(а): 09.04.2018 22:57 не все сайты коммерческие, за хостинг надо чем-то платить, поэтому спрашиваю и прошу помощи.
Вот и платите. Я за свои плачу пару тысяч в год, пока не разорился.
Ответить

Вернуться в «Бета-версии расширений для phpBB»