php recursive list help - php

I am trying to display a recursive list in PHP for a site I am working on.
I am really having trouble trying to get the second level to display. I have a function that displays the contents to the page as follows.
function get_menu_entries($content,$which=0)
{
global $tbl_prefix, $sys_explorer_vars, $sys_config_vars;
// INIT LIBRARIES
$db = new DB_Tpl();
$curr_time = time();
$db->query("SELECT * FROM ".$tbl_prefix."sys_explorer WHERE preid = '".$which."' && config_id = '".$sys_explorer_vars['config_id']."' && blocked = '0' && startdate < '".$curr_time."' && (enddate > '".$curr_time."' || enddate = '') ORDER BY preid,sorting");
while($db->next_record()){
$indent = $db->f("level") * 10 - 10;
$sitemap_vars['break'] = "";
$sitemap_vars['bold'] = "";
if($db->f("level") == 2) {
$sitemap_vars['ul_start'] = "";
$sitemap_vars['bold'] = "class='bold'";
$sitemap_vars['ul_end'] = "";
}
switch($db->f("link_type"))
{
case '1': // External Url
$sitemap_vars['hyperlink'] = $db->f("link_url");
$sitemap_vars['target'] = "";
if($db->f("link_target") != "") {
$sitemap_vars['target'] = "target=\"".$db->f("link_target")."\"";
}
break;
case '2': // Shortcut
$sitemap_vars['hyperlink'] = create_url($db->f("link_eid"),$db->f("name"),$sys_config_vars['mod_rewrite']);
$sitemap_vars['target'] = "";
break;
default:
$sitemap_vars['hyperlink'] = create_url($db->f("eid"),$db->f("name"),$sys_config_vars['mod_rewrite']);
$sitemap_vars['target'] = "";
break;
}
if($db->f("level") > 1) {
$content .= "<div style=\"text-indent: ".$indent."px;\" ".$sitemap_vars['bold'].">".$db->f("name")."</div>\n";
}
$content = get_menu_entries($content,$db->f("eid"));
}
return(''.$content.'');
}
At the moment the content displays properly, however I want to turn this function into a DHTML dropdown menu.
At present what happens with the level 2 elements is that using CSS the contents are indented using CSS. What I need to happen is to place the UL tag at the beginning and /UL tag at the end of the level 2 elements.
I hope this makes sense. Any help would be greatly appreciated.

Instead of using <div> tags with indentation, use an unordered list for each level, including the first one. Have your function output <ul> at the start and </ul> at the end, and change <div style="text-indent: ..."> to a simple <li>. Give the first level an ID so you can hook onto it. Then you can use CSS to remove bullet points and change the indentation, etc. You don't need to calculate the indentation or whether to bold the text in PHP—instead, use selectors and allow the browser to figure it out:
ul#menu { margin: 0; padding: 0; }
ul#menu > li { margin: 0; padding: 0; }
ul#menu > li > ul { margin-left: 10px; font-weight: bold; }
All this will allow you to use one standard algorithm for generating your list, instead of branching based on the level, as well as making the menu look like a menu to web crawlers, search engines and those with CSS-less browsers.
By the way, you should really be htmlspecialchars-ing all that dynamic text. You don't want a stray < to mess up your markup.

