Xpoint
   [напомнить пароль]

Обработка событий в XBL

2005-05-29 16:44:20 [обр] Станислав Полтавский [досье]

Добрый, всем, день.
Заинтересовался созданием своих компонентов в XBL. Но не все понятно.
Может кто-нибудь поскажет, как создать и возбудить собственное событие в XBL.
Из документации понятно, как работать со стандартными событиями. Типа onmouseup:
<handlers>
  <handler event="mouseup" action="alert(1)"/>
</handlers>
А как создать собственное событие?
Аналог того, что я хочу есть майкрософтовских htc-компонентах и выглядит примерно так:
...
<EVENT NAME="onMyEvent" ID="onMyEvent" />
<script>
function MyFunc(someData)
{
   var oEvent = createEventObject();
   oEvent.data= someData;
   onMyEvent.fire(oEvent);
}
</script>
...
Может ли мне кто-то подсказать, как это сделать в XBL?

Заранее благодарю,
Станислав Полтавский

спустя 10 часов [обр] Владимир Палант [досье]

Создание собственного события:

var event = document.createEvent("Events");
event.initEvent("MyEvent", true, true);
this.dispatchEvent(event);

Обрабочик, соответственно:

<handler event="MyEvent" action="alert(1)"/>

Не совсем, правда, уверен, что это сработает для нестандартного события. Если нет, то придётся добавлять обработчик вручную в конструкторе через addEventListener().

спустя 3 минуты [обр] Владимир Палант [досье]
Пример, который выплюнул мне Google: http://blogs.acceleration.net/birdman/archive/2004/10/04/321.aspx
спустя 7 часов [обр] Станислав Полтавский [досье]

Владимир, спасибо за ответ.
Однако, у меня не возникло полного понимания.
Согласно приведенному примеру я написал это:
<implementation>
   <method name="someMethod">
      <body>
         <![CDATA[
            this.fireEvent("oncreate", this);
         ]]>
      </body>
   </method>
   <method name="fireEvent">
      <parameter name="name"/>
      <parameter name="target"/>
      <body>
         <![CDATA[
            var oEvent = document.createEvent("Events");
            oEvent.initEvent(name, true, true);
            target.dispatchEvent(oEvent);
         ]]>
      </body>
   </method>
</implementation>

Событие взрывается, но не так, как я ожидал.

А именно, его можно перехватить так:
<handlers>
   <handler event="oncreate">
      <![CDATA[
         alert(777);
      ]]>
   </handler>
</handlers>

А мне хотелось бы так:
<element id="x1" oncreate="alert(999);" />

Возможно ли это в XBL?
Ведь это вполне законное желание.

Станислав Полтавский

спустя 1 час 49 минут [обр] Владимир Палант [досье]
  1. "on" — часть названия события исключительно в IE. По стандарту события называются mouseup, click, соответственно и ваше событие должно называться create.
  2. Атрибуты типа onclick определены только для стандартных событий. Если вы хотите такое же для собственного события, вы должны сделать его сами. Пример (в основном скопировано из исходников Xpoint Sidebar):
<implementation>
  <constructor>
  <![CDATA[
    if (this.hasAttribute('oncreate'))
      this.oncreate = this.getAttribute('oncreate');
  ]]>
  </constructor>
  <property name="oncreate"
      onget="return this._createInlineHandler">
    <setter>
    <![CDATA[
      if (typeof val == "function")
        this._createInlineHandler = val;
      else if (typeof val == "string")
        this._createInlineHandler = new Function('event', val);
      else
        this._createInlineHandler = null;
    ]]>
    </setter>
  </property>
</implementation>
<handlers>
  <handler event="create">
  <![CDATA[
    if (this._createInlineHandler)
      this._createInlineHandler(event);
  ]]>
  </handler>
  <handler event="DOMAttrModified">
  <![CDATA[
    if (event.target == this && event.attrName == 'oncreate')
      this.oncreate = event.newValue;
  ]]>
  </handler>
</handlers>
спустя 1 час 55 минут [обр] Станислав Полтавский [досье]

Спасибо, Владимир.
Этот пример работает. Однако у меня вызывает недоуменение, что разработчики не реализовали одну из самых необходимых вещей.
Похоже, что просто JavaScript реализован в XML.

Станислав Полтавский

спустя 1 час 27 минут [обр] Владимир Палант [досье]
"Одна из самых необходимых вещей" — автоматический маппинг между атрибутами и обработчиками событий? Спасибо, лучше не надо, пусть программист сам решает, что он хочет делать с атрибутами. В смысле отделения разметки от логики приложения инлайновые обработчики событий вообще нежелательны и поддерживаются лишь для совместимости с HTML 2.0. Заметьте, что для более новых типов событий, к примеру для того же DOMAttrModified, нет атрибута onDOMAttrModified — нужно использовать addEventListener() или аналогичный способ назначения обработчиков.
спустя 50 минут [обр] Станислав Полтавский [досье]

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

