Внешние ссылки в новом окне, средствами Друпала и jQuery.

Главные вкладки

Аватар пользователя Ромка Ромка 27 июня 2007 в 17:48

В этом сообщении рассказано о модуле External Links, который позволяет сделать так, чтобы все внешние сслыки, даже те, у которых не установлен атрибут "target=_blank", открывались во внешнем окне. Решение простое, но, на мой взгляд, не очень изящное, ведь приходится устанавливать сторонний модуль для выполнения задачи, которая легко решается с помощью библиотеки jQuery, встроенной в Друпал.

Js-script позаимствован мною отсюда, я только его немного доработал. Просто скопируйте и вставьте в любое место шаблона (в node.tpl.php, например) один из следующих вариантов кода.

0. Внимание! Все нижеперечисленные примеры работают с библиотекой jQuery 1.1.2 от 2007-02-28. С Друпалом 5.1 поставляется более старая версия этой библиотеки, по этому нужно скачать с jquery.com последнюю её версию, переименовать в jquery.js и скоприровать в папку misc.

1. Все внешние ссылки на странице открываются в новом окне:
drupal_add_js("\$(document).ready(function(){\$(\"a[href^=http:]\").each(function(){if(this.host!=\"" . $_SERVER['HTTP_HOST']. "\"){\$(this).attr(\"target\",\"_blank\");}});});", "inline");
?>

2. В новом окне открываются все ссылки из слоя "node", то есть из слоя с контентом, а не из меню, футера итп:
drupal_add_js("\$(document).ready(function(){\$(\"div.node a[href^=http:]\").each(function(){if(this.host!=\"" . $_SERVER['HTTP_HOST']. "\"){\$(this).attr(\"target\",\"_blank\");}});});", "inline");
?>

3. В новом окне открываются все ссылки, плюс справа от внешних ссылок отображается иконка, символизирующая новое окно:
drupal_add_js("\$(document).ready(function(){\$(\"a[href^=http:]\").each(function(){if(this.host!=\"" . $_SERVER['HTTP_HOST']. "\"){\$(this).attr(\"target\",\"_blank\");$(this).after(\"\");}});});", "inline");
?>, где 1.jpg – и есть та самая иконка.

4. В новом окне открываются все ссылки, плюс внешние ссылки выделяются особым стилем:
drupal_add_js("\$(document).ready(function(){\$(\"a[href^=http:]\").each(function(){if(this.host!=\"" . $_SERVER['HTTP_HOST']. "\"){\$(this).attr(\"target\",\"_blank\");$(this).addClass(\"extLink\");}});});", "inline");
?>, где extLink – описание класса, который применится ко всем внешним ссылкам.

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

P.S. Голый код, который не обязательно использовать в Друпале, выглядит так:

$(document).ready(function(){
$(function(){$("a[href^=http:]").each(function(){if(this.host!="example.com")$(this).attr("target","_blank")})})
});

?>

Тэги php использованы только для того чтобы подсветить синтаксис, иначе форум не корректно порежет этот пример. Example.com нужно заменить на свой хост.

P.P.S По мотивам вот этой статьи привожу пример того, как сделать так, чтобы юзеры сами могли выбирать открывать внешние ссылки в новом окне или в текущем.

1. Предварительная подготовка.

Необходимо включить модуль Profile, который входит в ядро пятого друпала, и с его помощью добавить в профиль пользователя поле типа checkbox, назовем его "profile_ext_links_in_new_window" и дадим ему заголовок "Открывать внешние ссылки в новом окне".

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

2. Открывать внешние ссылки в новом окне или нет?