Correct me if I'm wrong, but it seems that your issue is not that you don't know when to print the first set of <ul> tags, but that you are trying to print the second set (for level 2) in every function call, and thus ending up with too many open/close tags.
I think what you should try to do is sort your array by level, first (see uasort() and then you can output your opening <ul> tag on the first loop of the second level (use a counter to keep track of which loop you're on and then do something like if ($i == 0) or if ($i == (count($array) - 1)). This will work no matter how many nested levels you have.

Related

How to create two dynamic text columns that run down a page inline with one another

What I'm looking for is a way to print two complete form elements next to each other as they go down a php page. Essentially two columns of repeating elements.
I have a "div" loop that creates multiple elements on my page using the same div I guess? I'm using two variables to set their location on the page as it goes down, ex. ($down += 200, $left += 200) and it works pretty well. The problem I'm facing is that I have to put an excessive amount of space between each element because some parts are 20px tall and some are 50px tall. With the div loop it looks like they're not aware of each other as far as I can tell meaning all the smaller ones cause the next larger element not to move far enough down the page making them overlap. It'd rather not account for each individual one to only have it do extra space on the smaller ones. I feel like there should be a better option for this. I would also like to avoid a table unless someone can show me a table without the table portion and just the formatting.
while ($results = mysqli_fetch_assoc($towerquery))
{
if ($number % 2 == 0 && $number !== 0 ){ $left = 200; $down += 320; }
print '<span style="display:block;position:relative;left:'.$left.'px;top:'.$down.'px;font-family:tahoma;font-size:13px;margin:40px;">';
$down -= 300;
$left += 500;
}
You can always use Flexbox to create equal height divs:
.paddingBlock {
padding: 20px 0;
}
.eqDisplay {
display: flex;
}
.equal {
padding: 10px;
}
.equal:nth-of-type(odd) {
background: darkgreen;
}
.equal:nth-of-type(even) {
background: black;
}
.eqHW {
flex: 1;
}
.eqHWrap {
justify-content: space-between;
color: #eee;
}
<div class="paddingBlock">
<h1>Equal Column Height</h1>
<div class="eqHWrap eqDisplay">
<div class="eqHW equal">
<p>Using</p>
<p>flex</p>
</div>
<div class="eqHW equal">
<p>works</p>
<p>well</p>
<p>despite</p>
<p>content</p>
<p>length</p>
</div>
</div>
</div>
Using that in php you could echo the results:
<?php
$yourVariable = array(1,9,5,12,73);
echo '<div class="paddingBlock"><div class="eqHWrap eqDisplay">';
while (x === x) {
echo '<div class="eqHW equal">' . $yourVariable . '</div>';
}
echo '</div></div>';
?>
The answer above definitely what lead me down the path to victory and dominance of my webpage, but I had to add a separate part to make it work for me which I have posted below
$number = 0;
if ($number % 2 == 0 || $number == 0 ) { print '<div class="eqHWrap eqDisplay">'; }
print '<div class="eqHW equal">';
print '<p>';
//multiple if statements, span elements, line breaks, returns
print '</p>';
if ($number % 2 !== 0 && $number !== 0 ) { print '</div>'; }
print '</div>';
$number++;
This extra code allowed me to only use one div and have it execute as two, because I'm pulling from an array of IPs and I can't get current and get next at the same time due to the coding disasters I kept running into. I assume other people run into the same problem when creating a loop to pull from an array as you can typically only do one at a time in sequence. My code is now successfully working though as seen below in the link!

Using PHP to check if a CSS stylesheet is active for if/else statement

This is a strange one and it might not even be possible, but what I'm trying to do is check whether a particular stylesheet is loaded, if it is run one code, else run another. For example:
// Create loop counter
$counter = 0;
while ( have_posts() ) {
// MaxIT - Shows 2 listings per loop instead of 2
for ($x = 0; $x < 2; $x++) {
// Increase loop counter
$counter++;
the_post();
// Include listing loop template
get_template_part( 'loop', 'listing' );
} // endwhile have_posts()
echo '<hr style="width:100%; padding-left: 40px; margin: 60px 0px;" />';
}
The point of this code is to display properties on a real estate website. The original code did not have the FOR loop, I added that in so it would display 2 properties at a time before displaying in a horizontal rule. This was purely for aesthetics and looks great when viewing the properties in "grid" view, which shows two properties per row, like:
PROPERTY | PROPERTY
HORIZONTAL RULE
However, the client requested having a list view also, which shows 1 property per row, with image on the left and details on the right. I accomplished this with a second stylesheet which is loaded on click of a drop-down selector. However, because the above PHP loads 2 properties before the HR, it shows like:
PROPERTY
PROPERTY
HORIZONTAL RULE
So what I want to accomplish is having the PHP say "if the grid_view.css is loaded, show 2 properties before the HR, else if the list_view.css is loaded, show 1 property before the HR".
Is this possible with PHP? I'm not familiar with any other programming languages, so if it can be done in Javascript / JQuery that would be fine but I might need the "dummy" explanation if possible.
Thanks heaps in advance!
---- UPDATE / EDIT
Ok, I'm having trouble working out how to do what Justin suggested with "setting a flag" (don't quite understand that terminology tbh) in the PHP, so here's more insight on my current code (and yes it's built on Wordpress, sorry I should have said so earlier).
In my header.php I have...
Argh, having trouble..
So in my header.php I have this...
<link rel="stylesheet" type="text/css" href="/wp-content/themes/wpcasa/slick/slick.css"/>
<link href="/wp-content/themes/wpcasa/lib/assets/css/layout.min.css" rel="stylesheet" type="text/css" title="layoutgrid">
<link href="/wp-content/themes/wpcasa/lib/assets/css/layout_list.css" rel="stylesheet" type="text/css" title="layoutlist">
<script type="text/javascript" src="/wp-content/themes/wpcasa/lib/assets/js/styleswitcher.js"></script>
Only one of those stylesheets is active at a time, whiche one is handled by the styleswitcher.js file...
function setActiveStyleSheet(title) {
var i, a, main;
for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title")) {
a.disabled = true;
if(a.getAttribute("title") == title) a.disabled = false;
}
}
}
function getActiveStyleSheet() {
var i, a;
for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title") && !a.disabled) return a.getAttribute("title");
}
return null;
}
function getPreferredStyleSheet() {
var i, a;
for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
if(a.getAttribute("rel").indexOf("style") != -1
&& a.getAttribute("rel").indexOf("alt") == -1
&& a.getAttribute("title")
) return a.getAttribute("title");
}
return null;
}
function createCookie(name,value,days) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else expires = "";
document.cookie = name+"="+value+expires+"; path=/";
}
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
window.onload = function(e) {
var cookie = readCookie("style");
var title = cookie ? cookie : getPreferredStyleSheet();
setActiveStyleSheet(title);
}
window.onunload = function(e) {
var title = getActiveStyleSheet();
createCookie("style", title, 365);
}
var cookie = readCookie("style");
var title = cookie ? cookie : getPreferredStyleSheet();
setActiveStyleSheet(title);
That is not my code and as mentioned earlier I barely know anything about Javascript.
Then in my search-listings.php file I have this markup to create the selector...
<div class="btn-group">
<button class="btn btn-mini dropdown-toggle" data-toggle="dropdown">View <span class="caret"></span></button>
<ul class="dropdown-menu pull-right">
<li>Grid view</li>
<li>List view</li>
</ul>
</div>
The main issue is that I need the loop counter from the PHP code at the top to run one way or another. The link provided by #aug seemed to make sense, but as far as I know I can't wrap that Javascript around the PHP to achieve what I need to do.
So to recap...
There's a PHP while loop which displays the property listings.
There's a PHP for loop which I wrote inside the while loop to display 2 listings each time the while loop cycles, instead of 1.
The above worked fine until the introduction of the "list" view came about, which due to my lacking PHP knowledge had to be implemented by using a Javascript file to switch the active stylesheet.
I now need a way to still be able to switch to the list view stylesheet, but to either change the $x < 2 to $x < 1 when the list view stylesheet is loaded, OR to be able to have an if / elseif statement that give you either $x < 2 or $x < 1 depending on which stylesheet is loaded.
I hope that makes sense, thanks for all the help so far!
PHP will get processed before any HTML, Javascript or CSS does, so it has no way of telling if the CSS class exists, because it does not exist at that point in time.
In your particular situation I would dump the properties into a JSON object and handle it with Javascript.
EDIT: PHP Specific Solution
Well, I'm making an assumption from your code you are using wordpress, which it may be worth while looking into get_posts() http://codex.wordpress.org/Function_Reference/get_posts
With the limited info and code available, the easiest way is for you that I can see is to set a flag that designates whether or not this is a list view.
lets assume that variable is $listview which is set to true or false.
in your page's template file you can do...
if(!$listview) {
//echo your extra css here...
}
then with your loop you created...
$counter = 0;
if(!$listview) { $hr_counter = 1; } else { $hr_counter = 2; }
while ( have_posts() ) {
// MaxIT - Shows 2 listings per loop instead of 2
for ($x = 0; $x < $hr_counter; $x++) {
// Increase loop counter
$counter++;
the_post();
// Include listing loop template
get_template_part( 'loop', 'listing' );
} // endwhile have_posts()
echo '<hr style="width:100%; padding-left: 40px; margin: 60px 0px;" />';
}
this way you will either do 2 posts then the rule, or 1 post then the rule.
Without seeing more of the code there isn't much else I can assist with in your specific situation.
Hope that helps or gets you headed in the right direction.

