ФорумыТемы

Новое сообщение

Сообщения темы 'JavaScript. Динамическое оглавление'

Фильтр:
содержит   Сортировка   

  

gliba 28.01.2007 01:53
Динамическое оглавление используется в проигрывателе курсов в системе дистанционного обучения "Карат".
Переход к курсу.

Код динамической загрузки оглавления


<style>
/* menu item */
A.menuel:link { COLOR: #0000ff; }
A.menuel:visited { COLOR: #0000cc; }
A.menuel:hover { COLOR: #00ffff; }
A.menuel:active { COLOR: #00ffff; }

/* current menu item */
A.menuact:link { color: #ffff00; }
A.menuact:visited { COLOR: #eeee00; }
A.menuact:hover { COLOR: #00ffff; }
A.menuact:active { COLOR: #00ffff; }

/* hint for menu item */
.hint
{
    BACKGROUND-COLOR: khaki
}
</style>

<script>
//navigation block 
var navdata = "";			//navigation data
var oldClass = "";			//class of not selected menu
var curPage = -1;			//current page displayed
var pages = new Array();	//array of course page objects
var lastSel = -1;			//selected page
var iForward = 2;			//1 - step forward, -1 - step back, 2 - initial open menu, 0 - show/hide
var maxwidth = 1;			//menu width
var pageTotal = 0;			//number of real pages
var yOffMenu = -1;			//y-offset of menu table
var skin = "";
var bEnglish = 0;

function coursePage( pid, title, url, level, num )
{
	this.pid = pid;
	this.title = title;
	this.url = url;
	this.level = level;		//= 0 - main menu, < 0 - submenu item
	this.type = 0;			//0 - content, 1 - test
	this.stat = "i";		//incomplete
	this.iMenu = 0;			//submenu: 0 - none, 1 - opened, -1 - closed
	this.num = num;			//
}
//parse course navigation data
function parsenavdata()
{
	pageTotal = 0;
	maxwidth = 1;
	var lastlevel = 0;
	var arr = navdata.split( "\n" );
	for( var i = 0; i < arr.length; i++ )
	{
		var s = trimSpaces( arr[ i ] );
		if( s == "" ) continue;
		var arr2 = s.split( "|" );	//pid, title, url, level <= 0
		var cur = pages.length;
		var level = Math.abs( 1 * arr2[ 3 ] );
		if( arr2[ 2 ] != "" ) pageTotal ++;
		pages[ cur ] = new coursePage( arr2[ 0 ], arr2[ 1 ], arr2[ 2 ], level, pageTotal );
		if( level > lastlevel && cur > 0 )
		{
			pages[ cur - 1 ].iMenu = -1;	//prev.item has submenu, close it
		}
		lastlevel = level;
		
		var titlen = arr2[ 1 ].length;	//title length
		if( titlen > maxwidth ) maxwidth = titlen;
	}
	maxwidth *= 11;
}
function createmenu()
{
	if( document.getElementById == null ) return;
	var objDiv = document.getElementById( "andr" );
	if( objDiv == null ) return;
	
	//start table for menu
	var s = ( '<table cellspacing="0" cellpadding="2" border="0" width="' + maxwidth + '"><tr><td>' );	
	var iSkipLevel = 100;
	for( var i = 0; i < pages.length; i++ )
	{	//check every page
		if( pages[ i ].level > iSkipLevel ) 
		{	//hide 
		}
		else
		{	//display with indent
			var iconspace = '<img border="0" height="16" width="' + ( pages[ i ].level * 16 ) + '" src="' + skin + 'm_space.gif">';
			var icon = '<img border="0" ';
			if( pages[ i ].iMenu == 0 ) 
			{	//$ - non-free resourse
				if( pages[ i ].url.indexOf( "$" ) >= 0 ) icon += 'src="' + skin + 'm_pagebook$.gif">';
				else icon += 'src="' + skin + 'm_pagebook.gif">';
			}
			else if( pages[ i ].iMenu > 0 ) icon += 'src="' + skin + 'm_openbook.gif">';
			else icon += 'src="' + skin + 'm_closebook.gif">';
		
			s += ( iconspace + '<a class="menuel" href="#" id="page' + i + '" onclick="return loadpage(' + i + ')" onmouseover="displaystatus(event,this,' + i + ')" onmouseout="resetstatus(' + i + ')">' + icon + pages[ i ].title + '</a><br>' );
			
			if( pages[ i ].iMenu < 0 ) iSkipLevel = pages[ i ].level;
			else iSkipLevel = 100;
		}
	}
	s += '</td></tr></table>';	//end menu table
	
	//hint to display the status of menu item
	var hint = '<div class="hint" id="hint" style="visibility:hidden;position:absolute;left:10;top:200;width:100;">bla-bla</div>';
	s += hint;
	
	objDiv.innerHTML = s;
	
	lastSel = -1;
	yOffMenu = -1;
}
//display a stus of menu item
function displaystatus( e, elem, n )
{
	if( yOffMenu == -1 )
	{	//calculate the y-offset of table with menu items
		var p = elem;
		while( p && p.nodeName != "BODY" )
		{
			if( p.nodeName == "DIV" || p.nodeName == "TABLE" )
			{
				yOffMenu += p.offsetTop;
			}
			p = p.parentNode;
		}
	}

	var stat = ( bEnglish == 1 ) ? "completed" : "завершен";
	var mylevel = pages[ n ].level;
	for( var i = n; i < pages.length; i++ )
	{
		if( i > n && pages[ i ].level >= 0 &&
			pages[ i ].level <= mylevel ) break;	//upper menu item reached
		if( ( pages[ i ].stat == "i" || pages[ i ].stat == "f" ) &&
			pages[ i ].url != "" )
		{
			stat = ( bEnglish == 1 ) ? "incomplete" : "незавершен";
			break;
		}
	}
	if( document.getElementById )
	{
		var obj = document.getElementById( "hint" );
		if( obj != null ) 
		{
			obj.style.visibility='visible';
			obj.style.top = yOffMenu + elem.offsetTop + elem.offsetHeight + 3;
			obj.innerHTML = stat;
		}
	}
}
function resetstatus( n )
{
	if( document.getElementById )
	{
		var obj = document.getElementById( "hint" );
		if( obj != null ) obj.style.visibility='hidden';
	}
}
function findOpenedItem( n )
{	//find index of opened item
	var mylevel = pages[ n ].level;
	if( mylevel == 0 ) return n;

	var i, iVis = n;	//assume it's visible
	for( i = n; i >= 0; i-- )
	{
		if( pages[ i ].level == mylevel - 1 )
		{	//parent
			mylevel--;		
			if( pages[ i ].iMenu < 0 ) iVis = i;	//submenu is invisible
			if( pages[ i ].level == 0 ) break;
		}
	}	
	return iVis;
}
//open all upper submenus of n
function extendmenuitem( n )
{	
	var nextlevel = pages[ n ].level - 1, i;
	for( i = n; i >= 0; i-- )
	{
		if( pages[ i ].level == nextlevel )
		{	//parent
			nextlevel--;		
			if( pages[ i ].iMenu < 0 ) pages[ i ].iMenu = 1;	//submenu will be visible
			if( pages[ i ].level == 0 ) break;
		}
	}	
	return;
}
//select item - change color
function selectmenuitem( n )
{
	var i = n, obj;
	if( i == lastSel ) return;	//already selected
	
	if( document.getElementById )
	{
		if( lastSel >= 0 )
		{	//deselect
			obj = document.getElementById( "page" + lastSel );
			if( obj != null ) obj.className = oldClass;
		}
		//select
		obj = document.getElementById( "page" + i );
		if( obj != null ) 
		{
			oldClass = obj.className;
			obj.className = "menuact";
		}
	}
	lastSel = i;
}
//iForward: 1 - step forward, -1 - step back, 2 - open all external menus, 0 - show/hide
function loadpage( m )
{
	var bLoad = true, bUpdateMenu = false;
	var n = 1 * m;
	if( n < 0 || n >= pages.length ) 
	{	//invalid index
		if( curPage >= 0 ) return false;
		n = 0;
		m = 0;
	}
	
	if( iForward == 1 || iForward == 2 )
	{	//go down
		for( ; n < pages.length; n++ )
		{	//url can be "" for menu item
			if( pages[ n ].url != "" ) break;
		}
	}
	if( iForward == -1 )
	{	//go up
		for( ; n >= 0; n-- )
		{	//url can be "" for menu item
			if( pages[ n ].url != "" ) break;
		}
	}	
	if( iForward == 0 && pages[ n ].iMenu != 0 )
	{	//show/hide submenu
		{	//don't navigate
			pages[ n ].iMenu = - pages[ n ].iMenu;	//show/hide submenu
			bUpdateMenu = true;	
			if( pages[ n ].url == "" ) 
			{
				n = curPage;		
				bLoad = false;
			}
		}
	}
	if( n < 0 || n >= pages.length ) 
	{
		iForward = 0;
		return false;	//invalid index
	}
	curPage = n;
	
	//open url
	var url = pages[ curPage ].url;
	if( bLoad ) 
	{		
		openit( url );	
	}

	if( pages[ curPage ].stat == "i" && 
		url.indexOf( "test" ) < 0 )
	{	//if resource is not a test and available then mark a page as completed
		pages[ curPage ].stat = "c";
	}
	
	if( !bUpdateMenu && n != findOpenedItem( n ) )
	{	//new menu item is hidden 
		extendmenuitem( n );
		bUpdateMenu = true;
	}
	
	if( bUpdateMenu ) 
	{
		createmenu();
	}
	
	selectmenuitem( n );
	iForward = 0;
	return false;		//false to supress <a href> behavior
}
//remove leading and trailing spaces, \r, \n
function trimSpaces( buf )
{
	//remove leading spaces
	var len = buf.length;
	while( len > 0 ) 
	{
		var s = buf.charAt( 0 );
		if( s == " " || s == "\n" || s == "\r" ) 
		{
			len --;
			buf = buf.substr( 1, len );
		} 
		else break;
	}
	//remove trailing spaces
	while( len > 0 ) 
	{
		var s = buf.charAt( len - 1 );
		if( s == " " || s == "\n" || s == "\r" ) 
		{
			len --;
			buf = buf.substr( 0, len );
		} 
		else break;
	}
	return buf;
}
//open url in new window
function openit( url, w, h, scroll, resize, left, top )
{
	if( url == "" ) return;
	
	var thisloc = "" + window.location;
	if( "" + w == "undefined" ) w = 600;
	if( "" + h == "undefined" ) h = 350;
	if( "" + scroll == "undefined" ) scroll = 'yes';
	if( "" + resize == "undefined" ) resize = 'yes';
	if( "" + left == "undefined" ) {
		left = ( screen.width - w ) / 2;
		if( left < 0 ) left = 0;
	}
	if( "" + top == "undefined" ) {
		top = ( screen.height - h - 30 ) / 2;
		if( top < 0 ) top = 0;
	}

	var pos2 = url.toLowerCase().indexOf("http:"), loc = url;
	if( pos2 < 0 && url.charAt( 0 ) != "/" )
	{	//relative path
		var pos = thisloc.lastIndexOf("/");
		if( pos >= 0 )
		{
			loc = thisloc.substring(0, pos+1) + url;
		}
	}
	
	if( loc == "" ) return;

	window.open( loc, '_blank', 'width=' + w + ',height=' + h + ',left=' + left + ',top=' + top + ',scrollbars=' + scroll + ',resizable=' + resize );
	return;
}
//load sample
function loadsample()
{
	if( pages.length > 0 ) return false;
	
	navdata = "1|JavaScript||0\n2|алгоритм SHA-1|sub002.htm|-1\n3|Построение гистограмм|sub003.htm|-1\n4|Как скопировать файл с CD-ROM'а в приложении MFC|sub001.htm|0";
	parsenavdata();
	createmenu();
	return false;
}
</script>
<div id="andr">Оглавление не загружено</div><a href="#" onclick="return loadsample()">Загрузить</a>


Переход к примеру.

Комментарии. Cтруктура оглавления хранится в переменной navdata как список строк в формате
"Идентификатор страницы | название страницы | url страницы | уровень вложенности".
Пример данных для оглавления из 4-х элементов.
navdata = "1|JavaScript||0\n2|алгоритм SHA-1|sub002.htm|-1\n3|Построение гистограмм|sub003.htm|-1\n4|Как скопировать файл с CD-ROM'а в приложении MFC|sub001.htm|0";
Анализ данных о структуре оглавления происходит в функции parsenavdata(). Переменная navdata расщепляется в массив arr. Каждый элемент массива есть одна строка описания структуры курса. Каждая непустая строка в свою очередь расщепляется в массив arr2, который используется для генерации объекта coursePage, который добавляется в конец массива pages.
Функция createmenu() создает код таблицы с оглавлением, а также элемент "hint". Каждый элемент оглавления реализуется как тег <A> c методами onclick="return loadpage()" onmouseover="displaystatus()" onmouseout="resetstatus()" Затем этот код "вставляется" в элемент документа с идентификатором "andr". Если уровень элемента меньше нуля, то вначале он не показывается (меню свернуто). Меню можно раскрыть с помощью клика. Следующий клик приведет к сворачиванию меню. Если url элемента оглавления непуст, то он запускается в новом окне с помощью функции openit(). При подведении курсора к элементу оглавления появляется подсказка (hint) о статусе элемента.
  



Новое сообщение
 

Послать уведомление по e-mail

Продолжить


Авторизоваться через https://www.pvobr.ru
Логин
Пароль
Регистрация

Авторизоваться через соцсети
Наверх