development blog.

iText SimSun Degree Symbol Spacing

Thursday, December 29th, 2011

I had a rather odd issue come up a few weeks ago for a client that generates data sheets for it’s Chinese distributors. These data sheets are generated via iText pdf using the SimSun font.

Below is a screen shot of the issue that came up when SimSun renders the degree symbol notice the trailing white space.

Since this was an actual issue with the font and the client requested that we not change the font due to Chinese standards I came up with the following solution.

SimSun supports the ‘Masculine Ordinal’ symbol. This symbol does not have the trailing white space that the ‘degree’ symbol does. So on the fly when it comes time for iText to generate a Chinese Datasheet I replace all Degree symbols with Masculine Ordinals. A little hacky but def the best solution available at the time.


myString.Replace('\u00B0', '\u00BA'); //replace degree with masculine ordinal

Weebly Automatically Generated Left Menu via jQuery

Thursday, September 8th, 2011

I’ve helped a few people put together websites using Weebly, since it’s a tool that non-technical people can easily use to manage and maintain their sites. However, Weebly currently does not offer the option of a left menu. I don’t particularly like all the moving dropdown menus. It just seems to busy for me.

So, here’s my solution to generate a left menu based based on the structure of the site. Basically, I grab the dropdown links and copy them into a side menu structure. I will note that you should be aware when you’re creating a site that the content will be shifted over. I have not adjusted the css to represent this myself, because it doesn’t really matter to me.

To see an example of this in action, go to www.highquest.info

Reference jQuery

Add a link to jQuery in the section on index.html:


<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>

The JavaScript

Add the following javascript code to the index.html page type html, probably at the bottom but inside the body tag. (or any other page types you’ve defined. You could actually have this for every page but the main page to keep left menus off that if you want.)
(Click Design => Edit HTML/CSS => index.html)


<script type="text/javascript">
      // You need this since Weebly uses another JavaScript library
      jQuery.noConflict();        

      function AddMenu() {

        // Find active link
        var activeLink = jQuery("#active");
        if (activeLink.length == 0) {
          activeLink = jQuery(".wsite-nav-current");
        }       

        var linkParent = activeLink;

        //find root page
        while (linkParent.parent().parent().hasClass("wsite-menu-wrap")) {
          linkParent = linkParent.parent().parent().parent();
        }

        // add menus when there are sub items to the root page -- but don't when there are no children (main page)
        if (linkParent .find("div").length > 0) {
          var contentDiv = jQuery("#wsite-content");

          //I add a table structure, which I know isn't the best, but it works well here.
          contentDiv.html("<table class='leftmenupage'><tr><td class='leftmenu'>" + linkParent.html()
                          + "</td><td class='rightcontent'>" + contentDiv.html()+ "</td></tr></table>");

          jQuery(".leftmenu div").show();
        }

        // Mark main nav link with id="active"
        var linkHref = linkParent.find("a").attr("href");
        var navLinks = jQuery("#navigation a");
        for (var i = 0; i < navLinks.length; i++) {
          if (navLinks.eq(i).attr("href") == linkHref) {
            navLinks.eq(i).parent().attr("id", "active");
          }
        }

      } 

      AddMenu();

 </script>

The CSS


ul.wsite-menu li { padding-bottom: 5px; } 

.leftmenupage { margin-left: -15px; width:850px; } 

td.leftmenu {
  width: 200px;
  white-space: nowrap;
  padding: 7px 7px;
  vertical-align: top;
  border-radius: 15px;
  background: #ddd;
  color: #333;
  padding: 12px 12px;
  min-width: 200px;
  min-height: 250px;
} 

td.leftmenu li { padding-bottom: 7px; }
td.leftmenu a {
  color: #333;
  font-size: 1.33em;
  padding: 5px 0px;
  display: block;
}
td.leftmenu a:hover {text-decoration: underline; }

td.leftmenu li a { font-size: 1em; }