Even/Odd to determine CSS class

I've read a lot of information about the determination of a even/odd number and using it to change the class of a div.
In my case I want to switch the position of divs called MessagePicture and MessageText every new message posted.
Picture left, Text right
Picture right, Text left
Picture left, Text right
ect.
This is the code I am using to display the messages, I also included one of my tries to get the even/odd code to work.
Can anyone tell me what I should change to get it to work?
<?PHP
$Query =
"
SELECT
ID,
NameBox,
MessageBox,
Code
FROM
messages
ORDER BY
ID
DESC LIMIT 10
";
$Result = mysql_query($Query);
if(!$Result)
{
echo 'ERROR: '.mysql_error();
}
else
{
if(mysql_num_rows($Result) == 0)
{
echo 'No results';
}
else
{
$i = 0;
$class = (++$i % 2) ? 'even' : 'odd';
while
($Row = mysql_fetch_assoc($Result))
echo '
<div id="MessageWrapper">
<div id="MessagePicture" class="'.$class.'">
<style>
#MessagePicture {
background-image: url(../../../Images/'.stripslashes($Row['Code']).'.png);
background-repeat: no-repeat;
background-position: center
</style>
</div>
<div id="MessageText" class="'.$class.'">
<div id="MessageTitle">
<h1>'.$Row['NameBox'].'</h1>
</div>
<div id="MessageContent">
<p>'.nl2br($Row['MessageBox']).'</p>
</div>
</div>
</div>
';}}}?>
Your $i always stays 0. Add $i++ in the while loop to increment it.
You can do that in one line:
$class = ($i++ % 2 == 0) ? 'even' : 'odd';
Full Example:
$i = 0;
while ($Row = mysql_fetch_assoc($Result)) {
$class = ($i++ % 2 == 0) ? 'even' : 'odd';
//echo ...
}
This may not be an answer to your exact problem, but since any markup already carries information on which of child element rows are even and which are odd, and since CSS is able to differentiate between these, you can achieve this using pure CSS, which is what I boldly offer here.
Use CSS selectors :nth-child(even) and :nth-child(odd) to select even and odd children, respectively. That way you also don't have to change or tag your markup. An example:
<ul>
<li>Apples</li>
<li>Oranges</li>
<li>Bananas</li>
<li>Pears</li>
<li>Pineapples</li>
</ul>
li:nth-child(even)
{
background-color: silver;
}
li:nth-child(odd) /* or leave this one out altogether */
{
background-color: white;
}
Check the following, rather authoritative page for more details and usage (like nth-child(5n+3)):
http://www.w3.org/Style/Examples/007/evenodd.en.html

PHP CSS HTML. Huge amount of data, dynamic columns and boxes

I have a huge list of data I want to display, 10,000's, with filters hopefully just a few thousand at a time.
Languages: HTML, PHP, CSS
I was thinking of the best way to display this data and thought of an idea I like. I would like to have a box (say a div) with a fixed height (90% or 100% of the screen/browser resolution). No horizontal scrolling. Data would display visually in columns, filling the first column, then the second, third, forth, etc.. as many as required. The boxes would house the columns and increase in number as required downwards (for vertical scrolling). This will need to be dynamic as I will not know what data will be displayed (based on filter), I will not know the users browser size etc..
Made a paint image if that helps more:
http://postimage.org/image/630pxp3sx/
If the box thing is not possible, could you at least tell me how to achieve the coloumn effect.
Hope that makes sense.
Ideally I think I want to achieve this with CSS?
Thanks
The closest you can get with pure CSS is with the columns property, but it won't fill exactly the way you want. The elements will fill from top to bottom, left to right, and divided equally so that all of the columns are as close to the same height as possible.
ul {
columns: 5em; /* some browsers require prefixes (eg. -moz-columns, etc.) */
}
http://jsfiddle.net/VQXH3/
Flexbox could do what you're asking for, but support for it is poor at the moment (IE10+, Opera, Chrome; Firefox is adding support for the new spec soon).
http://jsfiddle.net/VQXH3/1/ (try in Opera, didn't add prefixes to the demo)
If you want the columns to be as even as possible, simply figure out how many results are being displayed beforehand. Then, decide how many columns you want to display them. Say you had 100 results, and wanted to divide them among 5 columns, that would be 20 results for each column. You could do something like this in PHP/MySQL:
<?php
$con = mysql_connect('localhost', 'user', 'pass');
$db = mysql_select_db('data');
$get = mysql_query("SELECT * FROM table");
$columns = 5; // number of columns you want to have
$total = mysql_num_rows($get);
$perCol = ceil($total/$columns);
$counter = 0; // start counter at 0 and increment it as the loop progresses
$data = "<div class=\"column\">\n"; // create blank string for storing results
$counterTotal = 0; // keep track of total results
while($a = mysql_fetch_array($get)) {
$counter++;
$counterTotal++;
if ($counter == 1 ) { // no <br /> tag necessary
$data .= " " . $a['data'];
} else {
if ( $perCol == $counter ) {
$data .= "<br />\n " . $a['data'] . "\n</div>\n<div class=\"column\">\n";
$counter = 0; // reset counter for new column
} else {
$data .= "<br />\n " . $a['data'];
}
}
}
$data .= "\n</div>\n";
echo $data;
mysql_close($con);
?>
If you were wondering why I added all the new lines (\n) and whitespace in the code, it's just to make the source code look nice and pretty. :) Feel free to take that out if you wish, but I like my source code to look nice and readable, even when it's being dynamically generated.
Then if you want the columns to fill the whole width of the screen, you can just inject PHP into the <style> tag in the header, like this: (assuming it's on the same page as the code above so you can still access the $columns variable)
<style type="text/css">
.column {
float: left;
width: <?= floor(100/$columns); ?>%;
margin: 0px;
padding: 0px;
}
</style>
Of course this would only work if there is no remainder in the division, but it should come close even if it isn't a perfect division. Here is the code from a sample page I made to do this:
<?php
$con = #mysql_connect("localhost", "user", "pass");
$db = #mysql_select_db("sampleDB", $con);
$get = mysql_query("SELECT * FROM dataTable");
$columns = 5; // number of columns you want to have
$total = mysql_num_rows($get);
$perCol = ceil($total/$columns);
$counter = 0; // start counter at 0 and increment it as the loop progresses
$data = "<div class=\"column\">\n"; // create blank string for storing results
$counterTotal = 0; // keep track of total results
while($a = mysql_fetch_array($get)) {
$counter++;
$counterTotal++;
if ($counter == 1 ) { // no <br /> tag necessary
$data .= " " . $a['data'];
} else {
if ( $perCol == $counter ) {
$data .= "<br />\n " . $a['data'] . "\n</div>\n<div class=\"column\">\n";
$counter = 0; // reset counter for new column
} else {
$data .= "<br />\n " . $a['data'];
}
}
}
$data .= "\n</div>\n";
#mysql_close($con);
?>
<html>
<head>
<title>Data In Columns</title>
<style type="text/css">
.column {
float: left;
width: <?= floor(100/$columns); ?>%;
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<?= $data; ?>
</body>
</html>
If you'd like to see the results of this code, you can check out the sample that I made here: http://mdl.fm/sample.php
UPDATE: If you'd like to fit the content to the height of the screen and determine the number of columns needed, you would need to manually dictate how many items go in each column, so you would make the following replacements:
// replace this
$perCol = ceil($total/$columns);
// with this
$perCol = 20;
$columns = ceil($total/$perCol);
// the line above will just override the manual declaration of $columns
However, PHP cannot detect the browser's dimensions, so if you want to do that, you can forward to the PHP page again via Javascript with the dimensions included. Here is a piece of sample code you could use, put this in the tag of your page:
<script type="text/javascript">
function getDims() {
var myWidth = 0, myHeight = 0;
if( typeof( window.innerWidth ) == 'number' ) {
//Non-IE
myWidth = window.innerWidth;
myHeight = window.innerHeight;
} else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
//IE 6+ in 'standards compliant mode'
myWidth = document.documentElement.clientWidth;
myHeight = document.documentElement.clientHeight;
} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
//IE 4 compatible
myWidth = document.body.clientWidth;
myHeight = document.body.clientHeight;
}
return {
'width' : myWidth,
'height' : myHeight
};
}
function loadDims() {
if ( document.URL.indexOf("?w=") < 0 ) {
var dims = getDims();
window.location.href = '/sample.php?w=' + dims.width + '&h=' + dims.height;
}
}
</script>
Then update your with an onload like this:
<body onload="loadDims();">
At this point, you will know the browser dimensions inside the PHP code, so you can divide the given height by the text-size and see how many items can be contained in one column without the need for scrolling. Again, I have updated my page with this code, so just check it out if you want these complete snippets. Also, if you have any questions implementing them, just contact me through my website (http://mdl.fm) and I'd be glad to help.

Create a dynamic table-like grid without using tables

I am wondering if it's possible to create a grid-like layout using div's that are dynamically created using PHP.
I am creating a product page that will display all products in a PHP database. I want each product to be housed in a div, and 3 divs to display in a row with as many rows as needed to get through all the products.
Something like this:
div div div
$row['product1'] $row['product2'] $row['product3']
div div div
$row['product4'] $row['product5'] $row['product6']
I would prefer not to use a table. I know how to line divs up using the float and clear properties, but not if they are all being created in a while statement, which makes me think it might not be possible.
So I guess, is this possible without using tables, or should I just stick with that?
This can be done the way you ask, though it isn't the best way. It's entirely possible to identify the <div> positions within columns in a while loop:
// Looping over your results simplified...
$i = 1;
while ($results) {
if ($i % 3 == 1) {
$div_class = 'left';
}
else if ($i % 3 == 2) {
$div_class = 'middle';
}
else {
$div_class = 'right';
}
$i++;
// output, simplified
echo "<div class='$div_class'>$row_contents</div>";
}
Then use your CSS to float and clear as necessary for the left, middle, right classes.
.left, .middle, .right {
float: left;
}
.left { clear: left; }
.right { clear: right; }
However,
Given all of this, I still probably wouldn't bother with <div>s. Semantically if this is a list of products, you should be listing them in <li> tags. Then just style the <li> to float: left; and make each one 33% the width of the container so you get 3 per line.

Categories