Пример такого извращения вы привели двумя постами выше. Пожалуйста, не принимайте лично к себе "извращения".
Этот пример работает, но посмотрите, сколько кода нужно писать, чтобы определить и вызвать простое событие.
А теперь сравните, насколько удобней работать с событиями в Microsoft HTC. Пример в первом посте.

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

Я хочу лишь сказать, что критерий "В смысле отделения разметки от логики приложения инлайновые обработчики событий вообще нежелательны" мне непонятен. Кому нежелателен? Почему? Если "инлайновые обработчики событий" помогают мне быстрее решить задачу, уменьшить шансы сделать ошибку, а следовательно быстро разработать приложение и заработать больше денег, "инлайновые обработчики событий" есть благо.

Прошу прощения, если где-то был резок.

Станислав Полтавский

спустя 3 часа 26 минут [обр] Владимир Палант [досье]

Инлайновые обработчики событий помогают вам быстро написать код, который будет тяжело поддерживать, поскольку логика приложения идёт вперемешку с разметкой документа. Старые стандарты выросли без какого-либо настоящего планирования, там об этом не заботились. В более новых продвигают идею разделения HTML и JavaScript (а также отделения отображения от разметки с помощью CSS).

Но, если нужно, вовсе не обязательно писать столько кода для каждого атрибута. Вот такой несложный класс для Gecko универсально реализует маппинг атрибутов в обработчики событий:

function IntrinsicEventHandler(element)
{
  var handler = this;

  var initHandlers = function(eventName) {
    element.__defineGetter__(eventName, function(a) {
      return handler[eventName];
    });
    element.__defineSetter__(eventName, function(val) {
      if (typeof handler[eventName] == 'function')
        this.removeEventListener(eventName.replace(/^on/, ''), handler[eventName], false);

      handler[eventName] = null;
      if (typeof val == "function")
        handler[eventName] = val;
      else if (val)
        handler[eventName] = new Function('event', val);

      if (typeof handler[eventName] == 'function')
        this.addEventListener(eventName.replace(/^on/, ''), handler[eventName], false);
    });
    element[eventName] = element.getAttribute(eventName);
  };

  var args = IntrinsicEventHandler.arguments;
  for (var i = 1; i < args.length; i++)
    initHandlers('on' + args[i]);

  element.addEventListener('DOMAttrModified', function(e) {
    if (e.attrName.indexOf('on') == 0 && e.attrName in handler)
      element[e.attrName] = e.newValue;
  }, false);
}

Использовать можно как в XBL, так и в обычном коде:

new IntrinsicEventHandler(element, 'create', 'destroy', 'DOMAttrModified');

Для каждого события из списка в element создаётся свойство on<событие>, которое содержит обработчик для этого события (или null). Изменения одноимённого атрибута автоматически переносятся в это свойство. То есть, всё как в HTML.

спустя 4 часа 20 минут [обр] Станислав Полтавский [досье]

Большое спасибо, Владимир.
Вы очень мне помогли. Я использовал часть вашего кода в своем XBL элементе.

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

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

Не совсем понимаю тяжесть поддержки такого кода:

<script>
   function someFunc(){
      ...
   }
</script>

<element onpopup="someFunc"/>

Или такого:

   <element onpopup="alert('Popup')"/>

А такой код, по вашему, поддерживать легче?

<window onload="doOnLoad();" >
   <script>
      function doOnLoad(){
         var oElem = document.getElementById("e1");
         oElem.addEventListener("onpopup", someFunc, true);
      }
   </script>

   <element id="e1" />
</window>

А какой код лучше читается?
А если вы через три месяца будете читать собственный код, то код какого рода будет вами вспомнен быстрее?

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

Старые стандарты выросли без какого-либо настоящего планирования, там об этом не заботились. В более новых продвигают идею разделения HTML и JavaScript (а также отделения отображения от разметки с помощью CSS).

Если честно, то я не ощущаю в Mozilla какого-то супер-планирования. Скорее супер-энтузиазм. А "старые стандарты" продержались чуть ли не полвека и чтобы подвинуть их нужно нечто большее чем, может правильная, но недостаточная идея разделения.

Вообще, вы сами сказали это слово: "продвигают". Не поддавайтесь софтверным маркетологам. Они каждый год продвигают новые потребности. Ярким примером является технология AJAX. Грамотные люди уже лет пять пользуются XMLHTTP, однако только сейчас узнали, что используют модную технологию AJAX, за продвижение которой взялись маркетологи в этом году.

Еще раз спасибо, Владимир.

Станислав Полтавский

Powered by POEM™ Engine Copyright © 2002-2005