﻿// ------------------------------------------------------------------------------------------------------------------------------------------------------------
// Класс меню:

function TMenu(Name)
{
	this.Name = Name;							// Имя экземпляра меню (для подстановки в генерируемый html-код)
	this.Span = new String();					// Имя контейнера, содержащего html-код меню
	this.MarkerLength = new Number();			// Сколько пикселей отведено под маркер
	this.MarkerSpace = new Number();			// Горизонтальное расстояние между текстом элементов меню и маркером (в пикселах)
	this.MarkerTop = new Number();				// Вертикальный отступ маркера от верхней границы элемента (в пикселах)
	this.ActiveIndent = new Number();			// Горизонтальный отступ активного элемента
	this.MarginLeft = new Number();				// Ширина поля слева
	this.MarginRight = new Number();			// Ширина поля справа	
	this.MarkerPlus = new String();				// URL изображения маркера "плюс"
	this.MarkerMinus = new String();			// URL изображения маркера "минус"
	this.MarkerItem = new String();				// URL изображения маркера "оконечный элемент"
	this.MarkerOpen = new String();				// URL изображения маркера, остающегося всегда открытым
	
	this.Text = new Array();					// Массив текстового содержания элементов меню
	this.Address = new Array();					// Массив адресов ссылок элементов меню
	this.Ouner = new Array();					// Массив номеров родительских элементов
	this.Expanded = new Array();				// Массив свойств открытости/закрытости элементов
	this.AlwaysOpen = new Array();				// Массив, определяющий всегда открытые элементы: 0 - обычное поведение, 1 - всегда открыт и есть маркер, -1 - всегда открыт и нет маркера
	this.Display = new Array();					// Массив свойств видимости элементов меню (не редактируется, полностью зависит от состояния Expanded)
	
	this.Create = TMenuCreate;					// Генерация html-кода меню
	this.Show = TMenuShow;						// Показать элемент меню
	this.Hide = TMenuHide;						// Скрыть элемент меню
	this.Level = TMenuLevel;					// Вычисление глубины вложения элемента
	this.HasSubitems = TMenuHasSubitems;		//Определение наличия подэлементов
	this.IsVisible = TMenuIsVisible;			// Определение видимости элемента
	this.Collapse = TMenuCollapse;				// Свернуть элемент меню
	this.Expand = TMenuExpand;					// Развернуть элемент меню
	this.IsSubordinate = TMenuIsSubordinate;	// Подчинен ли первый элемент второму
	this.Location = TMenuLocation;				// Номер элемента, соответствующего текущей странице
	this.ExpandLocation = TMenuExpandLocation;	// Показать элемент, соответствующий текущей странице
	this.ExpandAll = TMenuExpandAll;			// Развернуть все элементы
	this.CollapseAll = TMenuCollapseAll;		// Свернуть все элементы
	this.ViewHTML = TMenuViewHTML;				// Просмотр текущего HTML-кода в textarea
}

// ------------------------------------------------------------------------------------------------------------------------------------------------------------
// Генерация html-кода меню:

function TMenuCreate()
{
	var html = '';
	var level, classname, indent;
	var i,j, n = this.Text.length;
	
	// Заполнение массива открытости элементов:
	for (i=0; i<n; i++) this.Expanded[i] = 0;	// по умолчанию все элементы закрыты
	// Заполнение массива, определяющего всегда открытые элементы :
	for (i=0; i<n; i++) if (this.AlwaysOpen[i] == undefined) this.AlwaysOpen[i] = 0; // по умолчанию отсутствуют
	// Заполнение массива видимости элементов (зависит от состояния открытости):
	for (i=0; i<n; i++) this.Display[i] = this.IsVisible(i);
	
	if (this.MarkerTop == undefined) this.MarkerTop = 5;
	
	// Генерация html-кода:
	for (i=0; i<n; i++) {
		// Каждому элементу меню соответствует span:
		html += '<span id="' + this.Span + '_' + i + '">';
		// В нем заключена таблица из одной строки, двух столбцов:
		if (this.Display[i] == 1) {
			// Каскадные базовые стили уровней:
			level = this.Level(i); classname = ''; for (j=0; j<=level; j++) classname += ' Level' + j;
			// Каскадные стили для элементов, имеющих вложенные элементы:
			if (this.HasSubitems(i) == 1) for (j=0; j<=level; j++) classname += ' Level' + j + 'Parent';
			// Каскадные стили для активных элементов, соответствующих текущей странице:
			indent = this.MarginLeft;
			if (this.Location() == i) {
				for (j=0; j<=level; j++) classname += ' Level' + j + 'Location';
				indent += this.ActiveIndent;
			}
			html += '<table width="100%" class="' + classname + '" style="border-collapse:collapse"><tr valign="top">';
			// В первом столбце - маркер, зависящий от типа и состояния элемента:
			html += '<td align="right" width=' + this.MarkerLength + ' style="padding-left:' + Number((this.MarkerLength + this.MarkerSpace + 1)*this.Level(i) + indent) + 'px">';
			// Если элемент не всегда открыт:
			if (this.AlwaysOpen[i] == 0) {
				if (this.HasSubitems(i) == 1) {
					if (this.Expanded[i] == 1) html += '<img src="' + this.MarkerMinus  + '" border=0 onMouseDown="' + this.Name  + '.Collapse(' + i  + ')" style="margin-top:' + this.MarkerTop + 'px; cursor:pointer"></td>';
					else html += '<img src="' + this.MarkerPlus + '" border=0 onMouseDown="' + this.Name  + '.Expand(' + i  + ')" style="margin-top:' + this.MarkerTop + 'px; cursor:pointer"></td>';
				}
				else html += '<img src="' + this.MarkerItem  + '" border=0 style="margin-top:' + this.MarkerTop + 'px"></td>';
			}
			// Если элемент всегда открыт:
			else html += (this.AlwaysOpen[i] == 1) ? ('<img src="' + this.MarkerOpen  + '" border=0 style="margin-top:' + this.MarkerTop + 'px"></td>') : '</td>';
			// Во втором столбце - текст ссылки:
			if (this.Address[i] != '')	// есть адрес: ссылка
				html += '<td style="padding-left:' + this.MarkerSpace + 'px; padding-right:' + this.MarginRight + 'px"><a class="' + classname + '" href="' + this.Address[i] + '">' + this.Text[i] + '</a></td>';
			else												// иначе обычный текст
				html += '<td style="padding-left:' + this.MarkerSpace + 'px">' + this.Text[i] + '</td>';
			html += '</tr></table>'; 
		}
		html += '</span>';
	}
	
	document.getElementById(this.Span).innerHTML = html;
}

// ------------------------------------------------------------------------------------------------------------------------------------------------------------
// Показать элемент меню:

function TMenuShow(id)
{
	var html = '';
	var j, level, classname, indent;
	// Каскадные базовые стили уровней:
	level = this.Level(id); classname = ''; for (j=0; j<=level; j++) classname += ' Level' + j;
	// Каскадные стили для элементов, имеющих вложенные элементы:
	if (this.HasSubitems(id) == 1) for (j=0; j<=level; j++) classname += ' Level' + j + 'Parent';
	// Каскадные стили для активных элементов, соответствующих текущей странице:
	indent = this.MarginLeft;
	if (this.Location() == id) {
		for (j=0; j<=level; j++) classname += ' Level' + j + 'Location';
		indent += this.ActiveIndent;
	}
	html += '<table width="100%" class="' + classname + '" style="border-collapse:collapse"><tr valign="top">';
	// В первом столбце - маркер, зависящий от типа и состояния элемента:
	html += '<td align="right" width=' + this.MarkerLength + ' style="padding-left:' + Number((this.MarkerLength + this.MarkerSpace + 1)*this.Level(id) + indent) + 'px">';
	// Если элемент не всегда открыт:
	if (this.AlwaysOpen[id] == 0) {
		if (this.HasSubitems(id) == 1) {
			if (this.Expanded[id] == 1) html += '<img src="' + this.MarkerMinus  + '" border=0 onMouseDown="' + this.Name  + '.Collapse(' + id  + ')" style="margin-top:' + this.MarkerTop + 'px; cursor:pointer"></td>';
			else html += '<img src="' + this.MarkerPlus + '" border=0 onMouseDown="' + this.Name  + '.Expand(' + id  + ')" style="margin-top:' + this.MarkerTop + 'px; cursor:pointer"></td>';
		}
		else html += '<img src="' + this.MarkerItem  + '" border=0 style="margin-top:' + this.MarkerTop + 'px"></td>';
	}
	// Если элемент всегда открыт:
	else html += (this.AlwaysOpen[id] == 1) ? ('<img src="' + this.MarkerOpen  + '" border=0 style="margin-top:' + this.MarkerTop + 'px"></td>') : '</td>';
	// Во втором столбце - текст ссылки:
	if (this.Address[id] != '')	// есть адрес: ссылка
		html += '<td style="padding-left:' + this.MarkerSpace + 'px; padding-right:' + this.MarginRight + 'px"><a class="' + classname + '" href="' + this.Address[id] + '">' + this.Text[id] + '</a></td>';
	else													// иначе обычный текст
		html += '<td style="padding-left:' + this.MarkerSpace + 'px">' + this.Text[id] + '</td>';
	html += '</tr></table>'; 
	document.getElementById(this.Span + '_' + id).innerHTML = html;
	this.Display[id] = 1;
}

// ------------------------------------------------------------------------------------------------------------------------------------------------------------
// Скрыть элемент меню:

