x3m (мой скрипт - древовидное меню)

 
0
 
JavaScript
ava
Alx | 08.10.2004, 23:18
Это меню ещё не совсем доделано - надо ещё сделать кнопки "Открыть/Скрыть всё", может добавить глубокие слои. Хотя, в принципе, оно и должно быть с одним подслоем, подразделами одного раздела на сайте. Собственно говоря, как сейчас. :)

Но потом можно будет над этим до конца подумать..

Sardar
плиз, не рви мне руки и не загоняй в минусы, я ещё не научился по W3C писать! smile smile
added later:
чё-то я переутомился, линк забыл кинуть... smile
http://beauweb.h12.ru/portfolio/x3m/
Comments (11)
ava
Sardar | 08.10.2004, 23:20 #
Работает в Мозилле, значит хорошо. Внешне красиво, но код "очень не красивый". Выпадание лучше двигать плавнее, причем скорость должна падать по экспоненте, так красивее.
напишу статью как работать и главное понимать события, также установку свойств элемнтам.

Попробую переписать получше, если не против smile
ava
Се ля ви | 09.10.2004, 09:37 #
Вроде неплохо, только чего-то я не понял - почему при отображении пилюсикаа ветка открыта, нажмёшь на пилюсик - он станет минусом и ветка закроется, может, надо наоборот, как в винде, например?

Ну и тормозит пострашному... Видимо из-за того, что ты каждый пункт отдельным слоем сделал - видно что они скрывааются по-одному, мне кажется, нужно их скрывать сразу...

У меня такого рода скрипт есть, год назад писал - правда не столь эстетично выглядит, дизайновой обвески к нему я не делал, но при желании можно:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251" />
<title>JSTree - Dinamic Demo</title>

<script type="text/javascript" language="javascript1.2" src="scripts/tree.js"></script>


<style type="text/css">
<!--

@import url('style/tree.css');

-->
</style>

</head>

<body>

<!-- Здесь вставляется шапка документа -->

<div class="popupMenu" id="popupMenu1"></div>

<script type="text/javascript" language="javascript1.2">
<!--

writeTree();

//-->
</script>


<!-- Здесь вставляется окончание документа и содержимое текущей страницы -->

</body>
</html>

style/tree.css:
/* CSS Document */

.treeGlobal {
width: 300px;
height: 500px;
border: 2px solid #999999;
}

.treeControl {
text-align: right;
}

.treeClose {
cursor: pointer;
background-color:#999999;
color: #000000;
}

.grPlus {
cursor: pointer;
}

.grContents {
padding-left: 15px;
display: none;
}

.popupMenu {
position: absolute;
display: none;
width: 150px;
border: 1px outset #CCCCCC;
background-color: #CCCCCC;

color:#000000;
font-weight: bold;
}

a.popupMenuString:hover {
background-color: #003399;
color: #FFFFFF;
}

.popupMenuStringDefault {

font-weight: bold;
}

hr.menuSeparator {
color: #666666;
width: 150px;
text-align: center;
size: 1px;
height: 2px;
}

scripts/tree.js:
// JavaScript Document

var data = new Array(
"543;1;gr;Новости сайта;",
"533;2;gr;Новости по компьютерам;",
"434;3;st;Новость 1;",
"435;3;st;Новость 2;",
"436;3;st;Новость 3;",
"437;3;st;Новость 4;",
"438;3;st;Новость 5;",
"439;3;st;Новость 6;",
"440;3;st;Новость 7;",
"233;2;gr;Новости Internet;",
"234;3;st;Новость 1;",
"235;3;st;Новость 2;",
"236;3;st;Новость 3;",
"237;3;st;Новость 4;",
"240;3;st;Новость 157;",
"573;1;gr;Публикации в прессе;",
"578;2;st;Публикация №1;",
"579;2;st;Публикация №2;",
"590;2;st;Публикация №3;",
"592;2;st;Публикация №4;",
"596;2;st;Публикация №5;",
"599;2;st;Публикация №6;",
"101;1;gr;Файлы для загрузки;",
"103;2;df;Документация по процессу;",
"104;2;df;Документация по форуму;",
"107;2;df;Документация по регистрации;" );

