Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 12 of 12
  1. #1
    Senior Coder
    Join Date
    Apr 2003
    Location
    Canada
    Posts
    1,063
    Thanks
    2
    Thanked 0 Times in 0 Posts

    help with word stacks...

    I am trying to transform a set of two radio buttons in a stack of two labels, one blue and on gray representing, respectively, the selected radio and the unselected one. Clicking on this stack will change which of the labels is blue (and which of the radio buttons is checked). It works well but it breaks down in an ugly manner when the two labels aren't of the same width. The best way to see what I mean is to try the test page I made out on your own server or to navigate here to see the page in action.

    The comments in the source code and actual content explain pretty much what I am aiming for and what the problems are. Also, this is an attempt at accessibility and graceful degradation, so any remarks concerning those issues are most welcome.
    Code:
    <!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>
    		<title>word stacks</title>
    		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    		<style type="text/css">
    
    			.stackContainer
    			{
    				line-height: 2em;	/* Prevents the stackBottom from overlaping the second line of text found in the stack container, should there be a second line. */
    			}
    			
    			.stack
    			{
    				display: inline-block; /* prevent the block options to induce line breaks in your text */
    				line-height: 1; /* Have the 2 options verticaly close to each other */
    				position: relative; /* Moves the lines to be in between*/
    				top: 0.5em;
    				white-space: nowrap; /* prevent line breaks */
    			}
    		
    			.stackTop, .stackBottom
    			{
    				display: block; /* Stack the options on top of each other */
    			}
    			
    			/* The following is extra for presentation */
    			.stackSelected	/* Represents the chosen  value */
    			{
    				color: #009;
    			}
    			
    			.stackUnselected	/* Represents the other option */
    			{
    				color: #777;
    			}
    			
    			.stack
    			{
    				cursor: pointer;
    			}
    			
    			p
    			{
    				margin: 3em;
    			}
    		</style>
    		<?php
    			function createWordStack($name, $value1, $value2)
    			{
    				// Set default values (by default, $value1 is checked and not $value2)
    				$firstChecked = "checked=\"checked\" ";
    				$secondChecked = "";
    				if(isset($_POST[$name]))	// One value was chosen
    				{
    					if($_POST[$name] == $value2)	// Not default value
    					{
    						$firstChecked = "";
    						$secondChecked = "checked=\"checked\" ";
    					}
    					// else fall back to default value
    				}
    				// else fall back to default value
    				// Write out the html
    				echo("<span class=\"stack\">
    						<label for=\"" . $name . "\">
    							<input type=\"radio\" name=\"" . $name . "\" value=\"" . $value1 . "\" " . $firstChecked . "/>" . $value1 . "
    						</label>
    						<label for=\"" . $name . "\">
    							<input type=\"radio\" name=\"" . $name . "\" value=\"" . $value2 . "\" " . $secondChecked . "/>" . $value2 . "
    						</label>
    					</span>");
    			}
    		?>
    		<script type="text/javascript">
    			// It is recommended to use this function only if stacks have been created with the php function createStack and if these stacks are contained in an element of class stackContainer
    			function makeStacks()
    			{
    				var forms = document.getElementsByTagName("form");	// Find all forms
    				var nb_forms = forms.length;
    				for(var i = 0; i < nb_forms; ++i)
    				{
    					if(forms[i].className.indexOf("stackContainer") != -1)	// If it's a stackContainer
    					{
    						var spans = forms[i].getElementsByTagName("span");	// Find all spans
    						var nb_spans = spans.length;
    						for(var j = 0; j < nb_spans; ++j)
    						{
    							if(spans[j].className.indexOf("stack") != -1)	// If it's a stack
    							{
    								var labels = spans[j].getElementsByTagName("label");	// Find all labels
    								var nb_labels = labels.length;
    								if(nb_labels == 2)	// Only works with two labels!
    								{
    									labels[0].className += " stackTop";
    									labels[1].className += " stackBottom";
    									for(var k = 0; k < nb_labels; ++k)
    									{
    										var inputs = labels[k].getElementsByTagName("input");	// Find all inputs
    										var nb_inputs = inputs.length;
    										if(nb_inputs == 1 && inputs[0].type == "radio")	// Only works with one radio button per label!
    										{
    											inputs[0].style.display = "none";	// Hide radio button
    											labels[k].className += (inputs[0].checked)?" stackSelected":" stackUnselected";
    										}
    									}
    								}
    								// add onclick listener to invert which radio button is checked and invert which label appears on top
    								spans[j].onclick = function()
    								{
    									var labels = this.getElementsByTagName("label");	// Find all labels
    									// We already know that there are only two labels, from earlier!
    									for(var l = 0; l < 2; ++l)
    									{
    										// Invert className from stackTop to stackBottom (or vice-versa)
    										if(labels[l].className.match(/stackSelected/))
    										{
    											labels[l].className = labels[l].className.replace(/stackSelected/, "stackUnselected");
    										}
    										else if(labels[l].className.match(/stackUnselected/))
    										{
    											labels[l].className = labels[l].className.replace(/stackUnselected/, "stackSelected");
    										}
    									}
    									// Change which of the radios is checked
    									var inputs = labels[0].getElementsByTagName("input");	// Find all inputs from first label
    									// We already know that there is a single label and that it is a radio, from earlier!
    									if(!inputs[0].checked)	// If this one is not checked, check it to change which of the radios is checked
    									{
    										inputs[0].checked = true;
    									}
    									else
    									{
    										var inputs = labels[1].getElementsByTagName("input");	// Find all inputs from second label
    										// We already know that there is a single label and that it is a radio, from earlier!
    										if(!inputs[0].checked)	// If this one is not checked, check it to change which of the radios is checked
    										{
    											inputs[0].checked = true;
    										}
    										// else there is something wrong as none of the radios are checked!
    									}
    								}
    							}
    						}
    					}
    				}
    			}
    			window.onload = makeStacks;
    		</script>
    	</head>
    	<body>
    		<h1>Word stacks</h1>
    
    		<h2>How it works</h2>
    		<ol>
    			<li>PHP transforms<br />
    				<code>&lt;?php createWordStack("name","one","two"); ?&gt</code><br />
    				into<br />
    				<code>
    					<pre>
    &lt;span class="stack"&gt;
    	&lt;label for="name"&gt;
    		&lt;input type="radio" name="name" value="one" /&gt;one
    	&lt;/label&gt;
    
    	&lt;label for="name"&gt;
    		&lt;input type="radio" name="name" value="two" checked="checked" /&gt;two
    	&lt;/label&gt;
    &lt;/span&gt;
    					</pre>
    				</code>
    			</li>
    			<li>
    				javascript hides the radio buttons, applies class declarations to the labels and adds an onclick event listener to the<br />
    				<code>
    					&lt;span class="stack"&gt;
    				</code>
    			</li>
    		</ol>
    		
    		<h2 id="example">Example</h2>
    		<form action="<?php echo($_SERVER['PHP_SELF'] . "#example"); ?>" class="stackContainer" method="post">
    			<p>Choose between <?php createWordStack("name","one","two"); ?> options.</p>
    			<input type="submit" value="Test that the radio buttons hidden behind this still work" />
    		</form>
    		<h3>print_r($_POST)</h3>
    		<pre>
    			<?php print_r($_POST); ?>
    		</pre>
    
    		<form class="stackContainer">
    			<h2>Known issues</h2>
    			<p>
    				This technique
    				<?php createWordStack("no_matter","absolutely does not","does"); ?>
    				look good with two different sizes of `words`,
    				<?php createWordStack("no_matter2","no matter","although this depends"); ?>
    				in which order they appear. If looks better when the longer word is above the other though. Plus, the way it breaks makes it unreadable when the longer word is on the bottom if the remainder of the text needs to span many lines.
    			</p>
    			<p>
    				Another problem is when the bottom word
    				<?php createWordStack("no_matter3","is","isn't"); ?>
    				longer than the top word but actually consists of a single word. It cannot wrap and therefore interferes with the following text.
    		 	</p>
    		
    			<p>
    				<?php createWordStack("no_matter4","It really becomes unusable and quite ugly if the top word happens to wrap and span over two or more lines. Of course, the first know issue shown above is enough to understand that THIS known issue doesn't mean a thing if it is the bottom that is too long as it will span over many lines no matter what since it is limited by the width of the shorter word above..","It still works"); ?>
    				.. and so, all in all, it is better to avoid long words altogether.
    			</p>
    			<p>
    				Now, just to illustrate what I am saying above.. 
    				<?php createWordStack("no_matter5","Look at this ****!","It really becomes unusable and quite ugly if the top word happens to wrap and span over two or more lines. Of course, the first know issue shown above is enough to understand that THIS known issue doesn't mean a thing if it is the bottom that is too long as it will span over many lines no matter what since it is limited by the width of the shorter word above.."); ?>
    				.. and so, all in all, it is better to avoid long words altogether.
    			</p>
    		 	<h2>Notes</h2>
    			<p>
    				At least, the next paragraph
    				<?php createWordStack("no_matter6","isn't","is"); ?>
    				pushed down too far.
    		 	</p>
    		 	<p>
    				<?php createWordStack("no_matter7","It works","It doesn't work"); ?>
    				when I put the stackBottom BEFORE the stackTop, so I could also call them stackChosen and stackAlternate and just change the className in order to choose one or the other. This is what the javascript used to do when you click on the stack: if the label is of class stackTop, it changes it to stackBottom, and vice-versa. Now, only the colour is changed..
    			</p>
    	 	</form>
    	</body>
    </html>
    I'm sorry, I know this is no way of asking a question, but I just don't know how else to phrase it. I did put much effort in making this test page as clear as possible.

    Thanks in advance
    Last edited by shlagish; 06-23-2010 at 07:35 AM. Reason: Added a doctype declaration and a meta tag defining charset and provided a link to the test page
    Shawn

  • #2
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    25,620
    Thanks
    78
    Thanked 4,388 Times in 4,353 Posts
    Well, I see it working, but I don't understand its utility.

    I see several ways to fix the appearance (primarily by getting rid of the radio buttons completely) but not if the text needs to wrap to another line.

    I don't even understand what it should look like if it needs to be multi-line.
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • #3
    Senior Coder
    Join Date
    Apr 2003
    Location
    Canada
    Posts
    1,063
    Thanks
    2
    Thanked 0 Times in 0 Posts
    Actually, I don't really know how it should look myself if the text needs to be multi-line, hence the question! Here I am asking for your ideas!

    And I do want to keep the radio buttons in case someone without javascript needs to use the form. Plus, that information needs to be passed to the server somehow, doesn't it?

    As for it's utility, it is to condense this huge form I have to something smaller and less... intimidating? You see I have a form with 56 radio buttons and about 150 checkboxes so I feel I need to organize them in the easiest and most condensed way so the user won't be too lost. I have put in tabs, grouped checkboxes together and the such, and now I wish to transform these sets of two radio buttons into one sigle form element which can take two different values, the word stack.

    What if you tell me about your ideas to fix the appearance and we can start from that. Please note that I have made a change to the code so that clicking on a stack no longer changes the order of appearance of the labels, only the colour is changed.
    Shawn

  • #4
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    25,620
    Thanks
    78
    Thanked 4,388 Times in 4,353 Posts
    Okay...

    (1) You get rid of the radio buttons by using <input type="hidden" name="whatever"> in their place.
    (2) You put each stack into a <div>, so that the longer one will force the <div> to that size.
    (3) You use <span>s for each of the texts with onclick handlers on them and simulate radio button action in JS code. You copy the clicked on span to the hidden field.

    Does not, of course, handle mutliple lines at all. The spans would wrap inside the div, but that wouldn't look good, at all.

    I have *not* tried specifying a width for a <span> that is wider than its contents. If that would work, you could take the longer of the two widths and force the shorter to that size and then put all of it inside another <span> instead of a <div>.
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • #5
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    25,620
    Thanks
    78
    Thanked 4,388 Times in 4,353 Posts
    Quote Originally Posted by shlagish View Post
    Please note that I have made a change to the code so that clicking on a stack no longer changes the order of appearance of the labels, only the colour is changed.
    Ahhh...clever! So you just make sure the longer one is on the top. Hmmm...so maybe you don't need more than that??
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • #6
    Senior Coder
    Join Date
    Apr 2003
    Location
    Canada
    Posts
    1,063
    Thanks
    2
    Thanked 0 Times in 0 Posts
    I tried replacing <span class="stack"> with <div class="stack"> (and adjusting the js accordingly). Of course that includes a break before and after the stack, which is undesirable. So I added display: inline; that removed the line break under the stack, but not the one above. Am I doing something wrong? Is there any other way of preventing line breaks from appearing?
    Shawn

  • #7
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    25,620
    Thanks
    78
    Thanked 4,388 Times in 4,353 Posts
    I would think you could stick with <span>. It has the advantage that it *will* word wrap for you. No?
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • #8
    Senior Coder
    Join Date
    Apr 2003
    Location
    Canada
    Posts
    1,063
    Thanks
    2
    Thanked 0 Times in 0 Posts
    I posted the same question on stackoverflow and got a pretty good answer using display: inline-block on the stack and simply display: block on stackTop and stackBottom. I've updated the test page if you want to see the result. I think it's pretty good! I just wonder if it will work cross-browser. I've only been able to test on Firefox and Epiphany.

    Oh, and I will edit the source code in my original post so you can see how that works as well
    Shawn

  • #9
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    25,620
    Thanks
    78
    Thanked 4,388 Times in 4,353 Posts
    Works fine in MSIE 7 except that the long text spans do *NOT* get broken. So the page just gets really wide and you get a horizontal scrollbar. I *suspect* that can be fixed with further styling, using forced word wrap for the container div.

    Aha. Works same in Chrome. So yeah, I think you need to add a style to your container div.

    No, I can't try the code. I don't use PHP. Don't have it installed on my machine. When I looked at it before, I did so by doing VIEW==>>SOURCE of your posted page.
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • #10
    Senior Coder
    Join Date
    Apr 2003
    Location
    Canada
    Posts
    1,063
    Thanks
    2
    Thanked 0 Times in 0 Posts
    Looks like it works in safari and chrome without any troubles. If someone could confirm with Opera, that would be a pass to me!

    Apart from that, what would you suggest as further styling to avoid these really long lines. I guess it either breaks to multiple lines, or it doesn't. Myself, I preffer the huge non breakable lines because I doubt I will ever actually use lines which span that long.. But you never know of course..
    Shawn

  • #11
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    25,620
    Thanks
    78
    Thanked 4,388 Times in 4,353 Posts
    <shrug>If you prefer the non-breakable lines, I would say you are done.

    I don't know if doing <div style="word-wrap: break-word;"> would fix the problem or not.
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • #12
    Senior Coder
    Join Date
    Apr 2003
    Location
    Canada
    Posts
    1,063
    Thanks
    2
    Thanked 0 Times in 0 Posts
    word-wrap: break-word is very much better! Thanks a lot!
    Shawn


  •  

    Tags for this Thread

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •