Приветствую всех читающих. :D

Дебажил свой экстеншин и заметил в нем аномальное поведение xbl.
По мануалу - при установке связки должен вызваться constructor, а при удалении - destructor.
На практике - конструктор срабатывает, деструктор нет. Если связку не убирать с элемента, то при закрытии браузера деструктор срабатывает. Если связаный элемент удалить (типа removeChild), то связка с него не отваливается и деструктор не вызывается (т.е. элемент пропадает, браузер закрываешь, деструктор не вызывается).

Собственно хотел поинтересоваться - это баг ? Можно как-то сделать чтобы деструктор вызывался автоматический ?

Так, гуглом установлено что это баг - https://bugzilla.mozilla.org/show_bug.cgi?id=230086 :( очень древний.

Можно попробовать вынести деструктор в метод и вызывать самостоятельно, но это очень неудобно и не всегда уследишь + как быть с расширяемыми XBL ? (т.е. один - расширение второго) ?

Мысль пришла по поводу слежения - если попробовать слушать DOMNodeRemoved и в нем фильтровать свои элементы с xbl, дергать у них свой метод destroy или что-то подобное ? Такое вообще реально ? :)

Codeblight пишет

Мысль пришла по поводу слежения - если попробовать слушать DOMNodeRemoved и в нем фильтровать свои элементы с xbl, дергать у них свой метод destroy или что-то подобное ? Такое вообще реально ?

Почему бы и нет ?

Просто подумалось что медленно будет работать.  Вот примерно что получилось:

Функция, рекурсивно обрабатывающая стандартные деструкторы:

Выделить код

Код:

function xbl_destructor_bugfix(event)
	{
		if (event.originalTarget.nodeName == 'opwidget')
		{
			// ok, we needs call desructor recursion
			// but have some problems... $)

			var binded_to = document.defaultView.getComputedStyle(event.originalTarget, null).getPropertyValue('-moz-binding');
			var get_url = binded_to.match(/url\((\'|\")?(.*?)\1?\)/mi);
			if (get_url != null)
			{
				// current binding founded
				var bind_params = get_url[2].match(/([^\#]+)#(.*)/mi);
				if (bind_params != null)
				{
					var bind_to_url = bind_params[1];
					var bind_to_section =  bind_params[2];

					var ajax = Components.classes['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance(Components.interfaces.nsIXMLHttpRequest);
					ajax.open('GET', bind_to_url, false);
					ajax.send(null);
					
					if ((ajax.responseXML != null) && (ajax.responseXML.documentElement.nodeName != 'parsererror'))
					{
						// XBL xml successful loaded
						var xbl_destructor_recursion_removal = function(xbl_xml, section)
						{
							var xpe = new XPathEvaluator();
							var nr = function (prefix)
							{
								var ns =
								{
									html : 'http://www.w3.org/1999/xhtml',
									xul : 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul',
									xbl : 'http://www.mozilla.org/xbl'
								};
								return ns[prefix] || null;
							};

							var result = xpe.evaluate('/xbl:bindings/xbl:binding[@id=\'' + section + '\']', xbl_xml, nr, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
							if (result.singleNodeValue)
							{
								// section founded
								var section_node = result.singleNodeValue;
								var extension_of = (section_node.hasAttribute('extends') ? section_node.getAttribute('extends') : '');
								result = xpe.evaluate('xbl:implementation/xbl:destructor', section_node, nr, XPathResult.FIRST_ORDERED_NODE_TYPE, null);

								if (result.singleNodeValue)
								{
									event.originalTarget.destroy = function(){ eval(result.singleNodeValue.textContent); };
									event.originalTarget.destroy.call(event.originalTarget);
								}
								
								// extexsions from other files not supported, you can modify this code for other files 8-)
								if ((extension_of) && (extension_of.indexOf('#') == 0)) xbl_destructor_recursion_removal(xbl_xml, extension_of.substring(1));
							}
						};

						// try to remove
						xbl_destructor_recursion_removal(ajax.responseXML.documentElement, bind_to_section);
					}
				}
	        	}
		}
	}

К документу прицепляется так:

Выделить код

Код:

document.addEventListener('DOMNodeRemoved', xbl_destructor_bugfix, false);

Сразу говорю что этот вариант с ограничениями:
1. для ускорения фильрации своих xbl вставил

if (event.originalTarget.nodeName == 'opwidget')

- тут можно вписать свое или вообще это условие убрать (должно начать тормозить).
2. расширения xbl из разных файлов не поддерживаются (у меня все водном файле - под это и писал).
3. у ваших объектов не должно быть метода destroy (можно переименовать в любое другое на свой вкус).


работает ;)