Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   Общий предок (https://javascript.ru/forum/events/18267-obshhijj-predok.html)

trikadin 23.06.2011 20:12

Общий предок
 
Как получить общего предка двух элементов (в DOM'е)? Есть простые способы, или нужно самому писать?

Sweet 23.06.2011 21:03

нужно самому писать

Aetae 23.06.2011 21:07

Если по классу как-то так наверное, набросок:
function parent(class1,class2){
  var e=document.getElementsByClassName(class1)[0];
  while((e=e.parentNode)&&!e.getElementsByClassName(class2)[0]);
  return e
}

trikadin 23.06.2011 21:27

Не удивлён, однако...

trikadin 23.06.2011 21:30

Нет классов. Два абсолютно любых элемента. С какой стороны лучше подступиться?

Sweet 23.06.2011 21:59

Я думаю, общий смысл должен быть таким:
function mutualParent(elem1, elem2){
  var test;
  while(elem1 !== document.body){
    elem1 = elem1.parentNode;
    test = elem2;
    while(test !== document.body){
      test = test.parentNode;
      if(test === elem1) return test;
    };
  };
  return null;
};

Slawaq 23.06.2011 22:33

от, только толсто, много циклов, но работает
<body>
<div>
    <div id="multi-parent">
        <div>
            <div id="firstChild"></div>
        </div>
        <div>
            <div>
                <div id="secondChild"></div>
            </div>
        </div>
    </div>
</div>
<script type="text/javascript">
var $ = function(n){return document.getElementById(n);}
var getPerent = function(fe,se){
    var body = document.getElementsByTagName("body")[0];
    var parentF = fe.parentNode;
    var parentS = se.parentNode;
    var arrayParantsF = [];
    var arrayParantsS = [];
    while(true){
        if(parentF!=body){
            arrayParantsF[arrayParantsF.length]=parentF;
            parentF = parentF.parentNode;
        }else{
            break;
        }
    }
    while(true){
        if(parentS!=body){
            arrayParantsS[arrayParantsS.length]=parentS;
            parentS = parentS.parentNode;
        }else{
            break;
        }
    }
    for(i=0;i<arrayParantsF.length;i++){
        for(j=0;j<arrayParantsS.length;j++){
            if(arrayParantsF[i]==arrayParantsS[j]) return arrayParantsS[j];
        }
    }
    return body;
}
alert(getPerent($("firstChild"),$("secondChild")).id);
</script>
</body>

trikadin 23.06.2011 22:37

Это я написал)) Я просто надеялся... А вдруг! Как-то проше... Но нет. Жестокая реальность показала смехотворную необоснованность моих надежд.

trikadin 23.06.2011 22:40

Slawaq, о боже, что это??

Aetae 23.06.2011 22:41

Всё можно оптимизировать, потом покажу как.)

trikadin 23.06.2011 22:48

Цитата:

Сообщение от Aetae
потом покажу как

Когда звёзды выстроятся в правильном порядке? :)

Slawaq 23.06.2011 22:51

вообще-то от что получилось :)
<body>
<div>
    <div id="multi-parent">
        <div>
            <div id="firstChild"></div>
        </div>
        <div>
            <div>
                <div id="secondChild"></div>
            </div>
        </div>
    </div>
</div>
<script type="text/javascript">
var $ = function(n){return document.getElementById(n);}
var getParent = function(fe,se){
    var parentF = fe.parentNode;
    while(true)
        if(parentTest(se,parentF)) return parentF;
        else parentF=parentF.parentNode;    
    return document.body;
}
function  parentTest(child,parent){
    while(true){
        if(child.parentNode==parent) return true;
        else
            if(child.parentNode!=document.body) child=child.parentNode;
            else break;
    }
    return false;
}
alert(getParent($("firstChild"),$("secondChild")).id);
</script>
</body>

nikita.mmf 23.06.2011 23:07

function getParent ( firstElem, secondElem ) {
	var parent;
	while ( parent != document.body ) {
		parent = firstElem.parentNode, child = parent.firstChild; 
		while ( child ) {
			if ( child == secondElem ) { 
				return parent; 
			}
			child = child.nextSibling;
		}
		parent = parent.parentNode;
	}
	return parent;
}


Агоритм не рабочий

Sweet 23.06.2011 23:10

Slawaq, зачем каждый раз body получать через getElementsByTagName?
nikita.mmf, не думаю, что через .nextSibling будет эффективно. Скорее наоборот.

nikita.mmf 23.06.2011 23:23

Sweet, сложно сказать, это все зависит структуры, мне так кажется, это как бы поиск в глубину и поиск в ширину. Навскидку трудоемкость вашего алгоритма О(n^2), а у моего O(n*m), где n - число родителей до body, а m - макимальное число детей у одного родителя.

Slawaq 23.06.2011 23:38

nikita.mmf, у меня ваш скрипт не работает, только всё лагать начинает...

trikadin 23.06.2011 23:39

Народ, вы чего. У нас же тут не математические вычисления с длинными числами. Средняя вложенность элемента на странице - 15-20 родителей. Соответственно, не более 400 операций сравнения при худшем раскладе. С таким даже алгоритм Slawaq'а быстро справится.

UPD: мне даже кажется, что про 15-20 - я загнул.

Aetae 24.06.2011 00:55

function unitedParent(first,second){
  var parents=function(e){var a=[];while(e=e.parentNode)a.push(e);return a}
  var f=parents(first), s=parents(second), fl=f.length, sl=s.length;
  while(f[--fl]&&f[fl]===s[--sl]);
  return f[fl+1]||null
}

trikadin 24.06.2011 23:15

Aetae, у вас ошибка. Грубо говоря, если обзывать предков числами, то при сравнении элемента с таким массивом предков: [0, 1, 2] и элемента с вот таким: [1, 2, 3] - ф-ция вернёт null.

Но идея с набиванием предков в массив - отличная. Благодарю.

Aetae 25.06.2011 01:07

Пример пжалста, ибо не могу представить такой ситуации. У всех в DOM'е один главный предок.)
Пример:
<html>
<body>   
<style>div{padding:5px;margin:5px;border:2px dotted #000}
#first{border-color:#f00}
#second{border-color:#0f0}
#parent{border-color:#00f}
</style>
 
<div>
  <div>
    <div></div>
    <div id="second"></div>
  </div>
  <div id="first"></div>
</div>
 
<script>
function unitedParent(first,second){
  var parents=function(e){var a=[];while(e=e.parentNode)a.push(e);return a};
  var f=parents(first), s=parents(second), fl=f.length, sl=s.length;
  while(f[--fl]&&f[fl]===s[--sl]);
  return f[fl+1]||null
}
unitedParent(document.getElementById('first'),document.getElementById('second')).id="parent";
</script>
</body>
</html>

trikadin 25.06.2011 02:10

Да, я ступил. Mea Culpa) Всё, прекрасно) Спасибо))

tenshi 27.06.2011 11:19

тут не надо никаких циклов. достаточно навести текстовый диапазон началом на один элемент, концом на другой, а потом попросить у него родительский контейнер.

tenshi 27.06.2011 11:21

гуглить по TextRange commonAncestorContainer

Aetae 27.06.2011 11:28

*бьется головой о стену*

tenshi 27.06.2011 11:47

*приклеил к стене подушечку*

trikadin 06.07.2011 18:55

tenshi, хоть это и некропост будет, но всё же... Range-объектов в ie нет (причём версии до восьмой, что ли). А я немного гоняюсь за кроссбраузерностью.

tenshi 06.07.2011 21:31

да ладна? х)
http://yandex.ru/yandsearch?text=tex... chrome&lr=213

trikadin 06.07.2011 21:56

Range по стандарту w3c и по "стандарту" microsoft - немного разные вещи. Почитайте.

Да простой пример, собственно:
alert(document.createRange);

У меня восьмой осёл, и выдаёт undefined.

tenshi 06.07.2011 22:06

тебе шашечки или ехать?

trikadin 06.07.2011 22:06

Ну, и плюс к тому же, Range.commonAncestorContainer - это не совсем общий родитель. Пример:

<div id="div">text</div>
<script>
div= document.getElementById('div');

rng= document.createRange(); // not ie
rng.setStart(div, 0);
rng.setEnd(div, 1);
alert(rng.commonAncestorContainer.id); // "div"
</script>


В данном случае, он равен элементу, в котором начинается и заканчивается Range-объект. А общим родителем этих двух элементов в данном случае будет body.

trikadin 06.07.2011 22:07

Извините) Любимая тема, понесло))

tenshi 06.07.2011 22:18

на элементы надо наводиться снаружи, а не внутри и всё будет хорошо


Часовой пояс GMT +3, время: 07:23.