var counter = new Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1); // Счётчик. Необходим для корректного присвоения атрибута ID элементам, вписываемым в документ.

var plus = new String('[+] '); // строковое значение на щелчке на котором происходит открытие ветви дерева (можно вставить '<img' и др. теги)
var minus = new String('[-] '); // строковое значение на щелчке на котором происходит закрытие ветви дерева (можно вставить '<img' и др. теги)
var point = new String('[o] '); // строковое значение перед отображением нераскрывающейся ветви дерева (можно вставить '<img' и др. теги)


function refreshPopup(popupName, ID){

document.all[popupName].innerHTML =
'<a class="popupMenuString popupMenuStringDefault" href="/redirect/?' + ID + '" onclick="hidePopup(); window.open(\'/redirect/?' + ID + '\', \'view\');" target="view"><div class="popupMenuItem">Открыть</div></a>' +
'<a class="popupMenuString" href="/admin/edit/?' + ID + '" onclick="hidePopup(); window.open(\'/admin/edit/?' + ID + '\', \'view\');" target="view"><div class="popupMenuItem">Редактировать</div></a>' +
'<hr class="menuSeparator" />' +
'<a class="popupMenuString" href="/admin/del_doc.php/?' + ID + '" onclick="hidePopup();"><div class="popupMenuItem">Удалить</div></a>' +
'<a class="popupMenuString" href="/admin/add_doc.php/?' + ID + '" onclick="hidePopup();"><div class="popupMenuItem">Добавить</div></a>';
}


function hidePopup(){

document.all['popupMenu1'].style.display = 'none';
}

function showPopup(ID, X, Y){

refreshPopup('popupMenu1', ID);

document.all['popupMenu1'].style.left = X;
document.all['popupMenu1'].style.top = Y;
document.all['popupMenu1'].style.display = 'block';

return false;
}

function showTreeNode(level, numberOfNode){

if (!level || !numberOfNode) return false;

/* if (document.all['contents_' + level + '_' + numberOfNode].style.display == 'block')
return hideTreeNode(level, numberOfNode);*/

document.all['contents_' + level + '_' + numberOfNode].style.display = 'block';
document.all['plus_' + level + '_' + numberOfNode].onclick = new Function('hideTreeNode(' + level + ', ' + numberOfNode + ')');
document.all['plus_' + level + '_' + numberOfNode].innerText = minus;

return true;
}

function hideTreeNode(level, numberOfNode){

if (!level || !numberOfNode) return false;

document.all['contents_' + level + '_' + numberOfNode].style.display = 'none';
document.all['plus_' + level + '_' + numberOfNode].onclick = new Function('showTreeNode(' + level + ', ' + numberOfNode + ')');
document.all['plus_' + level + '_' + numberOfNode].innerText = plus;

return true;
}


function insertTreeStart(numberOfLines){

document.writeln(
'<span class="treeHeader" id="treeHeader">дереВО! :-)</span>' +
'<div class="treeGlobal" id="treeGlobal">' +
'<div class="treeControl">' +
//<!--span class="treeReduce" id="treeReduceButton" onclick="document.all['treeGlobal'].style.display = 'none'">[_]</span-->
'<span class="treeClose" id="treeCloseButton" onclick="document.all[\'treeGlobal\'].style.display = \'none\'">[x]</span>' +
'</div>\n');
}


function insertGR(ID, LEVEL, NAME) {

document.writeln(
'<span class="grPlus grPlus' + LEVEL + '" id="plus_' + LEVEL + '_' + counter[LEVEL] + '">' + plus + '</span><span class="gr grLevel' + LEVEL + '" id="gr_' + LEVEL + '_' + counter[LEVEL] + '"><a href="/redirect/?' + ID + '" ondblclick="window.open(\'/admin/edit/?' + ID + '\', \'view\');" target="view" oncontextmenu="return false;" onmouseup="if (event.button == 2) showPopup(' + ID + ', event.x, event.y);">' + NAME + '</a></span><br /><div class="grContents gr' + LEVEL + 'Contents" id="contents_' + LEVEL + '_' + counter[LEVEL] + '">\n'
);
document.all['plus_' + LEVEL + '_' + counter[LEVEL]].onclick= new Function ('showTreeNode(' + LEVEL + ', ' + counter[LEVEL]++ + ')');
}

function insertST(ID, LEVEL, NAME) {

document.writeln(
'<span class="stMarker stMarker' + LEVEL + '" id="stMarker_' + LEVEL + '_' + counter[LEVEL] + '">' + point + '</span><span class="st stLevel' + LEVEL + '" id="st_' + LEVEL + '_' + counter[LEVEL]++ + '"><a href="/redirect/?' + ID + '" ondblclick="window.open(\'/admin/edit/?' + ID + '\', \'view\');" target="view" oncontextmenu="return false;" onmouseup="if (event.button == 2) showPopup(' + ID + ', event.x, event.y);">' + NAME + '</a></span><br />\n'
);

}


function insertDF(ID, LEVEL, NAME) {

document.writeln(
'<span class="dfMarker dfMarker' + LEVEL + '" id="dfMarker_' + LEVEL + '_' + counter[LEVEL] + '">' + point + '</span><span class="df dfLevel' + LEVEL + '" id="df_' + LEVEL + '_' + counter[LEVEL]++ + '"><a href="/redirect/?' + ID + '" ondblclick="window.open(\'/admin/edit/?' + ID + '\', \'view\');" target="view" oncontextmenu="return false;" onmouseup="if (event.button == 2) showPopup(' + ID + ', event.x, event.y);">' + NAME + '</a></span><br />\n'
);

}


function insertFU(ID, LEVEL, NAME) {

document.writeln(
'<span class="fuMarker fuMarker' + LEVEL + '" id="fuMarker_' + LEVEL + '_' + counter[LEVEL] + '">' + point + '</span><span class="fu fuLevel' + LEVEL + '" id="fu_' + LEVEL + '_' + counter[LEVEL]++ + '"><a href="/redirect/?' + ID + '" ondblclick="window.open(\'/admin/edit/?' + ID + '\', \'view\');" target="view" oncontextmenu="return false;" onmouseup="if (event.button == 2) showPopup(' + ID + ', event.x, event.y);">' + NAME + '</a></span><br />\n'
);

}



function writeTree(thisDoc){ // Параметр - это id данного документа. Если отсутствует, считаем, что данный документ не доступен из этого дерева. Если присутствует - для него действуют особые правила оформления в дереве.

var S = new String();
var ID = new Number();
var LEVEL = new Number();
var TYPE = new String();
var NAME = new String();

var lastLEVEL = new Number(1);

insertTreeStart(data.length);

for (var x = new Number(0); x < data.length; x++){

S = data[x];

ID = parseInt(S.substring(0, S.indexOf(';')));
S = S.substring(S.indexOf(';') + 1, S.length);

LEVEL = parseInt(S.substring(0, S.indexOf(';')));
S = S.substring(S.indexOf(';') + 1, S.length);

TYPE = S.substring(0, S.indexOf(';'));
S = S.substring(S.indexOf(';') + 1, S.length);

NAME = S.substring(0, S.length - 1);


//alert('ID = ' + ID +'\nLEVEL = ' + LEVEL + '\nTYPE = ' + TYPE + '\nNAME = ' + NAME);

if (lastLEVEL > LEVEL)
for (var y = new Number(LEVEL); y < lastLEVEL; y++ )
document.writeln('</div>');

lastLEVEL = LEVEL;


switch(TYPE){
case "gr": insertGR(ID, LEVEL, NAME); break;
case "st": insertST(ID, LEVEL, NAME); break;
case "df": insertDF(ID, LEVEL, NAME); break;
case "fu": insertFU(ID, LEVEL, NAME); break;
default : alert('Error! Unknown document type - ' + TYPE + '. Please, tell about this to system administrator of this resourse. Thanx.')
}
}
}

document.onclick = function() { hidePopup(); }
//document.oncontextmenu = new Function("return false");
//document.onmouseup = function(){ hidePopup(); }

К сожалению Винда пропатченная sp2`м блокирует... надо подразобраться будет...
ava
Alx | 09.10.2004, 10:54 #
Цитата
Работает в Мозилле

слушай, это наверное мой первый более или менее приличный скрипт, работающий в мозилле. У меня сломался диск с всеми браузерами и я не могу установить их пока, работает только Мозилла, щас сам там посмотрю! :)

Цитата
Попробую переписать получше, если не против

я-то нет, если хочешь, но это будет уже не мой код! smile я тогда ещё сам постараюсь сделать всё, что вы сказали, чтобы смело говориь, что это пусть не отличный скрипт, но мой! :)

кстати тут моё предыдущее меню. Развиваться-то надо! :)

Цитата
Ну и тормозит пострашному...

нет, это из-за того, что каждая папка грузится по отдельности. Просто сейчас один молодой человек рисует для каждого раздела значки, поэтому потом я папки вообще уберу. А если ты имеешь ввиду, что тормозит скрытие-раскрытие меню, то это специально, чтобы плавно было! :)

вчера забыл сказать - я ещё собираюсь сделать интерфейс, для редактирования пунктов и подпунктов. Будет очень удобно всё менять. Это будет большой плюс, согласны? ;-)
ava
Sardar | 09.10.2004, 17:23 #
Это называется "Я мозиллу обновил" smile
ava
Alx | 09.10.2004, 18:02 #
недолго я радовался... smile
ava
Alx | 09.11.2004, 17:54 #
всем приф!

вот. Beta-версия :)

http://alx.h14.ru/x3m/example.html
http://alexandro.narod.ru/x3m.rar

что тут у нас имеется. это - древовидное меню. что с ним может сделать юзер.

на нужную страничку вставляется скрипт с переменными настроек и линка на внешний скрипт с самой прогой. в настройках присутствуют переменные:

var showPM = "ON"; // показывать или нет плюсики и минусики
var showIcons = "ON"; // показывать или нет иконки
var showLines = "OFF"; // показывать или нет линии
var folderTextLink = "OFF"; // чем является текст папок: линкой на что-то или просто кнопкой для открытия папки
var firstimeOpened = "OFF"; // будет ли изначально меню развернуто или нет
var openingSpeed = 70; // скорость развёртывания подменю
var closingSpeed = 70; // скорость свёртывания подменю
var pixDepth = 18; // длина отступа подменю влево от родительского пункта.

как строется генерация меню. Чтобы юзер получил конфигурацию, например
Цитата


Папка 1

  Папка 1.1

    Пункт 1.1.1

    Пункт 1.1.2

  Пункт 1.2

Папка 2

  Пункт 2.1


ему необходимо ввести следующие данные:

var all = ["x3m"];
all[1] = ["Папка 1;papka1;x3m_img/folder_cl.gif"];
all[1][1] = ["Папка 1.1;papka1/papka1;x3m_img/folder_cl.gif"];
all[1][1][1] = ["Пункт 1.1.1;papka1/papka1/1.html;x3m_img/page.gif"];
all[1][1][2] = ["Пункт 1.1.2;papka1/papka1/2.html;x3m_img/page.gif"];
all[1][2] = ["Пункт 1.2;papka1/2.html;x3m_img/page.gif"];
all[2] = ["Папка 2;papka2;x3m_img/folder_cl.gif"];
all[2][1] = ["Пункт 2.1;papka2/1.html;x3m_img/page.gif"];


картинку можно задать любую, как для папки, так и для пункта. если нужно, чтобы при открытии папки, её иконка менялась, необходимо обозвать картинку так, чтобы в ней присутствовали символы cl и в той же директории иконку с одержимым, включающем op.
Например так:

all[1] = ["Папка 1;papka1;my_images/pervayaclpapka.gif"];

и

all[1] = ["Папка 1;papka1;my_images/pervayaoppapka.gif"];

тогда иконка будет меняться.

в скрипте есть 15 встроенных иконок.

Скрипт поддерживается IE и Opera, начиная с 7.0 (прапвда в каком-то глючном виде). Пробовал во всех основных браузерах (MSIE, 3 версии Oper`ы, NN, Mozilla), кроме последнего FireFox.
Если кому не трудно - проверьте, плз, хотя скорее всего там тоже не покатит.

Теперь о том, что к меня не получилось:

1.Функции openAll() и closeAll работают только при

var openingSpeed = 70;
var closingSpeed = 70;


потому что:

2. не получилось сделать так, чтобы плавно закрывались все подменю при закрытии какой-нибудь верхней папки.
Короче говоря, если есть

Цитата


Папка 1

   Пункт 1.1

   Папка 1.2

      Пункт 1.2.1

      Папка 1.2.2

         Пункт 1.2.2.1

      Пункт 1.2.3


при закрытии Папка 1 вся эта байда закрывается в два присеста: вначале всё содержимое Папка 1.2 исчезает, а потом и Пункт 1.1 :( а нужно, чтобы всё было плавно: вот по такому порядку:
Цитата


Пункт 1.2.3

Пункт 1.2.2.1

Папка 1.2.2

Пункт 1.2.1

Папка 1.2

Пункт 1.1


а получается:
Цитата


Папка 1.2

Пункт 1.1


не знаю, как это сделать:( поэтому и закрыть всё и раскрыть всё не работает :(

3. Теоретически меню должно поодерживать линии, указывающие на пункты. Всё бы было хорошо, но я не представляю, как можно реализовать такой вариант:
user posted image
то есть у меня не получилось написать алгоритм, который высчитывал где линии рисовать, а где нет. поэтому пока они отключены.

вот, пожалуй, всё. если ещё чё-нить вспомню - напишу. smile я буду очень рад и преогромно благодарен всем, кто сможет мне что-нибудь подсказать, посоветовать или помочь с решением этих проблем. Прошу также посравнивать мой скрипт с лучшим из мне известных -
http://www.destroydrop.com/javascript/tree/
я знаю, что там есть функции и настройки покруче чем у меня, но у меня тоже кое-что есть. напрмер плавность, возможность выбора абсолютно любой картинки для каждого пункта и папки и т.д. :)

и последнее, 2Sardar
я тут недавно увидел твоё меню, оно тоже "плавное" smile а я думал моё уникально smile. но кому из нас первому пришла эта идея (не из тщеславия спрашиваю, просто интересно smile)? мне где-то в начале октября smile у тебя, конечно, покрасивее меню вылетает, но я не хотел использовать абсолютно позиционированные DIV`ы...
ava
Sardar | 10.11.2004, 00:27 #
В Мозилле не пашет, ругается на отсутствие window.event и другие вещи. Читай мою и Aliance статейку о событиях. Юзаем устаревшие и поддерживаемые только ИЕ коллекции children.

На счтёт плавного закрытия - это до нас с тобой уже придумывали, как и большинство эффектов smile
Моё меню построенно на списках, что лучше таблиц как у тебя. На таблицах сложнее сделать динамичную модификацию меню(подгрузка пунктов меню), да и таблицы глючат под Мозиллой.

P.S. Уже готово, отлаживаю меню для нашего FAQ'а, посмотришь как сделанно ;-) Сейчас какие то не понятные траблы с мозиллой, но это лечится.
ava
Alx | 10.11.2004, 16:05 #
Цитата (Sardar @ 10.11.2004, 00:27)
Моё меню построенно на списках

а можно поподробнее?

насчёт траблов я и сам знаю, только исправить самому не получилось. я знаю, нужно childNodes[n] и parentNode только у меня всё равно не получается.

Ну а вообще, хотелось бы услышать общий отзыв о коде и обо всём остальном (юзабильность, удобство настройки меню и т.п.) :p
ava
Sardar | 10.11.2004, 21:46 #
Цитата (ALEXANDRO @ 10.11.2004, 15:05)
а можно поподробнее?

Открой менюшку, посмотри верстку, она заранее "сгенерированна".

Цитата (ALEXANDRO @ 10.11.2004, 15:05)
только у меня всё равно не получается

Спашивал бы что не получается ;-)


Цитата (ALEXANDRO @ 10.11.2004, 15:05)
Ну а вообще, хотелось бы услышать общий отзыв о коде и обо всём остальном (юзабильность, удобство настройки меню и т.п.)

Это чисто субьективное мнение...
Хранение данных меню в многомерном массиве - издевательство над пользователем, тут даже кодер со стажем запутатся может ;-) Создать обьектный интерфейс - просто.
Траблы с анимацией ты уже описал, траблы с таблицами ты еще познаешь, ну а код... код совсем не очень... :hmmm
Не хочу тебя задеть ;-) если есть желание разобратся и переписать код, то дай знать, шаг за шагом сделаем что-нибудь более удобоваримое smile
ava
Alx | 10.11.2004, 22:10 #
Цитата (Sardar @ 10.11.2004, 21:46)
если есть желание разобратся и переписать код

желание огромное! только самому написать с твоей помощью, а не чтобы ты написал :p :)

Цитата (Sardar @ 10.11.2004, 21:46)
Спашивал бы что не получается

а я откуда знаю? :omg мозилла же не возвращает сообщения с описанием ошибок и что ей там не нравица! :)

Цитата
Хранение данных меню в многомерном массиве - издевательство над пользователем

да? а мне кажется, это легче, чем в dTree... (ссылка выше) ну ладно, а как по другому? ведь если использовать пользовательский класс, будет почти тоже самое? там как?

mytree.add("ID","parentID","text","URL","image")

а у меня

all[1] = ["text,UL,image"]

разве моё не проще выглядит?

Цитата (Sardar @ 10.11.2004, 21:46)
код совсем не очень

лично мне совсем самому не нравится mainFuncOp() и mainFuncClose(). Но как по-другому реализовать передачу ссылки на объект при запуке таймера, я не знаю. столько с этим не промучился. Почему создатели языка не сделают, чтобы можно было задавать таймаут в массиве? например так:

for (var i=0;i<=10;i++;1000)
{document.write(i + "<br>");
}

и строка писалась бы каждую секунду.... :rolleyes
ava
Sardar | 11.11.2004, 00:06 #
Цитата (ALEXANDRO @ 10.11.2004, 21:10)
а я откуда знаю? smile мозилла же не возвращает сообщения с описанием ошибок и что ей там не нравица!

Ну есть же дебаггер Venkman, на крайняк напиши в строка адреса: "javascript:" вылезет окошко с консолью, там все ошибки.
Цитата (ALEXANDRO @ 10.11.2004, 21:10)
разве моё не проще выглядит?

А так(мой избитый прием):
menu=new Menu("здесь можно и имя задать...");
menu.createOption("Опция 1","http://чёртовы.кулички.ru");
menu.createOption("Опция 2");

menu2=new Menu("Подменю уровня 1");
menu2.createOption("Опция подменю 1");
options=["Опция 1", "http://лукоморье.ru", //создадим разом опции, так быстрее
"Опция 2", "http://лукоморье.narod.ru"
]
menu2.createOption("Опция подменю 2").createChildMenu("Я подменю уровня 2").setOptions(options);

menu.getOption(1).setChildMenu(menu2);
menu.expand();
/*
"здесь можно и имя задать..."
`-"Опция 1"
`-"Опция 2"|
`-"Подменю уровня 1"
`-"Опция подменю 1"
`-"Опция подменю 2"|
`-"Я подменю уровня 2"
`-"Опция 1"
`-"Опция 2"
*/

Как видишь куча различных способов модификации меню "на лету" и никаких ID и не нужно, у нас в скрипте есть наше дерево.
Цитата (ALEXANDRO @ 10.11.2004, 21:10)
Почему создатели языка не сделают, чтобы можно было задавать таймаут в массиве?

Не в том направлении мыслишь ;-) На странице просто нельзя сделать задержку в привычном виде(usleep), здесь все работает параллельно smile
Please register or login to write.
Firm of day
Вы также можете добавить свою фирму в каталог IT-фирм, и публиковать статьи, новости, вакансии и другую информацию от имени фирмы.
Подробнее
Contributors
advanced
Submit