В page.tpl.php в тэгах < head > < /head > после подключения библиотеки jquery вставьте такой код:
global $user;
$req = db_query("SELECT v.value FROM {profile_values} v INNER JOIN {profile_fields} f
ON f.fid = v.fid WHERE f.name = 'profile_ext_links_in_new_window' AND uid = " . $user->uid);
$res = db_fetch_object($req);
if($res->value)
{
?>

<script type="text/javascript">
$(document).ready(function(){
   $("a[href^=http:]").each(function(){
           if(this.host!="<? php print $_SERVER['HTTP_HOST'];? >"){
               $(this).attr("
target","_blank");
               $(this).after("
<img src=1.jpg>");//эту строчку можно убрать, она после внешней ссылки выводит картинку
           }    
       })
});

/*
Обратите внимание на то, что в строке php print $_SERVER['HTTP_HOST'];? > я поставил 2 лишних пробела, чтобы текст скрипта здесь корректно отобразился, их нужно убрать.
*/
}
?>
Всё, теперь если в профиле отмечена галка "Открывать внешние ссылки в новом окне", то все внешние ссылки принудительно будут открываться в новом окне, если галка не установлена, то ссылка будет открываться в зависимости от значения атрибута target.

Нагрузка на сервер минимальна, делается всего-лишь один дополнительный запрос к базе. При желании эту нагрузку можно еще снизить убрав INNER JOIN из запроса. Для этого надо в таблице profile_fields посмотреть fid поля profile_ext_links_in_new_window, в моем случае он равен 11 и заменить строчку
$req = db_query("SELECT v.value FROM {profile_values} v INNER JOIN {profile_fields} f
ON f.fid = v.fid WHERE f.name = 'profile_ext_links_in_new_window' AND uid = " . $user->uid);
?>
строчкой:
$req = db_query("SELECT value FROM {profile_values} WHERE fid = 11 AND uid = " . $user->uid);
?>
11, разумеется, нужно заменить на ваш fid.

Комментарии

Аватар пользователя emzi emzi 27 июня 2007 в 19:05

Классно придумано Smile
На этот скрипт еще полезно подвесить счетчик переходов на внешние, что-то типа:

$(function(){$("a[href^=http:]").each(
  function(){
    if(this.host!="example.com") {
      $(this).attr("target","_blank");
      $(this).bind("click", function() {
        new Image().src="/node/100?"+this.href;
      });
    }})})

"node/100" - это условная точка отсчета для внешних ссылок. Анализируя запросы этой ноды с параметром, можно будет судить о том, куда и откуда уходят с вашего сайта

Аватар пользователя Ромка Ромка 28 июня 2007 в 11:04

Классно придумано Smile
На этот скрипт еще полезно подвесить счетчик переходов на внешние, что-то типа:

Или так:

drupal_add_js("\$(document).ready(function(){\$(function(){\$(\"a[href^=http:]\").each(function(){if(this.host!=\"" . $_SERVER['HTTP_HOST']. "\")\$(this).attr(\"target\",\"_blank\");$(this).after(\"\");$.get(\"" . base_path() . "c.php\", { nid: \"" . $node->nid . "\" } );})})});", "inline");
?>

То есть по клику по ссылке открываем ее в новом окне и нид ноды передаем скрипту c.php, который делает с ним, что посчитает нужным программист.

Аватар пользователя Ромка Ромка 28 июня 2007 в 10:30

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

Аватар пользователя emzi emzi 28 июня 2007 в 11:01

On чт, 28/06/2007 - 08:01 Razgonka.ru says:
У меня прямо противоположное мнение.
Здесь мы обсуждаем техническую сторону вопроса, не так ли? Хотелось бы знать, что Вам не понравилось с точки зрения реализации?

Аватар пользователя emzi emzi 28 июня 2007 в 11:04

On чт, 28/06/2007 - 09:19 Ромка says:
не знаю, как у других, у меня код примеров вылезает далеко направо, неудобно читать.

Аватар пользователя Ромка Ромка 28 июня 2007 в 11:20

не знаю, как у других, у меня код примеров вылезает далеко направо, неудобно читать

У меня тоже, только я не знаю как это исправить. По идее Друпал сам должен расставить переносы строк как надо...

Аватар пользователя Ромка Ромка 29 июня 2007 в 10:41

Блин, косяк. Включил эту опцию у себя в профиле. На главной странице ява-скрипт инклюдится несколько раз, так как вызов его прописан в node.tpl.php, я изначально не продумал такой варинт. Исправить проблему предлагаю так: из node.tpl.php скрипт удаляем, а в page.tpl.php в тэг head после подключения jquery.js и после проверки включена ли в профиле юзера соответствующая опция надо вставть код вида:

$(document).ready(function(){
$("a[href^=http:]").each(function(){
if(this.host!=" php print $_SERVER['HTTP_HOST'];? >"){
$(this).attr("target","_blank");
$(this).after("");//эту строчку можно убрать, она после внешней ссылки выводит картинку
}
});
});
?>
это не пхп код, то есть его либо надо вставлять вне тэгов , либо cделать print "этот код"/

Обратите внимение на то, что я в строчке php print $_SERVER['HTTP_HOST'];?> поставил 2 лишних пробела, чтобы фильтр друпала нормально подсветил код, эти пробелы в реальных условиях нужно убрать.

Я исправил первый пост с учетом этого багофикса...

Аватар пользователя Onza Onza 29 июня 2007 в 11:00

Включил опцию в профиле, но она не работает корректно... Иногда внутренние линки в новом, иногда наоборот - внешние в том же...

Аватар пользователя Ромка Ромка 29 июня 2007 в 11:04

И еще один косячище. У меня в ИЕ теперь абсолютно все ссылки открываются в новом окне, полагаю этот от того, что в пятом Друпале установлена не последняя версия jquery, по этому её нужно обновить (заменить файл misc/jquery.js на последнюю версию скачанную с jquery.com)