Skip to content

Instantly share code, notes, and snippets.

@A-gambit
Created May 11, 2014 21:42
Show Gist options
  • Save A-gambit/628f4362bb7e4c565799 to your computer and use it in GitHub Desktop.
Save A-gambit/628f4362bb7e4c565799 to your computer and use it in GitHub Desktop.
//green - збережені елемени
//red - видалені елменти
//blue - додані елменти
//orange - змінені елменти
var b, //before - перший фрагмент
a; //after - другий фрагмент
var bTag, //тегы before
aTag; //тегы after
var elem = [], //масив елементів з after, які збереглися у before
num=0, //кількість елементів у масиві elem
elemBefore = []; //масив елементів з before, які збереглися у after
numBefore=0; //кількість елементів у масиві elemBefore
cur=-1, //поточный номер збереженого елемента в before
mark = []; //масив маркерів на теги after
var objFirst = new Object(); //об'єкт, який зберігає нові елементи after
objFirst.type='added'; //ім'я об'єкту objFirst
objFirst.element=[]; //масив, який містить нові елементи у фрагменті after
var objSecond = new Object(); //об'єкт, який зберігає нові елементи before
objSecond.type='removed'; //ім'я об'єкту objSecond
objSecond.element=[]; //масив, який містить елементи before, яким не знайдено відповідність у after
var objThird = new Object(); //об'єкт, який зберігає елементи в яких потрібна заміна
objThird.type='changed'; //ім'я об'єкту objThird
objThird.beforeElement=[]; //масив елементів з after, які потребують заміни
objThird.afterElement=[]; //масив елементів з before, які потребують заміни
objThird.html=[]; //innerHTML after, які потребують заміни (або src(href) у випадку посилань)
//======функуція підготовки початкови станів тегів фрагментів, та значень глобальнх змінних=============
function prepear(){
//перевірка на рівності фрагментів
if(b.innerText===a.innerText){
b.style.color="green";
a.style.color="green";
}
else{
b.style.color="red";
a.style.color="blue";
}
//маркування тегів фрагментів before
for(var i=0;i<bTag.length;i++){
if(bTag[i].src!==undefined)
bTag[i].style.cssText="border: 4px solid red;";
else
bTag[i].style.cssText="color: red;";
}
//маркування тегів фрагментів after та підготовка масиву mark
for(var i=0;i<aTag.length;i++){
if(aTag[i].src!==undefined)
aTag[i].style.cssText="border: 4px solid blue;";
else
aTag[i].style.cssText="color: blue;";
mark[i]=true;
}
}
//================ функція пошуку елементу (використовується для фраменту у after)=======================
function findElement(el){
//значення елменту, який потрібно знайти
for(var i=0; i<elem.length;i++){
if(elem[i]===el)
return false;
}
return true;
}
//================ функція первірки розташування збереженого елменту у after============================
function position(el){
//елемент, що шукається серед елментів after
for(var i=0;i<aTag.length;i++){
if(aTag[i].tagName===el.tagName){
if(aTag[i].src!==undefined){
if(aTag[i].style.cssText!=="border: 4px solid green;" && el.src===aTag[i].src && mark[i]){
mark[i]=false;
//перевірка чи поточний знайдений елемент має правильне розташування
if(i>cur){
cur=i;
return true;
}
else
return false;
}
}
else{
if(aTag[i].style.color!="green" && el.innerHTML===aTag[i].innerHTML && mark[i]){
mark[i]=false;
//перевірка чи поточний знайдений елмент має правильне розташування
if(i>cur){
cur=i;
return true;
}
else
return false;
}
}
}
}
}
//================функція превірки рівності посилань у елементах=======================================
function checkHref(beforeChilde, afterChilde, func){
/*елемент з фрагменту before, елемент з фрагменту after, значення виклику функції
(значення пошуку однакових елементів/елементів, які потребують заміни, у фрагментах before та after)*/
if(func){
if(beforeChilde.href!==undefined && afterChilde.href!==undefined){
if(beforeChilde.href===afterChilde.href){
return true;
}
else
return false;
}
else{
if(beforeChilde.href!==undefined || afterChilde.href!==undefined){
return false;
}
else
return true;
}
}
else
return true;
}
//=================функція перевірки знаходження елементів, які потребують заміни=====================
function count(beforeChilde, afterChilde){
//елемент з фрагменту before, елемент з фрагменту after
beforeChilde=beforeChilde.firstChild;
afterChilde=afterChilde.firstChild;
var beforeNumber=0,//кількість братів елементу у фрагменті before, які збережені у фрагменті after
afterNumber=0; //кількість братів елементу у фрагменті after, які збережені у фрагменті before
while(beforeChilde){
if(beforeChilde.tagName!==undefined){
if(beforeChilde.style.color==="green" || beforeChilde.style.cssText==="border: 4px solid green;"){
beforeNumber++;
}
}
beforeChilde=beforeChilde.nextSibling;
}
while(afterChilde){
if(afterChilde.tagName!==undefined){
if(afterChilde.style.color==="green" || afterChilde.style.cssText==="border: 4px solid green;"){
afterNumber++;
}
}
afterChilde=afterChilde.nextSibling;
}
//перевірка на рівність збережених братів
if(beforeNumber===afterNumber)
return true;
else
return false;
}
//=================функція перевірки батьківсьго збережених елементів==================================
function know(beforeChilde,afterChilde){
//елемент з фрагменту before, елемент з фрагменту after
if(numBefore!==0){
//перевірка умови існування одного батька у елементів
if(beforeChilde.parentNode===elemBefore[numBefore-1].parentNode){
//перевірка умови існування одного батька
if(afterChilde.parentNode===elem[num-1].parentNode){
return true;
}
else
return false;
}
else
return true;
}
else
return true;
}
/*====================функція знаходження подібних елментів before та after===============================
===================================та елементів, яким потрібна заміна======================================*/
function check(beforeNode, afterNode, func){
/*елемент з фрагменту before, елемент з фрагменту after, значення виклику функції
(значення пошуку однакових елементів/елементів, які потребують заміни, у фрагментах before та after)*/
var beforeChilde = beforeNode.firstChild,//задання елементу, як першого молодшого елементу beforeNode
afterChilde = afterNode; //задання елементу, який рівний afterNode
//поки існує елмент
while(beforeChilde){
//перевірка на відповідність по всім елементам afterNode
for(var i=0; i<afterNode.childElementCount;i++){
afterChilde=afterNode.children[i];//задати елемент як поточний елмент afterNode
//перевірка на однаковість типів елементів
if(beforeChilde.tagName===afterChilde.tagName){
//перевірка на використання елемента
if(findElement(afterChilde)){
//перевірка на наявність дітей у елементів
if(beforeChilde.childElementCount>0 && afterChilde.childElementCount>0){
check(beforeChilde, afterChilde, func);
}
else{
//перевірка на посилання
if(checkHref(beforeChilde,afterChilde,func)){
//перевірка на тип елементу - зображення чи завантажений контент
if(beforeChilde.src===undefined){
//перевірка innerHTML
if(func && beforeChilde.innerHTML===afterChilde.innerHTML && beforeChilde.style.color!=="green"){
//перевірка послідовності розташування елемента за останнім збереженим фрагментом
if(position(afterChilde)){
//перевірка послідовності розташування елемента за його батьківським елементом
if(know(beforeChilde,afterChilde)){
//маркування елементів та додавання до відповідних масивів
beforeChilde.style.color="green";
afterChilde.style.color="green";
elem[num]=afterChilde;
elemBefore[numBefore]=beforeChilde;
numBefore++;
num++;
break;
}
}
}
//перевіка на маркування елемента у випадку пошуку елементів, яким потрібна заміна
if(!func && beforeChilde.style.color!=="green"){
//перевірка правильності розташування елемента, який потребує заміни
if(count(beforeChilde.parentNode, afterChilde.parentNode)){
//маркування елементів та додавання до відповідних масивів та об'єктів
beforeChilde.style.color="orange";
afterChilde.style.color="orange";
objThird.beforeElement[objThird.beforeElement.length]=beforeChilde;
objThird.afterElement[objThird.afterElement.length]=afterChilde;
objThird.html[objThird.html.length]=afterChilde.innerHTML;
elem[num]=afterChilde;
num++;
break;
}
}
}
else{
if(func &&beforeChilde.src===afterChilde.src && beforeChilde.style.cssText!=="border: 4px solid green;"){
if(position(afterChilde)){
if(know(beforeChilde,afterChilde)){
//маркування елементів та додавання до відповідних масивів
beforeChilde.style.cssText="border: 4px solid green;";
afterChilde.style.cssText="border: 4px solid green;";
elem[num]=afterChilde;
elemBefore[numBefore]=beforeChilde;
numBefore++;
num++;
break;
}
}
}
//перевіка на маркуванння елемента у випадку пошуку елементів, яким потрібна заміна
if(!func && beforeChilde.style.cssText!=="border: 4px solid green;"){
//перевірка правильності розташування елемента, який потребує заміну
if(count(beforeChilde.parentNode, afterChilde.parentNode)){
//маркування елементів та додання до відповідних масивів та об'єктів
beforeChilde.style.cssText="border: 4px solid orange;";
afterChilde.style.cssText="border: 4px solid orange;";
objThird.beforeElement[objThird.beforeElement.length]=beforeChilde;
objThird.afterElement[objThird.afterElement.length]=afterChilde;
objThird.html[objThird.html.length]=afterChilde.src;
elem[num]=afterChilde;
num++;
break;
}
}
}
}
}
}
}
}
//перехід до наступного елементу
beforeChilde=beforeChilde.nextSibling;
}
}
/*функція, яка знаходить нові елементи у другому фрагменті та елементи, яким не було знайдено відповідності у другому фрагменті, тобто видалені елементи
також функція маркує батьківські блоки з збереженими елементами*/
function element(node, task, name){
/*фрагмент в якому шукаються зміни
значення роботи функції - пошуку змін чи маркування збережених елементів
тип пошуку - нових/видалених елементів*/
var childe = node.firstChild; //елемент перший син node
while(childe){
if (childe.tagName!==undefined){
if(!task){
//пошук доданих елементів
if(name===1){
if(childe.style.color==="blue" || childe.style.cssText==="border: 4px solid blue;"){
objFirst.element[objFirst.element.length]=childe;
}
}
//пошук видалених елементів
else if(name===2){
if(childe.style.color==="red" || childe.style.cssText==="border: 4px solid red;"){
objSecond.element[objSecond.element.length]=childe;
}
}
}
element(childe, task, name);
//перевірка на функцію маркерування
if(task){
if(childe.parentNode!==a && childe.parentNode!==b){
if(childe.style.color==="green" || childe.style.cssText==="border: 4px solid green;"){
childe.parentNode.style.color="green";
}
}
}
}
childe=childe.nextSibling;
}
}
//функція пошуку змінених елементів
function change(beforeNode, afterNode){
//елемент х фрагменту before, елемент х фрагменту after
var beforeChilde = beforeNode.firstChild, //перший син beforeNode
afterChilde = afterNode; //елемент рівний afterNode
while(beforeChilde){
if(beforeChilde.tagName!==undefined){
if(beforeChilde.style.color==="green"){
for(var i=0; i<afterNode.childElementCount;i++){
afterChilde=afterNode.children[i];//елемент син afterNode
if(afterChilde.style.color==="green"){
if(afterChilde.tagName===beforeChilde.tagName){
if(beforeChilde.childElementCount>0 && afterChilde.childElementCount>0){
//перевірка на неоднаковість innerHTML
if(afterChilde.innerHTML!==beforeChilde.innerHTML){
objThird.beforeElement[objThird.beforeElement.length]=beforeChilde;
objThird.afterElement[objThird.afterElement.length]=afterChilde;
objThird.html[objThird.html.length]=afterChilde.innerHTML;
beforeChilde.style.color="orange";
afterChilde.style.color="orange";
change(beforeChilde,afterChilde);
break;
}
}
}
}
}
}
}
beforeChilde=beforeChilde.nextSibling;
}
}
//головна функція diff()
function diff(){
b=document.getElementById('before');//задання зміної для фрагменту before
a=document.getElementById('after');//задання зміної для фрагменту after
bTag = b.getElementsByTagName('*');//задання тегів фрагменту before
aTag = a.getElementsByTagName('*');//задання тегів фрагменту after
//підготовка початкових значень
prepear();
//пошук збережених елементів у фрагментах before та after
check(b, a, true);
//пошук крайніх елементів, яким потрібна заміна before та after
check(b, a, false);
//додавання до об'єкту objFirst з типом added, нових елментів
element(a, true, 1);
//маркування елементів after, які містять подібні елементи з фрагментом before
element(a, false, 1);
//додавання до об'єкту objSecond з типом removed, видалених елементів
element(b, true, 2);
//маркування елементів before, які містять подібні елементи з фрагментом after
element(b, false, 2);
//знаходження пар елементів у фрагментах before і after, які потребують заміни, та запис їх у об'єкті objSecond з типом changed
change(b,a);
//виведення отриманих результатів у консоль
console.log(objFirst);
console.log(objSecond);
console.log(objThird);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment