// Multi-Level System Script - http://coursesweb.net/
// Class to create multiple dropdown <select> lists
var MakeSLists = function() {
// messages displayed
var lang = {
'erraddnct': 'Add a name in text field',
'errchg0': 'Root cannot be changed.',
'errm_name': 'Add a name for resource, between 2 and 250 characters.\n Only Letters, Numbers, "-", and "_"',
'dchanged':'Data changed',
'delitem': 'The selected List and its sub-categories succesfuly deleted'
}
var thisob = this; // stores the 'this' reference of the object with this class
var geto = 'txt'; // if 'mysql' value, gets data from MySQL database
var saveto = 'txt'; // to tell php where to save data
var ctgItems = {'0':[]}; // stores items with 'ctg_id'/option:[id_sub-categories] for each <option> in <select> (starts with 'root')
var ctgData = {'0':{'namec':'Root', 'lurl':'#', 'ctg':':'}};
var opt1 = 0; // to know when is selected `1st option in <select>, 1 (modified in addSubSelect(), used in addCategory())
var ctparent = ':'; // the value for 'ctg' column
var ctid = 0; // id of category /sub-category
var sid = 'sl'; // the id first <select> (Root). Will contain the id of last/current <select>
/** Functions to set <select> data **/
// empty text field for category name, and resets link url
var resetNameUrl = function() {
document.getElementById('namec').value = '';
document.getElementById('lurl').value = '#';
}
// adds category /sub-category in select-lists
function addCategory() {
var namec = document.getElementById('namec').value.replace(/\</g, '<').replace(/\>/g, '>').replace(/"/g, '"'); // option value (replace <>" with their html-encodes)
var lurl = encodeURI(document.getElementById('lurl').value).replace(/\</g, '<').replace(/\>/g, '>').replace(/"/g, '"'); // get link address
if(namec.length > 0) {
// adds it in $ctgData. Gets the last-index, to set /add id of new category
var idct = 0;
for(var ix in ctgData) {
if((ix * 1) > idct) idct = ix * 1;
}
idct++;
// the level-category in this sub-category
if(ctid > 0) var setctg = ctparent+ctid+':';
else var setctg = ctparent;
ctgData[idct] = {'namec':namec, 'lurl':lurl, 'ctg':setctg};
// if parent-category exists in $ctgItems, adds it in array, else, create the parent-category array
if(ctgItems[ctid]) ctgItems[ctid].push(idct);
else ctgItems[ctid] = [idct];
// sets the id of <select> which is displayed with the new category (current select id if it is added in the same select, $opt1 indicates the selection is current <select>)
var sid_next = (opt1 == 1) ? sid : sid+'_n';
// sets the ID of tag in which adds the <select> (current-parent tag if it was selected 1st <option>)
var idadds = (opt1 == 1 && document.getElementById('n_'+sid)) ? document.getElementById('n_'+sid).parentNode.parentNode.id : 'n_'+sid;
// adds the <select> with <option>s and tag for next sub-<select>
if(ctgItems[ctid].length > 0) document.getElementById(idadds).innerHTML = getSelect(ctgItems[ctid], sid_next);
resetNameUrl(); // empty category-name, reset link url
document.getElementById('curentitem').innerHTML = ctgData[ctid].namec; // display curent selected item
document.getElementById('m_menu').innerHTML = setHtml(); // display html code
}
else {
// focus text field, and message
document.getElementById('namec').focus();
alert(lang.erraddnct);
}
}
// modify the name of category/sub-category in last selected <option>
function modifyCategory() {
var namec = document.getElementById('namec').value.replace(/\</g, '<').replace(/\>/g, '>').replace(/"/g, '"'); // option value (replace <>" with their html-encodes)
var lurl = encodeURI(document.getElementById('lurl').value).replace(/\</g, '<').replace(/\>/g, '>').replace(/"/g, '"'); // gets link address
// if not root
if(ctid != 0) {
// change the name and link in ctgData, to the id of category
ctgData[ctid].namec = namec;
ctgData[ctid].lurl = lurl;
var parentid = getParentId(ctid); // gets parent-ID to pas its array with sub-categories to getSelect()
ctid = parentid; // sets current-id to parentid couse refreshes current <select>
opt1 = 1; // to know it is on 1st option in <select>
// re-adds the <select> with <option>s, in the <span> with current <select>
var parentSpan = sid.replace(/_n$/i, '') ? sid.replace(/_n$/i, '') : sid; // span id of current <select>
if(ctgItems[parentid].length > 0) document.getElementById('n_'+parentSpan).innerHTML = getSelect(ctgItems[parentid], sid);
resetNameUrl(); // empty category-name, reset link url
document.getElementById('m_menu').innerHTML = setHtml(); // display html code
document.getElementById('curentitem').innerHTML = ctgData[ctid].namec; // display curent selected item
alert(lang.dchanged);
}
else alert(lang.errchg0);
}
// delete the category in last selected <option> (including all its sub-categories), delete also its id in array of its parent in $ctgItems
function deleteCategory() {
// if not root
if(ctid != 0) {
delete ctgData[ctid];
delete ctgItems[ctid];
var parentid = getParentId(ctid); // gets parent-ID
// traverses the items in parent to remove deleted item
var remainctg = []; // stores the remaining items, to be added in parent
for(var i in ctgItems[parentid]) {
if(ctgItems[parentid][i] != ctid) remainctg.push(ctgItems[parentid][i]);
}
ctgItems[parentid] = remainctg;
addSelCtgs(); // resets data and adds 1st <select> list with main categories
resetNameUrl(); // empty category-name, reset link url
document.getElementById('curentitem').innerHTML = ctgData[0].namec; // display curent selected item
alert(lang.delitem);
}
else alert(lang.errchg0);
}
// returns the ID of parent sub-category (idsct)
var getParentId = function(idsct) {
var parentid = 0;
var breakl = 0;
// traverses the array of each item in $ctgItems, if find idsct, stores to return it, stop the loop
for(var idpr in ctgItems) {
var nrarsubctg = ctgItems[idpr].length;
for(var i=0; i<nrarsubctg; i++) {
if(ctgItems[idpr][i] == idsct) {
parentid = idpr;
breakl = 1;
}
if(breakl == 1) break;
}
}
return parentid * 1;
}
// resets data and adds 1st <select> with main categories
function addSelCtgs() {
// reset these properties couse after delete it is displayed 1st list
ctid = 0;
sid = 'sl';
ctparent = ':';
// if items in Root, shows 1st <select>, else, resets properties to initial value
if(ctgItems[0].length > 0) document.getElementById('n_'+sid).innerHTML = getSelect(ctgItems[0], sid+'_n');
else {
ctgItems = {'0':[]};
ctgData = {'0':{'namec':'Root', 'lurl':'#', 'ctg':':'}};
document.getElementById('n_'+sid).innerHTML = '';
}
document.getElementById('m_menu').innerHTML = setHtml(); // display html code
}
// return <select> list with category-IDs in arsubctg array in $ctgItems, receives the array, and the ID for <select>
var getSelect = function(arsubctg, ids) {
// gets the level of current list
var levelnr = ids.split('_').length - 1;
var slist = '<div><div><sub>Level '+ levelnr +'</sub><select onchange="obMSL.addSubSelect(this)" id="'+ids+'" name="'+ids+'"><option value="'+ctid+'_'+ctparent+'_">---</option>';
var nrarsubctg = arsubctg.length
// traverse the object and create <option> with value=idctg_level
for(var i in arsubctg) {
if(ctgData[arsubctg[i]]) slist += '<option value="'+arsubctg[i]+'_'+ctgData[arsubctg[i]].ctg+'">'+ctgData[arsubctg[i]].namec+'</option>';
}
return slist+'</select></div><span id="n_'+ids+'"></span></div>';
}
// function to get the dropdown list, receives the selected list object
this.addSubSelect = function(slist) {
sid = slist.id; // store the id of selected list in sid property
var opid_lvl = slist.value.split('_'); // separes id and parent-category of selected category /option
ctid = opid_lvl[0] * 1; // id of selected category
ctparent = opid_lvl[1]; // stores the parent-category
document.getElementById('n_'+sid).innerHTML = ''; // empty the tag in which will be added the <select>
// if selected option is 1st <option> (value ends with '_'), empty the tag for next-select
if(slist.value.match(/_$/)) opt1 = 1; // to know it was 1st <option>
else opt1 = 0; // to know isn't 1st <option>
// if exists object (with item) of the selected option in $ctgItems adds the <select> with <option>s and tag for next sub-<select>
// else, empty the tag in which is added the sub-<select> of this <select>
if(opt1 == 0 && ctgItems[ctid] && ctgItems[ctid].length > 0) {
document.getElementById('n_'+sid).innerHTML = getSelect(ctgItems[ctid], sid+'_n');
}
else document.getElementById('n_'+sid).innerHTML = '';
// if not 1st <option> and ctgData item, adds its Name and URL in text field, else, empty those fields
if(opt1 == 0 && ctgData[ctid]) {
document.getElementById('namec').value = ctgData[ctid].namec.replace(/</ig, '<').replace(/>/ig, '>').replace(/"/ig, '"');
document.getElementById('lurl').value = decodeURI(ctgData[ctid].lurl.replace(/</ig, '<').replace(/>/ig, '>'));
}
else resetNameUrl();
document.getElementById('curentitem').innerHTML = ctgData[ctid].namec; // display curent selected item
}
/** Get-Codes functions **/
// adds in #m_menu and #htmlcode textarea the html code of data procesed from $ctgItems and $ctgData
var setHtml = function() {
document.getElementById('m_menu').innerHTML = ''; // to have empty the tag in which adds the html code
// traverses $ctgItems to add each item in html tags
for(var i in ctgItems) {
var addcode = '<ul>'; // stores <li>s with categories of each direct item in $ctgItems
var nrctgi = ctgItems[i].length; // number of categories in each item
// traverses the array with categories in each item, and adds them in tags, with their name from $ctgData
for(var i2=0; i2<nrctgi; i2++) {
var clsli = ctgItems[ctgItems[i][i2]] ? ' class="litems"' : ''; // add class to items with childs
addcode += '<li id="ctg'+ctgItems[i][i2]+'"><a href="'+ ctgData[ctgItems[i][i2]].lurl +'" title="'+ ctgData[ctgItems[i][i2]].namec +'"'+ clsli +'>'+ ctgData[ctgItems[i][i2]].namec +'</a></li>';
}
// closes the html tag, and appends the code in its coresponding category
addcode += '</ul>';
var idul = (i == 0) ? 'm_menu' : 'ctg'+i; // id of current defined <ul>
if(document.getElementById(idul)) document.getElementById(idul).innerHTML += addcode;
}
return document.getElementById('m_menu').innerHTML.replace(/ id="ctg[0-9]+"/ig, ''); // returns html code, deleting the IDs
}
// returns the string with JSON code of objects $ctgItems and $ctgData
var setJsonStr = function() {
return '['+ JSON.stringify(ctgItems) +',\n'+ JSON.stringify(ctgData) +']';
}
// adds in #sqlcode textarea the SQL code that can be used to store $ctgData in SQL database
var setSql = function() {
var addcode = 'CREATE TABLE `table_name` (`id` INT UNSIGNED PRIMARY KEY, `namec` CHAR(255) NOT NULL DEFAULT "", `lurl` VARCHAR(500) NOT NULL DEFAULT "#", `ctg` CHAR(255) NOT NULL DEFAULT ":") CHARACTER SET utf8 COLLATE utf8_general_ci;\nINSERT INTO `table_name` (`id`, `namec`, `lurl`, `ctg`) VALUES ';
// sets to adds the items data from ctgData as rows in SQL
for(var i in ctgData) {
addcode += "("+ i +", '"+ ctgData[i].namec +"', '"+ ctgData[i].lurl +"', '"+ ctgData[i].ctg +"'),";
}
return addcode.replace(/,$/, ''); // returns the code, deleting the last ','
}
// to add codes in textareas
this.addTxtarea = function() {
document.getElementById('htmlcode').value = '<div id="m_menu">'+ setHtml() +'</div>';
document.getElementById('jsoncode').value = setJsonStr();
document.getElementById('sqlcode').value = setSql();
Ajax(0, 'return', document.getElementById('m_style').href);
}
/** Get, Save, Ajax and Others **/
// gets categories data saved in TXT file
this.getData = function() {
var resname = document.getElementById('getctg').value; // resource /menu name
// if $geto is 'txt', get data directly via Ajax, else, if 'mysql', gets with Ajax via php
if(geto == 'txt') Ajax(0, 'get', 'menus/'+ resname +'.txt');
else if(geto == 'mysql') Ajax('ctgres='+ resname +'&saveto='+ geto, 'get', 'setmenu/setmenu.php');
thisob.tabShowHide('sets', 'gets', 'codes'); // switch to Set Data Tab
document.getElementById('ctgres').value = resname; // add resource name in text-field for saving data
}
// gets and pass data to Ajax, to be saved on server
this.saveData = function() {
// if it is added name for resource to save
var ctgres = document.getElementById('ctgres');
if(ctgres.value.match(/^[a-z0-9_-]{2,250}$/i)) {
// sets data (pass categories structure in JSON)
var datasend = 'ctgres='+ ctgres.value +'&sdata='+ encodeURIComponent(setJsonStr()) +'&saveto='+ saveto +'&admname='+ document.getElementById('admname').value +'&admpass='+ document.getElementById('admpass').value;
Ajax(datasend, 'save', 'setmenu/setmenu.php');
}
else {
ctgres.focus();
alert(lang['errm_name']);
}
}
// create the XMLHttpRequest object, according to browser
function getXmlHttp() {
var xmlHttp = null; // will stere and return the XMLHttpRequest
if(window.XMLHttpRequest) xmlHttp = new XMLHttpRequest(); // Forefox, Opera, Safari, ...
else if(window.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); // IE
return xmlHttp;
}
// sends data to PHP and receives the response
function Ajax(datasend, req, tofile) {
var ajaxreq = getXmlHttp(); // get XMLHttpRequest object
ajaxreq.open("POST", tofile, true); // create the request
ajaxreq.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); // header for POST
ajaxreq.send(datasend +'&ajx=1'); // make the ajax request, poassing the data
// checks and receives the response
ajaxreq.onreadystatechange = function() {
if (ajaxreq.readyState == 4) {
// if $req is 'css', adds response in textarea for css code
// if is 'get', request to get data (JSON with two arrays, for $ctgItems, and $ctgData)
// else, request to save data, and alerts response
if(req == 'return') document.getElementById('csscode').value = ajaxreq.responseText;
else if(req == 'get') {
// if menu resource not exists, alerts message, else, gets the JSON, array with two objects, for $ctgItems and $ctgData
if(ajaxreq.responseText.indexOf('not found!<') > 0) alert('The resource: "'+ document.getElementById('getctg').value +'" not found');
else {
var jsonob = JSON.parse(ajaxreq.responseText);
ctgItems = jsonob[0];
ctgData = jsonob[1];
addSelCtgs(); // resets data and adds 1st <select> with main categories
}
}
else if(req == 'save') alert(ajaxreq.responseText);
}
}
}
// for tab effec, receives the ID of element to show and IDs of elements to hide
this.tabShowHide = function(sid, hid1, hid2) {
document.getElementById(sid).style.display = 'block';
document.getElementById(hid1).style.display = 'none';
document.getElementById(hid2).style.display = 'none';
// add class="tabvi" to tab that shows, and deletes it from the other tabs
document.getElementById('tab'+sid).setAttribute('class', 'tabvi');
document.getElementById('tab'+hid1).removeAttribute('class');
document.getElementById('tab'+hid2).removeAttribute('class');
}
// to register events
this.regEvets = function() {
// for radio buttons, to change displayed menu style
document.getElementById('hv_menu').onclick = function(){ document.getElementById('m_style').href = 'setmenu/'+ this.value+'.css'; thisob.tabShowHide('sets', 'gets', 'codes');};
document.getElementById('vh_menu1').onclick = function(){ document.getElementById('m_style').href = 'setmenu/'+ this.value+'.css'; thisob.tabShowHide('sets', 'gets', 'codes');};
document.getElementById('vh_menu2').onclick = function(){ document.getElementById('m_style').href = 'setmenu/'+ this.value+'.css'; thisob.tabShowHide('sets', 'gets', 'codes');};
// for tab efect
document.getElementById('tabgets').onclick = function(){ thisob.tabShowHide('gets', 'sets', 'codes');};
document.getElementById('tabsets').onclick = function(){ thisob.tabShowHide('sets', 'gets', 'codes');};
document.getElementById('tabcodes').onclick = function(){
thisob.tabShowHide('codes', 'gets', 'sets');
thisob.addTxtarea();
};
// tabs-codes
document.getElementById('tabchtml').onclick = function(){ thisob.tabShowHide('chtml', 'cjson', 'csql');};
document.getElementById('tabcjson').onclick = function(){ thisob.tabShowHide('cjson', 'chtml', 'csql');};
document.getElementById('tabcsql').onclick = function(){ thisob.tabShowHide('csql', 'chtml', 'cjson');};
// on change 1st select list
document.getElementById('sl').onchange = function(){ this.addSubSelect(this); }
// button to add/modify/delete category/sub-category
document.getElementById('addctg').onclick = addCategory;
document.getElementById('chgctg').onclick = modifyCategory;
document.getElementById('delctg').onclick = deleteCategory;
// for radio buttons that set from which resource type to get data
document.getElementById('getxt').onclick = function(){ geto = this.value;};
document.getElementById('getmysql').onclick = function(){ geto = this.value;};
document.getElementById('btnget').onclick = thisob.getData; // button to get data
// for radio buttons that set where to save data
document.getElementById('totxt').onclick = function(){ saveto = this.value;};
document.getElementById('tomysql').onclick = function(){ saveto = this.value;};
document.getElementById('toboth').onclick = function(){ saveto = this.value;};
document.getElementById('btnsave').onclick = thisob.saveData; // button to save data
// to auto select data in textarea
document.getElementById('htmlcode').onfocus = function(){ this.select();};
document.getElementById('csscode').onfocus = function(){ this.select();};
document.getElementById('jsoncode').onfocus = function(){ this.select();};
document.getElementById('phpctxt').onfocus = function(){ this.select();};
document.getElementById('sqlcode').onfocus = function(){ this.select();};
document.getElementById('phpcmysql').onfocus = function(){ this.select();};
}
this.regEvets();
}
// create object to MakeSLists
var obMSL = new MakeSLists(); |