td.leftmenu li{
  color: #333;
  font-size: 1em;
  padding: 2px 0px;
}
td.leftmenu li li {
  color: #333;
  font-size: 1em;
  padding: 2px 0 2px 15px;
} 

td.rightcontent {
  width: 75%;
  padding-left:25px;
  width: 650px;
}

Scrollable DataGrid table with Fixed Header with jQuery

Thursday, August 25th, 2011

Problem

Implement scrolling on a table, but make the header fixed.

I had a really long table and wanted to make it scrollable, but keep the header in place. I saw a few examples of this, but with very little explanation to go with it. So, I just did it myself.

Sample Markup


<div>

  <table id="MyDataRows">

    <thead>
      <tr class="grid_header">
        <th>Col1</th>
        <th>Col2</th>
        <th>Col3</th>
      </tr<>
    </thead>

    <tbody>
      <tr>
        <td>Data</td>
        <td>Data</td>
         <td>Data</td>
      </tr>
    </tbody>
  </table>

</div>

First Attempt

So, the first option I saw online was to add “overflow-y: auto; display: block; height: 330px;” to the tbody tag. I saw somewhere where this could work with a single column, but with multiple columns, the header is pushed to the right, and the table rows are pushed to the left. I played with this awhile, but never could get it to work.

Solution

While not as elegant as I would like, this solution does work. Of course, if you isolate the header and then wrap the data rows in a div with the overflow-y stuff, that would work. However, a datagrid populates the header automatically. You could build another datagrid and mess with that, but jQuery quickly solves the issue. Here’s the plan:

  • Add a place for the header to be moved outside of the table with the rows where the overflow-y will be used
  • Move the header
  • Realign the columns

New Markup

This is pretty basic.  I added a table just before the table with data in it.  This will hold the header.  I also styled the div to allow for scrolling.


<table id="MyHeader"></table>

<div style="overflow-y: auto; height: 330px;">

  <table id="MyDataRows">

    <thead>
      <tr class="grid_header">
        <th>Col1</th>
        <th>Col2</th>
        <th>Col3</th>
      </tr>
    </thead>

    <tbody>
      <tr>
        <td>Data</td>
        <td>Data</td>
        <td>Data</td>
      </tr>
    </tbody>
  </table>

</div>

jQuery Code


<script type="text/javascript">// <![CDATA[
$(function () {
    /* move the table header from the datagrid outside, so it doesn't scroll" */
    $("#MyHeader").append($("#StudentData thead"));
    $("#MyDataRows").css("margin-bottom", "0");

    var ths = $("#MyHeader th");
    var tds = $("#MyDataRows tr:first td");

    /* Reset the padding of the th's to match the td's */
    ths.css("padding-left", tds.first().css("padding-left"));
    ths.css("padding-right", tds.first().css("padding-right"));

    /* Set the widths of all the th's (except the last to acccount for scroll bar) to the corresponding td width */
    for (var i = 0; i < tds.length - 1; i++) {
        ths.eq(i).width(tds.eq(i).width());
    }
});
// ]]></script>

Final Markup

So, the end result is two tables whose column widths match but which function as a scrollable datagrid table with a fixed header.


<table id="MyHeader">
  <thead>
    <tr class="grid_header">
      <th>Col1</th>
      <th>Col2</th>
      <th>Col3</th>
    </tr>
  </thead>
</table>

<div style="overflow-y: auto; height: 330px;">

  <table id="MyDataRows">

    <tbody>
      <tr>
        <td>Data</td>
        <td>Data</td>
        <td>Data</td>
      </tr>
    </tbody>

  </table>

</div>

Aligning a List of Checkboxes with Text that Wraps

Friday, June 17th, 2011

Summary

I ran into a problem where there was a list construct and each item was a checkbox. When the text of the checkbox wrapped, the alignment was all messed up, so I came up a way to make it look better.  I also had some additional items I wanted to be aligned as well, so I put those things in a div.

Screenshots

Here’s how it looks with and without the formatting:

Without the formatting (may need to zoom in)

With Formatting

HTML


<div class="checkboxlist">
    <ul>
        <li>
            <asp:CheckBox ID="CheckBox1" runat="server" Text="This is a checkbox option in an unordered list that is pretty long and ends u wrapping onto another line, but maintains alignment" />
        </li>
        <li>
            <asp:CheckBox ID="CheckBox2" runat="server" Text="This is yet another checkbox option in an unordered list that is pretty long and ends u wrapping onto another line, but maintains alignment" />
            <div>
                <br /> Here's some other info as well that isn't a part of the checkbox. The alignment for this works as well.
            </div>
        </li>
    </ul>
</div>

CSS


div.checkboxlist ul li { margin: 7px 0px; }
div.checkboxlist ul li input { width: 15px; display: block; float:left;}
div.checkboxlist ul li label { padding-left: 28px; display: block; }
div.checkboxlist ul li div { margin-left: 28px; clear: both; font-size: .9em; }

Custom ASP.NET JQuery Slider Control

Friday, June 17th, 2011

I found a really nice jQuery slider control that I incorporated into an ASP.NET Custom Control. My apologies, though, that I can’t find where I got this code. It may be just the jQuery UI slider.

I have added the following properties:

  • Initial Value
  • Max Value
  • Min Value
  • Increment
  • Selected Value

This allows you to specify a large range of values, like 0 to 100, but then you can set an increment of 5 or 10 so that there are only 10 or 20 values to select from rather than 100.  For instance, if you were having the user select a rotation value, you could have 0 to 360 degrees, but 360 values on a slider is a bit too much.  So, you set the increment to 15, and they have 24 values for which they can actually see a noticeable difference.

The Initial Value is just that–it lets you set the default.  Use the Selected Value to get the value that was selected.

 

Anyway, here’s the code:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Globalization;

