Логин:   Пароль:




Новости
Рассылки
Форум
Поиск


Java
- Апплеты
- Вопрос-ответ
- Классы
- Примеры
- Руководства
- Статьи
- IDE
- Словарь терминов
- Скачать

Мобильная Java
- Игры
- Примеры
- Статьи
- WAP, WML и пр.

JavaScript
- Вопрос-ответ
- Примеры
- Статьи

Веб-мастеринг
- HTML
- CSS
- SSI

Разминка для ума
Проекты
Книги
Ссылки
Программы
Юмор :)




Rambler's Top100

JavaScript: СтатьиКонтекстное меню для Netscape Navigator и Internet Explorer

Контекстное меню для Netscape Navigator и Internet Explorer

Почему-то на сайтах, посвященных программированию на JavaScript, традиционно считается, что это невозможно, так как Netscape по щелчку правой клавишей мыши создает собственное всплывающее меню. Попробуем развеять это заблуждение. Дело в том, что выпадающее меню в Netscape Navigator 7.1 и выше версии (ниже версии нет в наличии - если код корректно работает в версии Netscape ниже 7.1 - пожалуйста напишите мне), можно отключить с помощью знакомой инструкции:


 <body oncontextmenu="return false;">
, но как же создать выпадающее меню, если в Netscape следующий код (работающий в Internet Explorer):

 <body oncontextmenu="myfunction(); return false;">
не работает, то есть - функция вызывается, но в Nescape Navigator возникает выпадающее меню, поверх создаваемого нами в функции myfunction. Как же обойти это ограничение? Я нашел такое решение:

 <body oncontextmenu="return myfunction()">

Как вы вполне можете догадаться, функция "myfunction()" в конце своего исполнения возвращает результат - return false, что с точки зрения Netscape Navigator считается корректным. Но только вот такой код не считается корректным у Internet Explorer. Что поделаешь? Война браузеров! Придется воспользоваться таким интересным приемом, как условная трансляция (надеюсь, что подобрал словосочетание правильное, по аналогии с условной компиляцией в Си) браузера Internet Explorer. Дело в том, что Microsoft © позаботилась о создании специальных конструкций, которые для остальных браузеров выглядят как комментарий. С помощью этих конструкций можно создать достаточно сложные ветвления кода. Попробуем создать ветвление кода на основе этих самых конструкций и разберем его чуть ниже.


 <script language="JavaScript" type="text/javascript">
 <!--

  /*@cc_on
   @if( true )
    document.write( "<body oncontextmenu=\"myfunction(); return false;\">" );
   @else*/
    document.write( "<body oncontextmenu=\"return myfunction();\">" );
   /*@end
  @cc_off @*/
 
 //-->
 </script>

Разберем первую эту часть скрипта подробно. Вначале определяется тип браузера пользователя, эта часть нам не интересна - такие скрипты можно найти в Internet повсюду. Для начинающих лучше всего воспользоваться редактором с подсветкой синтаксиса. Итак первая интересующая нас инструкция: "/*@cc_on" - это инструкция начала "условной трансляции", обратить внимание стоит только на ее начало - "/*" - это обычный комментарий. Internet Explorer выше пятой версии разбирает даже комментарии, и ищет директивы "условной трансляции" (большой брат следит за тобой!). Теперь присмотримся к следующей строке - тут указана на первый взгляд странная строка: "@if( true )" - условие, которое выполнится в любом случае! Необходимость этого условия не кажется очевидной, но на самом деле все очень просто, если Internet Explorer прочтет эту инструкцию - он выполнит код, который предназначен только ему одному, а строку идущую после директивы "@else*/" пропустит. А теперь предположим, что условия "@if( true ) ... @else" нет - что получится? Internet Explorer выполнит сразу две инструкции - и мы получим в документе сразу два <body> с разными параметрами! Не очень приятная перспектива. Последняя инструкция @cc_off @*/ завершает "условную трансляцию". Таким образом мы получили переносимый код, подходящий для браузеров на основе движка Internet Explorer (Avant, Maxthon, etc...) и движка Gecko (Netscape Navigator, Mozilla, Mozilla Firefox, Mozilla Firebird, etc...).

Создадим примитивный лист стилей (наша задача создать не красивый, а понятный код - украсить его вы можете сами! Наш лист стилей:


 <style type="text/css">
 <!--
	.hidemenu {
		  display: none;
		  position: absolute;
		}
	.showmenu {
		display: block;
		position: absolute;
	}
 //-->
 </style>

Он отвечает только за отображение и сокрытие контекстного меню, что нам собственно и надо. Теперь надо определить координаты курсора в момент щелчка правой клавиши мыши по документу. Основная проблема заключается в том, что для Netscape Navigator возникает такая проблема, обработчик события event.onmousedown - перекрывает обработчик, заданный в body (в общем-то вполне логично, поскольку event задается относительно окна, а не документа, как в body). И опять возникает ненавистное браузерное контекстное меню. Я решил эту проблему таким образом (если кто знает решение проще - пришлите мне письмо):


 if( document.all ) {
 
 } else if( document.getElementById ) {
  document.captureEvents( Event.MOUSEMOVE );
  document.onmousemove = getCoord;
 }

Я стал отслеживать каждое передвижение мыши на экране и записывать координаты курсора в глобальные переменные:


 var mouseX;
 var mouseY;

 function getCoord( event ) {
   mouseX = event.pageX;
   mouseY = event.pageY;
 }

Теперь соберем саму функцию отображения меню:


 function myfunction() {     
  if( document.all ) {
   if( event.button == 2 || event.button == 3 ) {
    if( !document.all.contextmenu )
     return;
    var menu = document.all.contextmenu;
    menu.style.left = event.offsetX;
    menu.style.top = event.offsetY;
    menu.className = menuState ? "hidemenu" : "showmenu";
    menuState = !menuState;
   }
  } else if ( document.getElementById ) {
   if( !document.getElementById( "contextmenu" ) )
    return;
   var menu = document.getElementById( "contextmenu" );
   menu.style.left = mouseX;
   menu.style.top = mouseY;
   menu.className = menuState ? "hidemenu" : "showmenu";
   menuState = !menuState;
   return false;
   }
  }

Функция не требует особых навыков в JavaScript, чтобы в ней разобраться. Скажу лишь вкратце, устанавливается положение меню на основе координат курсора с ветвлением на два браузера. Разница лишь в том, что Internet Explorer получает координаты из события event, а Netscape Navigator из глобальных переменных. Если вы правильно собрали скрипт - у вас должно получиться нечто подобное:


<html>
 <head>
  <meta http-equiv="Content-type" content="text/html; charset=Windows-1251">
  <title>Context menu</title>
  <style type="text/css">
  <!--
	.hidemenu {
		  display: none;
		  position: absolute;
		}
	.showmenu {
		display: block;
		position: absolute;
	}
  //-->
  </style>

  <script language="JavaScript" type="text/javascript">
  <!--
    if( document.all ) {
      document.onmousedown = myfunction;
    } else if( document.getElementById ) {
      document.captureEvents( Event.MOUSEMOVE );
      document.onmousemove = getCoord;
    }

    var mouseX;
    var mouseY;
    var menuState = false;
    
    function getCoord( event ) {
      mouseX = event.pageX;
      mouseY = event.pageY;
    }

    function myfunction() {     
     if( document.all ) {
      if( event.button == 2 || event.button == 3 ) {
	if( !document.all.contextmenu )
	  return;
	var menu = document.all.contextmenu;
	menu.style.left = event.offsetX;
	menu.style.top = event.offsetY;
	menu.className = menuState ? "hidemenu" : "showmenu";
	menuState = !menuState;
      }
     } else if ( document.getElementById ) {
      if( !document.getElementById( "contextmenu" ) )
	return;
      var menu = document.getElementById( "contextmenu" );
      menu.style.left = mouseX;
      menu.style.top = mouseY;
      menu.className = menuState ? "hidemenu" : "showmenu";
      menuState = !menuState;
      return false;
     }
    }    
    
  //-->
  </script>

  <script language="JavaScript" type="text/javascript">
  <!--
   /*@cc_on
    @if( true )
     document.write( "<body oncontextmenu=\"myfunction(); return false;\">" );
    @else*/
     document.write( "<body oncontextmenu=\"return myfunction();\">" );
   /*@end
   @cc_off @*/ 
  //-->
  </script>

<div id="contextmenu" class="hidemenu" style="background-color: Yellow;">
 <span><a href="javascript: void( 0 )">Первый пункт меню</a></span><br>
 <span><a href="javascript: void( 0 )">Второй пункт меню</a></span><br>
 <span><a href="javascript: void( 0 )">Третий пункт меню</a></span>
</div>

</body>
</html>

Для тех же, кто желает "погорячее" привожу код, полностью основанный на "условной трансляции" Microsoft ©. Комментировать код не буду - изложенного выше материала вполне достаточно, чтобы разобраться в нем самому.


<html>
 <head>
  <meta http-equiv="Content-type" content="text/html; charset=Windows-1251">
  <title>Context menu</title>
  <style type="text/css">
  <!--
	.hidemenu {
		  display: none;
		  position: absolute;
		}
	.showmenu {
		display: block;
		position: absolute;
	}
  //-->
  </style>

  <script language="JavaScript" type="text/javascript">
  <!--
    var menuState = false;

    /*@cc_on
     @if( true )
      document.onmousedown = myfunction;
     @else*/
      var mouseX;
      var mouseY;

      if( document.getElementById ) {
	document.captureEvents( Event.MOUSEMOVE );
	document.onmousemove = getCoord;
      }

      function getCoord( event ) {
        mouseX = event.pageX;
        mouseY = event.pageY;
      }
     /*@end
    @cc_off @*/

    function myfunction() {
    /*@cc_on
      @if( true )
	if( event.button == 2 || event.button == 3 ) {
	  if( !document.all.contextmenu )
	    return;
          var menu = document.all.contextmenu;
	  menu.style.left = event.offsetX;
	  menu.style.top = event.offsetY;
	  menu.className = menuState ? "hidemenu" : "showmenu";
  	  menuState = !menuState;
        }
      @else*/
       if( !document.getElementById( "contextmenu" ) )
	return;
      var menu = document.getElementById( "contextmenu" );
      menu.style.left = mouseX;
      menu.style.top = mouseY;
      menu.className = menuState ? "hidemenu" : "showmenu";
      menuState = !menuState;
      return false;
      /*@end
      @cc_off @*/
    }

    
  //-->
  </script>

  <script language="JavaScript" type="text/javascript">
  <!--
   /*@cc_on
    @if( true )
     document.write( "<body oncontextmenu=\"myfunction(); return false;\">" );
    @else*/
     document.write( "<body oncontextmenu=\"return myfunction();\">" );
   /*@end
   @cc_off @*/ 
  //-->
  </script>

  <div id="contextmenu" class="hidemenu" style="background-color: Yellow;">
   <span><a href="javascript: void( 0 )">Первый пункт меню</a></span><br>
   <span><a href="javascript: void( 0 )">Второй пункт меню</a></span><br>
   <span><a href="javascript: void( 0 )">Третий пункт меню</a></span>
  </div>

 </body>
</html>

С точки зрения производительности такой код лучше, поскольку браузерам, на основе движка Gecko, не требуется проверять дополнительные условия. И в завершение этой статьи хочу привести пример создания контекстного меню с помощью технологий, встроенных в Internet Explorer. По сути создается отдельное немодальное окно на основе полученного кода. Этот код не может использовать внешние таблицы стилей (даже встроенные в документ!), поэтому вводить данные о стиле придется контекстно к элементу.


 <html>
 <head>
  <title>Microsoft context menu</title>  
  <script language="JavaScript" type="text/javascript">
  <!--

  var winPopup = window.createPopup();

  var mWidth = 247;
  var mHeight = 67;

  function goContext()
  {  
    var winPopupBody = winPopup.document.body;

    winPopupBody.innerHTML = winContext.innerHTML;
    winPopup.show( event.offsetX, event.offsetY, mWidth, mHeight, document.body );      
    document.body.onmouseup = closePopup;
  }

  function closePopup()
  {
    winPopup.hide();
  }

  //-->
  </script>
 </head>
 <body oncontextmenu="goContext(); return false">
  <div id=winContext style="DISPLAY: none">  
<div id="cells">
<div onmouseover="this.style.background='#ffffff'" style="BORDER-RIGHT: black 1px solid; PADDING-RIGHT: 2px; BORDER-TOP: white 1px solid; PADDING-LEFT: 

10px; FONT-WEIGHT: bold; FONT-SIZE: 8pt; BACKGROUND: #cccccc; LEFT: 0px; PADDING-BOTTOM: 2px; BORDER-LEFT: white 1px solid; CURSOR: hand; COLOR: black; 

PADDING-TOP: 2px; BORDER-BOTTOM: black 1px solid; FONT-FAMILY: verdana; POSITION: relative; TOP: 0px; HEIGHT: 20px" 
onclick="parent.oIframe.location.href='#';" onmouseout="this.style.background='#cccccc'">  Главная 

страница</div>
<div onmouseover="this.style.background='#ffffff'" style="BORDER-RIGHT: black 1px solid; PADDING-RIGHT: 2px; BORDER-TOP: white 1px solid; PADDING-LEFT: 

10px; FONT-WEIGHT: bold; FONT-SIZE: 8pt; BACKGROUND: #cccccc; LEFT: 0px; PADDING-BOTTOM: 2px; BORDER-LEFT: white 1px solid; CURSOR: hand; COLOR: black; 

PADDING-TOP: 2px; BORDER-BOTTOM: black 1px solid; FONT-FAMILY: verdana; POSITION: relative; TOP: 0px; HEIGHT: 20px" 
onclick="parent.oIframe.location.href='#';" onmouseout="this.style.background='#cccccc'">  Какое-то 

действие</div>
<div onmouseover="this.style.background='#ffffff'" style="BORDER-RIGHT: black 1px solid; PADDING-RIGHT: 2px; BORDER-TOP: white 1px solid; PADDING-LEFT: 

10px; FONT-WEIGHT: bold; FONT-SIZE: 8pt; BACKGROUND: #cccccc; LEFT: 0px; PADDING-BOTTOM: 2px; BORDER-LEFT: white 1px solid; CURSOR: hand; COLOR: black; 

PADDING-TOP: 2px; BORDER-BOTTOM: black 1px solid; FONT-FAMILY: verdana; POSITION: relative; TOP: 0px; HEIGHT: 20px" 
onclick="parent.oIframe.location.href='#';" onmouseout="this.style.background='#cccccc'">  Еще что-то 

делаем</div>
</div>
</div>
    
 </body>
</html>

Вся сложность создания дочернего окна с помощью технологий Internet Explorer - это необходимость внесения всего кода в новое окно, включая JavaScript и CSS. Результат чего можно видеть в непомерно разросшихся аттрибутах div'ов. Пример взят из MSDN и адаптирован мной для лучшей читаемости кода. Разберем подробнее. Итак, первое действие window.createPopup() - создает дочернее немодальное окно, но не отображает его на экране. Программистам, знакомым с WinAPI хотя бы поверхностно - объяснять это не надо. Далее определяем значения длины и высоты нашего меню (можно автоматизировать этот процесс, но это будет уже лишний код - сейчас главное понять как создается меню) - это переменные mWidth и mHeight. Следующий, интересующий нас оператор, это winPopup.document.body; - мы получаем ссылку на тело документа нового окна. Далее - получаем код из div'a с идентификатором winContext и присваиваем его телу документа созданного окна. Далее - просто отображаем новое окно - winPopup.show. Параметры: координата окна по горизонтали, координа окна по вертикали, ширина окна, высота окна, ссылка на документ-владелец нового окна.

На этом считаю статью законченной, если будут вопросы - пишите на e-mail: [email protected]

Вячеслав Шуранов aka Чайник (DUmmY)


Д. Гудман
"JavaScript и DHTML. Сборник рецептов. Для профессионалов"
Подробнее>>
Заказать>>


Сергей Дунаев
"Java для Internet в Windows и Linux"
Подробнее>>
Заказать>>

Узнай о чем ты на самом деле сейчас думаешь тут.


[an error occurred while processing this directive]



Apache Struts 2.0.11
Apache MyFaces Trinidad Core 1.2.3.
Sun переводит мобильные устройства с Java ME на Java SE
Хакерская атака!