function TMenuHide(id)
{
	document.getElementById(this.Span + '_' + id).innerHTML = '';
	this.Display[id] = 0;
}

// ------------------------------------------------------------------------------------------------------------------------------------------------------------
// Вычисление глубины вложения элемента:

function TMenuLevel(id)
{
	var level = 0;
	while (this.Ouner[id] > -1) {
		id = this.Ouner[id];
		level++;
	}
	return level;
}

// ------------------------------------------------------------------------------------------------------------------------------------------------------------
// Определение наличия подэлементов:

function TMenuHasSubitems(id)
{
	var i, n = this.Text.length;
	for (i=0; i<n; i++) if (this.Ouner[i] == id) return 1;
	return 0;
}

// ------------------------------------------------------------------------------------------------------------------------------------------------------------
// Определение видимости элемента:

function TMenuIsVisible(id)
{
	// Элемент виден, если все его хозяева открыты:
	while (this.Ouner[id] > -1) {
		id = this.Ouner[id];
		if (this.Expanded[id] == 0 && this.AlwaysOpen[id] == 0) return 0;
	}
	return 1;
}

// ------------------------------------------------------------------------------------------------------------------------------------------------------------
// Подчинен ли первый элемент второму:

function TMenuIsSubordinate(id1,id2)
{
	// Элемент id1 подчинен id2, если в цепочке хозяев id1 найдется id2:
	while (this.Ouner[id1] > -1) {
		id1 = this.Ouner[id1];
		if (id1 == id2) return 1;
	}
	return 0;
}
 
// ------------------------------------------------------------------------------------------------------------------------------------------------------------
// Свернуть элемент:

function TMenuCollapse(id)
{
	if (this.AlwaysOpen[id] != 0) return 0;
	var i, n = this.Text.length;
	// Скрываем все подчиненные элементы:
	for (i=0; i<n; i++) if (this.IsSubordinate(i,id) == 1) this.Hide(i);
	// Устанавливаем флаг закрытия и перерисовываем элемент:
	this.Expanded[id] = 0;
	this.Show(id);
}

// ------------------------------------------------------------------------------------------------------------------------------------------------------------
// Развернуть элемент:

function TMenuExpand(id)
{
	var i, n = this.Text.length;
	// Устанавливаем флаг открытия:
	this.Expanded[id] = 1; // alert(id + '\n' + this.Text[id] + '\nOuner=' + this.Ouner[id] + '\nExpanded=' + this.Expanded[0]);
	// Показываем все подчиненные не закрытые элементы:
	for (i=0; i<n; i++) if (this.IsSubordinate(i,id) == 1 && this.IsVisible(i)) this.Show(i);
	// Перерисовываем элемент:
	this.Show(id);
}

// ------------------------------------------------------------------------------------------------------------------------------------------------------------
// Номер элемента, соответствующего текущей странице:

function TMenuLocation()
{
	var loc, i, n = this.Text.length;
	// Имя текущей странице должно быть записано в скрытом div с id="page_title":
	if (document.getElementById('page_title') != null) 
		loc = document.getElementById('page_title').innerHTML;
	else
		loc = '';
	if (loc == '') return -1;
	// Ищем совпадение адреса страницы, начиная с последнего элемента меню:
	for (i=n-1; i>=0; i--) if (this.Address[i].split("/")[this.Address[i].split("/").length-1] == loc) return i;
	return -1;
}

// ------------------------------------------------------------------------------------------------------------------------------------------------------------
// Показать элемент, соответствующий текущей странице:

function TMenuExpandLocation()
{
	// Номер элемента, соответствующего текущей странице:
	var id = this.Location();
	if (id < 0) return;
	// Открываем его (показываем подэлементы):
	this.Expand(id);
	// Открываем всех его хозяев:
	while (this.Ouner[id] > -1) {
		id = this.Ouner[id];
		this.Expand(id);
	}	
}

// ------------------------------------------------------------------------------------------------------------------------------------------------------------
// Развернуть все элементы:

function TMenuExpandAll()
{
	var i, n = this.Text.length;
	for (i=0; i<n; i++) this.Expand(i);
}

// ------------------------------------------------------------------------------------------------------------------------------------------------------------
// Свернуть все элементы:

function TMenuCollapseAll()
{
	var i, n = this.Text.length;
	for (i=0; i<n; i++) {
		if (this.Level(i) > 0) this.Hide(i);
		this.Expanded[i] = 0;
		if (this.Level(i) == 0) this.Show(i);
	}
}

// ------------------------------------------------------------------------------------------------------------------------------------------------------------
// Просмотр текущего HTML-кода в textarea:

function TMenuViewHTML()
{
	var html = document.getElementById(this.Span).innerHTML;
	var html_textarea = '<textarea id="my_textarea" rows=20 cols=80>' + html + '</textarea>';
	
	document.getElementById(this.Span).innerHTML = html + html_textarea;
}