namespace Components
{
public class Slider: System.Web.UI.WebControls.WebControl, INamingContainer
{
TextBox txtValue;

#region Properties...

public int InitialValue
{
get
{
object o = ViewState["InitialValue"];
if (o == null)
return 0;
else
return (int) o;
}
set
{
EnsureChildControls();

ViewState["InitialValue"] = value;
txtValue.Text = value.ToString();
}
}
public int MaxValue
{
get
{
object o = ViewState["MaxValue"];
if (o == null)
return 0;
else
return (int)o;
}
set
{
ViewState["MaxValue"] = value;
}
}
public int MinValue
{
get
{
object o = ViewState["MinValue"];
if (o == null)
return 0;
else
return (int)o;
}
set
{
ViewState["MinValue"] = value;
}
}

public int Increment
{
get
{
object o = ViewState["Increment"];
if (o == null)
return 1;
else
return (int)o;
}
set
{
ViewState["Increment"] = value;
}
}
public int SelectedValue
{
get
{
return int.Parse(txtValue.Text);
}
}

#endregion

protected override void CreateChildControls()
{
base.CreateChildControls();

txtValue = new TextBox();
txtValue.ID = "txtValue";
txtValue.Text = InitialValue.ToString();
Controls.Add(txtValue);
}

protected override void Render(HtmlTextWriter htw)
{
EnsureChildControls();

DataAccess.Organization org = DataAccess.Organization.Get(Components.Classes.User.OrgID);

OutputLine(htw, IndentionType.IncreaseIndent, "<div>");
OutputLine(htw, IndentionType.NoIndent, "<script type=\"text/javascript\">");
OutputLine(htw, IndentionType.IncreaseIndent, "$(function() { FLTK.slidercontrol.init(\"" + this.ID + "\"," + MaxValue + "," + MinValue + "," + Increment + ");});");
OutputLine(htw, IndentionType.DescreaseIndent, "</script>");

OutputLine(htw, IndentionType.NoIndent, "<div id=\"" + this.ID + "\" class=\"ui-slider-container\" width=\"" + this.Width + "\">");

OutputLine(htw, IndentionType.IncreaseIndent, "<div class=\"sliderdisplayvalue\"></div>");
OutputLine(htw, IndentionType.NoIndent, "<div class=\"slider\"></div>");

OutputLine(htw, IndentionType.NoIndent, "<div class=\"slidervalue\">");
OutputLine(htw, IndentionType.IncreaseIndent, txtValue);
OutputLine(htw, IndentionType.DescreaseIndent, "</div>");

OutputLine(htw, IndentionType.DescreaseIndent, "</div>");
OutputLine(htw, IndentionType.DescreaseIndent, "</div>");
}

#region Output Routines...

private void OutputLine(HtmlTextWriter output, IndentionType indention, string text)
{
if (indention == IndentionType.IncreaseIndent)
output.Indent++;
else if (indention == IndentionType.DescreaseIndent)
output.Indent--;

output.WriteLine(text);
}

private void OutputLine(HtmlTextWriter output, IndentionType indention, Control control)
{
if (indention == IndentionType.IncreaseIndent)
output.Indent++;
else if (indention == IndentionType.DescreaseIndent)
output.Indent--;

try
{
control.RenderControl(output);
}
catch
{
output.WriteLine("*************************<BR>");
}
}

private void OutputLine(HtmlTextWriter output, IndentionType indentionBefore, IndentionType indentionAfter, Control control)
{
if (indentionBefore == IndentionType.IncreaseIndent)
output.Indent++;
else if (indentionBefore == IndentionType.DescreaseIndent)
output.Indent--;

try
{
control.RenderControl(output);
}
catch
{
output.WriteLine("*******<BR>");
}

if (indentionAfter == IndentionType.IncreaseIndent)
output.Indent++;
else if (indentionAfter == IndentionType.DescreaseIndent)
output.Indent--;
}

private enum IndentionType
{
NoIndent = 0,
IncreaseIndent = 1,
DescreaseIndent = 2
}

#endregion

}
}

The JavaScript that makes this work is here:


slidercontrol = {
init: function (cntrl, maxValue, minValue, step) {
var sliderCntrl = $("#" + cntrl);
var thisDiv = sliderCntrl.find(".ui-slider-container");
var currVal = sliderCntrl.find(".slidervalue :input").val();

sliderCntrl.find(".slider").slider(
{
value: currVal,
max: maxValue,
min: minValue,
step: step,
change: function (event, ui) { FLTK.slidercontrol.updateSlider(sliderCntrl, ui.value); },
slide: function (event, ui) { FLTK.slidercontrol.updateSlider(sliderCntrl, ui.value); }
});

slidercontrol.updateSlider(sliderCntrl, currVal);
},
updateSlider: function (cntrl, value) {
cntrl.find(".slidervalue :input").val(value);
cntrl.find(".sliderdisplayvalue").text(value);
}
}

And here’s my CSS:


/* Slider */
.ui-slider { position: relative; text-align: left; }
.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.25em; height: 1.5em; cursor: default; }
.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
.ui-slider .ui-state-default { height: 1.7em; }

.ui-slider-standard-width { width: 400px; }
.ui-slider-container {  }
.ui-slider-container .slider { margin-left: 25px; padding-top: 3px;}
.ui-slider-container .slidervalue { display: none; }
.ui-slider-container .sliderdisplayvalue { float:left; text-align: right;  }

.ui-slider-horizontal { height: 1.2em; }
.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
.ui-slider-horizontal .ui-slider-range-min { left: 0; }
.ui-slider-horizontal .ui-slider-range-max { right: 0; }

.ui-slider-vertical { width: .8em; height: 100px; }
.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
.ui-slider-vertical .ui-slider-range-max { top: 0; }

I use this on my Custom ASP.NET Chart Control to specify a variety of options.