User:Khanson/check tags.js

//Скрипт проверяет правильность закрытия тегов. //Автор: X-romix

if (wgAction == 'edit' || wgAction == 'submit') $(function{	var wpSave = document.getElementById('wpSave');	if (!wpSave) return;	addHandler(wpSave, 'click', XRomix_CheckTagsHandler); });

function XRomix_CheckTagsHandler(e){ var xSelectionStart=0; var xSelectionEnd=0; var wpTextbox1 = document.editform.wpTextbox1;

var isCancel=false; var text=document.editform.wpTextbox1.value;

var isCancel=!XRomix_CheckTags(text); if(isCancel){ setSelectionRange(wpTextbox1, xSelectionStart, xSelectionEnd); isCancel= !window.confirm("Имеются ошибки форматирования. Всё равно сохранить?"); }else{ setRedWindow(""); //Очищаем красное окно, если оно было }	if (isCancel){ //отменить нажатие кнопки e = e || window.event //из-за различий в IE и стандартных браузерах if (e.preventDefault) e.preventDefault; else e.returnValue = false //остановить действие, снова по-разному return false //на всякий случай }	//Выводит красное окно предупреждения function setRedWindow(res){ var w = document.getElementById('XRomix_editpage_CheckTags'); if (res!=""){ var wpSummary = document.getElementById('wpSummary') if (!wpSummary) return var w = document.getElementById('XRomix_editpage_CheckTags'); if(!w){ w = document.createElement('span') w.id = 'XRomix_editpage_CheckTags' wpSummary.parentNode.insertBefore(w, wpSummary.nextSibling); }			w.innerHTML = ' '+ 'Имеются незакрытые (или неправильно закрытые) элементы HTML или вики-разметки. ' + res +' '+ ' (подробнее ↗) '; }else{ if(w) w.innerHTML=''; //Если нет ошибки, то очищаем }	}	//////////////////////////////////////	//генерирует строку из пробелов указанной длины function generateSpaces(len){ var s1="               "; while(s1.length<len){ s1+=s1; }		return s1.substr(0,len); }	//////////////////////////////////////	//Проверяет теги function XRomix_CheckTags(text){ //////////////////////////////////////			//Заменяет текст между открывающим и закрывающим тегами на пробелы function replaceTags(tag1, tag2){ while(1==1){ var p=txt.search(tag1); if(p==-1) break; var p1=txt.indexOf(tag2,p); if(p1==-1) { //ошибка, закрывающий тег не найден setRedWindow('Не закрыт элемент '+htmlEncode(tag1)+'.'); xSelectionStart=p; xSelectionEnd=p+tag2.length+1; return false; }					var w1=generateSpaces(p1-p+tag2.length); var left=txt.substr(0, p); var right=txt.substr(p1+tag2.length); txt=left+w1+right; }					return true; }

//////////////////////////////////////			//Заменяет тег на пробелы function replace1Tag(tag1){ var p=txt.indexOf(tag1); if(p==-1) return; var w1=generateSpaces(tag1.length); var left=txt.substr(0, p); var right=txt.substr(p+tag1.length); txt=left+w1+right; }

var ok=0; if (document.URL.match(/\.js&action=(edit|submit)/)){ return true; //JavaScript не проверяем }else if (document.URL.match(/\.css&action=(edit|submit)/)){ return true; //CSS не проверяем }else if (wgTitle.match (/(Шаблон|Template)\:/)){ return true; //Шаблоны не проверяем }else if ('code'.replace(/d/g, 'r') != 'core'){ //Проверяем, поддерживает ли браузер регулярные выражения (RegExp) return true; }

var wpTextbox1 = document.editform.wpTextbox1; if(!wpTextbox1) return true;

var txt = wpTextbox1.value;

var ok=replaceTags(/ /, " "); if(!ok) return false; var ok=replaceTags(/<\!\-\-/, "-->"); if(!ok) return false; var ok=replaceTags(/$$/, "$$"); if(!ok) return false; var ok=replaceTags(/ ");		if(!ok) return false;		var ok=replaceTags(/]/, " ");		if(!ok) return false;		var arrPos = new Array;		var arrTags= new Array;

var arr = txt.match(/(<[\/]?[A-Za-z][^>]*>|\[\[|\]\]|\{\{|\}\})/g); if(arr==null) return true; //Нет тегов для проверки - возврат if(arr){ for(var i=0; i| | )/) >=0 ){ // <тег/> continue; //пропускаем такие теги, поскольку они не требуют закрытия }else if(TagName.search(/<[a-zA-Z][^>]*>/) >=0){ //открывающий <тег ...> //помещаем тег и его позицию в стек arrStackTags.push(TagName); arrStackPos.push(TagPos); }else if(TagName.search(/<\/[^>]+>/) >=0){ //Закрывающий  var TagNameN=TagName.replace(/[<>\/]/g, ""); TagNameN=TagNameN.toLowerCase; //Нормализованное имя тега - без угловых скобок и / if (arrStackTags.length==0){ setRedWindow('Неожиданный закрывающий тег '+htmlEncode(TagName)+'.') xSelectionStart=TagPos; xSelectionEnd=TagPos+TagName.length; return false; }else{ var TagName2=arrStackTags.pop; var TagPos2=arrStackPos.pop; var TagName2N=TagName2.replace(/[\s][^>]*/, ""); //убираем все после первого пробела TagName2N=TagName2N.replace(/[<>\/]/g, "");//убираем  TagName2N=TagName2N.toLowerCase; if(TagNameN!=TagName2N){ setRedWindow('Неожиданный закрывающий тег '+htmlEncode(TagName)+' после открывающего тега '+htmlEncode(TagName2)+'.'); xSelectionStart=TagPos; xSelectionEnd=TagPos+TagName.length; return false; }				}			}else if(TagName=="[["){ 					arrStackTags.push(TagName); 				arrStackPos.push(TagPos); 			}else if(TagName==""){ 					if (arrStackTags.length==0){					setRedWindow('Неожиданный закрывающий элемент '+htmlEncode(TagName)+'.');					xSelectionStart=TagPos;					xSelectionEnd=TagPos+TagName.length;					return false;				}else{					var TagName2=arrStackTags.pop;					var TagPos2=arrStackPos.pop;					if(TagName2!="{{"){						setRedWindow('Неожиданный закрывающий тег '+htmlEncode(TagName)+' после открывающего тега '+htmlEncode(TagName2)+'.');						xSelectionStart=TagPos;						xSelectionEnd=TagPos+TagName.length;						return false;					}				}			}		}//for		if(arrStackTags.length>0){			var TagName=arrStackTags.pop			var TagPos=arrStackPos.pop;			setRedWindow('Имеется незакрытый элемент '+htmlEncode(TagName)+'.');			xSelectionStart=TagPos;			xSelectionEnd=TagPos+TagName.length;			return false;		}//if	       return true; //нет ошибок	}//function	//подсчитывает концы строк в фрагменте текста	function countCrlf(str){		str=""+str;		var arr=str.match(/\n/g);		//Теперь массив содержит концы строк - возвращаем его длину		if (arr) return arr.length;		return 0;	}

//Извлекает первую строку (до \n или \r) из строки function get1string(text){ var p=text.indexOf("\n"); var p1=text.indexOf("\r"); if(p1!=-1 && p!=-1){ if(p>p1) p=p1; }		if(p!=-1){ text=text.substr(0, p); }		return text; }

//Браузеро-независимый setSelectionRange - изменяет начало и конец //выделенного фрагмента в поле ввода input function setSelectionRange(input, start, end){ if(!input) return; if(!input.value) return; var text=input.value.substring(start, end); text=get1string(text); if (input.setSelectionRange) {//Mozilla/Opera //Попытаемся спозиционировать курсор на нужный текст if (self.find) {//Mozilla, в Опере не работает input.focus; input.setSelectionRange(start, start); var caseSensitive = false var backwards = false var wrapAround = false self.find(text, caseSensitive, backwards, wrapAround); }				//Выделим диапазон input.focus; input.setSelectionRange(start, end); }else if (document.selection && document.selection.createRange) { //Internet Explorer //IE проглючивает с началом и концом выделенного фрагмента - вносим исправление var cnt1=countCrlf(input.value.substring(0, start)); var cnt2=countCrlf(input.value.substring(start, end)); var range = input.createTextRange; if(range.findText){ input.focus; range.collapse(true); range.moveStart("character", start - cnt1); range.moveEnd("character", start - cnt1); range.select; range.findText(text); range.collapse(true); }			var range = input.createTextRange; //Выделяем диапазон в IE			input.focus; range.collapse(true); range.moveStart("character", start - cnt1); range.moveEnd("character", end - start - cnt2); range.select; }		}

//Кодирование спецсимволов HTML function htmlEncode(s){ s=s.replace(/[\&]/g, "&amp;"); s=s.replace(/[<]/g, "&lt;"); s=s.replace(/[>]/g, "&gt;"); return s;	} }