<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title><![CDATA[Jorkin.ME - 蜗居，我们离“家”越来越远。 - 技术天地]]></title>
<link>http://Jorkin.ME/</link>
<description><![CDATA[为了谁？为了什么？值不值得？为什么别人那么幸福？-Jorkin.ME]]></description>
<language>zh-cn</language>
<copyright><![CDATA[Copyright 2005 PBlog3 v2.8]]></copyright>
<webMaster><![CDATA[Jorkin2000(AT)hotmail.com(Jorkin)]]></webMaster>
<generator>PBlog2 v2.4</generator> 
<image>
	<title>Jorkin.ME - 蜗居，我们离“家”越来越远。</title>
	<url>http://Jorkin.ME/images/logos.gif</url>
	<link>http://Jorkin.ME/</link>
	<description>Jorkin.ME - 蜗居，我们离“家”越来越远。</description>
</image>

			<item>
			<link>http://Jorkin.ME/article.asp?id=662</link>
			<title><![CDATA[[转]100% Table Height]]></title>
			<author>Jorkin2000(AT)hotmail.com(Jorkin)</author>
			<category><![CDATA[技术天地]]></category>
			<pubDate>Mon,12 Jul 2010 10:01:49 +0800</pubDate>
			<guid>http://Jorkin.ME/default.asp?id=662</guid>
		<description><![CDATA[<p><img alt="" align="right" width="100" height="100" src="http://Jorkin.ME/upload/month_1007/tableheight.gif" />Occasionally designers may want to center content in a web page and they want it centered both horizontally and vertically. The traditional method for doing that is to put the content into a table and to assign a values of 100% to the table's <code>HEIGHT</code> attribute and center to the <code>ALIGN</code> attribute. Recently, that approach has become more problematic.</p>
<p>You may have used this before and had it work but now, for some reason, new pages you create won't center vertically. You may be changing pages from standard HTML to XHTML and now tables don't respect the 100% <code>HEIGHT</code> attribute. Read on.</p>
<p>There are a few things you need to know here. There is not now, nor has there ever been a <code>HEIGHT</code> attribute for tables. Scour the <a href="http://www.w3.org/TR/html401/struct/tables.html#h-11.2.1">HTML specifications</a> and you will not find <code>HEIGHT</code> among the attributes for the table tag. The fact is, table height is <strong>invalid code</strong>. If you attempt to validate a page where you have assigned a height to a table, it will fail. Assigning a height to the table tag is not the answer. You can, however, legally assign a height using CSS.</p>
<h2>Rendering Modes</h2>
<p>But why, you ask, did it used to work and now it doesn't? Without going into a lot of specifics, the answer is that it has to do with the browser's rendering mode as determined by the document's <code>DOCTYPE</code>. You can read a lot more about that subject on <a href="http://www.ericmeyeroncss.com/bonus/render-mode.html">Eric Meyer's companion site</a> for his book <em>Eric Meyer on CSS</em>. The point is that browsers, rendering pages in quirks mode, expand tables to fill the 100% <code>HEIGHT</code>. Browsers rendering pages in standards compliance mode don't. That means that, if a page has a full and proper <code>DOCTYPE</code>, including the URI, or if it uses an XHTML <code>DOCTYPE</code>, the browser will render the page in standards compliance mode. If a page does not have a <code>DOCTYPE</code>, or if it has a partial <code>DOCTYPE</code> without the URI, the the browser will render the page in quirks mode. Newer web design software has begun inserting the full <code>DOCTYPE</code> in pages, so the pages get rendered in standards compliance mode.</p>
<p>Now don't get ahead of me. About now, you're thinking that all you need to do is remove the <code>DOCTYPE</code> and your tables will render the way you want them to. There are downsides to depending on quirks mode to render your page. Rendering pages in quirks mode, browsers use all the old bugs from prior versions, which means that you are less likely to get consistent rendering across different browsers and/or platforms. You wind up paying a hefty price to obtain your goal.</p>
<p>Fear not! There is a way to accomplish this, without resorting to quirks mode rendering. The answer will <strong>not</strong> make the invalid code magically become valid, but it will work in most browsers except for Internet Explorer on the Mac platorm.</p>
<h2>Why Percentage Height Fails</h2>
<p>Okay, to begin, maybe I should explain exactly why 100% height fails. Contrary to popular opinion, it is not because the browser ignores the invalid <code>HEIGHT</code> attribute. The real reason it fails is that the browser does not expand the <code>HTML</code> and/or <code>BODY</code> (depending on the browser) to fill the browser viewport. The browser is in almost all cases, in fact, rendering the table as 100% high. The problem is that it is 100% of the containing element (<code>HTML</code> and <code>BODY</code>), which may not be as high as the browser's veiwport. The <code>HTML</code> and <code>BODY</code> tags represent block elements that automatically expand to fill the width of their container, which is the browser's viewport. They do <strong>not</strong> expand vertically. That can be fixed. Consider the following CSS:</p>
<pre>
   html,body{
      margin:0;
      padding:0;
      height:100%;
      border:none
   }
	</pre>
<p>What does that do? That CSS tells the browser that the <code>HTML</code> and <code>BODY</code> elements have no padding, margin, or border and that their height is 100% of their containing elements. The containing element is the browser viewport! The margin, padding and border are set to zero because failing to do so would mean that the browser would use its default values and the margin and/or padding would be applied <em>outside</em> the 100% resulting in a scroll bar even when none was really needed.</p>
<h2>Using Valid Code</h2>
<p>If you're interested in writing valid code, you still have a problem because, in case I failed to mention it, table <code>HEIGHT</code> is invalid. Now you need to decide which is more important to you, writing valid code or getting the 100% height to display in Netscape version 4. Netscape 4's old and buggy implementation of CSS fails to render the CSS specified height.</p>
<p>If you can accept that NN4 will not display the 100% height, the &quot;proper&quot; way to do it would be to set the table height using CSS. My recommendation would be to create a ID selector in your style sheet that could be applied to a particular table. That way, you needn't worry about all tables on the page being affected. The ID definition might look something like this:</p>
<p><code>#fullheight{height:100%}</code></p>
<p>You would then apply the fullheight ID to your table like this:</p>
<p><code>&lt;table id=&quot;fullheight&quot; ... &gt;</code></p>
<h2>Vertical Centering</h2>
<p>Now that we have achieved 100% height with our table, it becomes a simple matter to center content. Let's take the following CSS:</p>
<pre>
   html, body, #wrapper {
      height:100%;
      margin: 0;
      padding: 0;
      border: none;
      text-align: center;
   }
   #wrapper {
      margin: 0 auto;
      text-align: left;
      vertical-align: middle;
      width: 400px;
   }
	</pre>
<p>Use the above CSS along with the following HTML:</p>
<pre>
   &lt;body&gt;
   &lt;table id=&quot;wrapper&quot;&gt;
      &lt;tr&gt;
         &lt;td&gt;This is centered&lt;/td&gt;
      &lt;/tr&gt;
   &lt;/table&gt;
   &lt;/body&gt;</pre>
<h2>The results</h2>
<p>Okay, I know that this discussion has been a bit longer and more involved that my usual &quot;examples&quot; and the reason is that I thought it was important to understand <em>how</em> and <em>why</em> the results are what they are. Here are four examples you can look at. Each will open in a new browser window and you can view the source code to see how it's done. The first three examples use exactly the same table markup. The last one uses CSS to style the table and set its height, which <strong>is</strong> perfectly valid.</p>
<ul>
    <li><a target="_blank" onclick="return ShowExample('/examples/tables/quirks.html');" href="http://apptools.com/examples/tables/quirks.html">Quirks mode rendering 100% height that works</a></li>
    <li><a target="_blank" onclick="return ShowExample('/examples/tables/standards.html');" href="http://apptools.com/examples/tables/standards.html">Standards mode rendering 100% height that fails</a></li>
    <li><a target="_blank" onclick="return ShowExample('/examples/tables/standardscss.html');" href="http://apptools.com/examples/tables/standardscss.html">Standards mode rendering that works with CSS</a></li>
    <li><a target="_blank" onclick="return ShowExample('/examples/tables/valid.html');" href="http://apptools.com/examples/tables/valid.html">Standards mode valid code rendering that works </a></li>
</ul>
<p>Like I said, this technique works in almost all browsers. The exception is Internet Explorer on the Mac.</p>
<p align="center">Good luck!</p>]]></description>
		</item>
		
			<item>
			<link>http://Jorkin.ME/article.asp?id=659</link>
			<title><![CDATA[JavaScript Interface Library for Microsoft Access]]></title>
			<author>Jorkin2000(AT)hotmail.com(Jorkin)</author>
			<category><![CDATA[技术天地]]></category>
			<pubDate>Mon,01 Mar 2010 11:35:55 +0800</pubDate>
			<guid>http://Jorkin.ME/default.asp?id=659</guid>
		<description><![CDATA[<p><strong>ACCESSdb</strong> is a JavaScript library used to dynamically connect to and query <i>locally available</i> Microsoft Access database files within Internet Explorer. All you need is an .mdb file; Access does not even need to be installed! All of the SQL queries available in Access can be executed on the fly, including Selects, Inserts, Updates, and JOINs. Results are output in several customizable formats including JSON, XML, and HTML.</p>
<p><a href="http://sourceforge.net/projects/accessdb/" target="_blank">Project Home</a> | <a href="http://sourceforge.net/project/showfiles.php?group_id=256504&amp;package_id=314492" target="_blank">Downloads</a> | <a href="http://sourceforge.net/scm/?type=svn&amp;group_id=256504" target="_blank">Subversion</a> </p>]]></description>
		</item>
		
			<item>
			<link>http://Jorkin.ME/article.asp?id=657</link>
			<title><![CDATA[Managing Hierarchical Data in MySQL]]></title>
			<author>Jorkin2000(AT)hotmail.com(Jorkin)</author>
			<category><![CDATA[技术天地]]></category>
			<pubDate>Mon,01 Feb 2010 16:16:56 +0800</pubDate>
			<guid>http://Jorkin.ME/default.asp?id=657</guid>
		<description><![CDATA[<p>中文翻译：<a href="http://www.cnblogs.com/phaibin/archive/2009/06/09/1499687.html" target="_blank">http://www.cnblogs.com/phaibin/archive/2009/06/09/1499687.html</a></p>
<p>下载：<a href="http://www.itpub.net/viewthread.php?tid=1260440" target="_blank">Joe Celko's.Trees and Hierarchies in SQL for Smarties.pdf</a></p>
<p>其它资源：<a href="http://www.itpub.net/thread-1233846-1-1.html" target="_blank">http://www.itpub.net/thread-1233846-1-1.html</a></p>
<h3>Introduction</h3>
<p>Most users at one time or another have dealt with hierarchical data in a SQL database and no doubt learned that the management of hierarchical data is not what a relational database is intended for. The tables of a relational database are not hierarchical (like XML), but are simply a flat list. Hierarchical data has a parent-child relationship that is not naturally represented in a relational database table.</p>
<p>For our purposes, hierarchical data is a collection of data where each item has a single parent and zero or more children (with the exception of the root item, which has no parent). Hierarchical data can be found in a variety of database applications, including forum and mailing list threads, business organization charts, content management categories, and product categories. For our purposes we will use the following product category hierarchy from an fictional electronics store:</p>
<p><img alt="" src="http://jorkin.reallydo.com/UPLOAD/month_1001/hierarchical-data-1.png" /></p>
<p>These categories form a hierarchy in much the same way as the other examples cited above. In this article we will examine two models for dealing with hierarchical data in MySQL, starting with the traditional adjacency list model.</p>
<h3>The Adjacency List Model</h3>
<p>Typically the example categories shown above will be stored in a table like the following (I'm including full Create and Insert statements so you can follow along):</p>
<pre>Create TABLE category(
category_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20) NOT NULL,
parent INT DEFAULT NULL);
Insert INTO category
VALUES(1,'ELECTRONICS',NULL),(2,'TELEVISIONS',1),(3,'TUBE',2),
(4,'LCD',2),(5,'PLASMA',2),(6,'PORTABLE ELECTRONICS',1),
(7,'MP3 PLAYERS',6),(8,'FLASH',7),
(9,'CD PLAYERS',6),(10,'2 WAY RADIOS',6);
Select * FROM category orDER BY category_id;
+-------------+----------------------+--------+
| category_id | name                 | parent |
+-------------+----------------------+--------+
|           1 | ELECTRONICS          |   NULL |
|           2 | TELEVISIONS          |      1 |
|           3 | TUBE                 |      2 |
|           4 | LCD                  |      2 |
|           5 | PLASMA               |      2 |
|           6 | PORTABLE ELECTRONICS |      1 |
|           7 | MP3 PLAYERS          |      6 |
|           8 | FLASH                |      7 |
|           9 | CD PLAYERS           |      6 |
|          10 | 2 WAY RADIOS         |      6 |
+-------------+----------------------+--------+
10 rows in set (0.00 sec)
</pre>
<p>In the adjacency list model, each item in the table contains a pointer to its parent. The topmost element, in this case electronics, has a NULL value for its parent. The adjacency list model has the advantage of being quite simple, it is easy to see that FLASH is a child of mp3 players, which is a child of portable electronics, which is a child of electronics. While the adjacency list model can be dealt with fairly easily in client-side code, working with the model can be more problematic in pure SQL.</p>
<h3>Retrieving a Full Tree</h3>
<p>The first common task when dealing with hierarchical data is the display of the entire tree, usually with some form of indentation. The most common way of doing this is in pure SQL is through the use of a self-join:</p>
<pre>Select t1.name AS lev1, t2.name as lev2, t3.name as lev3, t4.name as lev4
FROM category AS t1
LEFT JOIN category AS t2 ON t2.parent = t1.category_id
LEFT JOIN category AS t3 ON t3.parent = t2.category_id
LEFT JOIN category AS t4 ON t4.parent = t3.category_id
Where t1.name = 'ELECTRONICS';
+-------------+----------------------+--------------+-------+
| lev1        | lev2                 | lev3         | lev4  |
+-------------+----------------------+--------------+-------+
| ELECTRONICS | TELEVISIONS          | TUBE         | NULL  |
| ELECTRONICS | TELEVISIONS          | LCD          | NULL  |
| ELECTRONICS | TELEVISIONS          | PLASMA       | NULL  |
| ELECTRONICS | PORTABLE ELECTRONICS | MP3 PLAYERS  | FLASH |
| ELECTRONICS | PORTABLE ELECTRONICS | CD PLAYERS   | NULL  |
| ELECTRONICS | PORTABLE ELECTRONICS | 2 WAY RADIOS | NULL  |
+-------------+----------------------+--------------+-------+
6 rows in set (0.00 sec)
</pre>
<h3>Finding all the Leaf Nodes</h3>
<p>We can find all the leaf nodes in our tree (those with no children) by using a LEFT JOIN query:</p>
<pre>Select t1.name FROM
category AS t1 LEFT JOIN category as t2
ON t1.category_id = t2.parent
Where t2.category_id IS NULL;
+--------------+
| name         |
+--------------+
| TUBE         |
| LCD          |
| PLASMA       |
| FLASH        |
| CD PLAYERS   |
| 2 WAY RADIOS |
+--------------+
</pre>
<h3>Retrieving a Single Path</h3>
<p>The self-join also allows us to see the full path through our hierarchies:</p>
<pre>Select t1.name AS lev1, t2.name as lev2, t3.name as lev3, t4.name as lev4
FROM category AS t1
LEFT JOIN category AS t2 ON t2.parent = t1.category_id
LEFT JOIN category AS t3 ON t3.parent = t2.category_id
LEFT JOIN category AS t4 ON t4.parent = t3.category_id
Where t1.name = 'ELECTRONICS' AND t4.name = 'FLASH';
+-------------+----------------------+-------------+-------+
| lev1        | lev2                 | lev3        | lev4  |
+-------------+----------------------+-------------+-------+
| ELECTRONICS | PORTABLE ELECTRONICS | MP3 PLAYERS | FLASH |
+-------------+----------------------+-------------+-------+
1 row in set (0.01 sec)
</pre>
<p>The main limitation of such an approach is that you need one self-join for every level in the hierarchy, and performance will naturally degrade with each level added as the joining grows in complexity.</p>
<h3>Limitations of the Adjacency List Model</h3>
<p>Working with the adjacency list model in pure SQL can be difficult at best. Before being able to see the full path of a category we have to know the level at which it resides. In addition, special care must be taken when deleting nodes because of the potential for orphaning an entire sub-tree in the process (delete the portable electronics category and all of its children are orphaned). Some of these limitations can be addressed through the use of client-side code or stored procedures. With a procedural language we can start at the bottom of the tree and iterate upwards to return the full tree or a single path. We can also use procedural programming to delete nodes without orphaning entire sub-trees by promoting one child element and re-ordering the remaining children to point to the new parent.</p>
<h3>The Nested Set Model</h3>
<p>What I would like to focus on in this article is a different approach, commonly referred to as the <b>Nested Set Model</b>. In the Nested Set Model, we can look at our hierarchy in a new way, not as nodes and lines, but as nested containers. Try picturing our electronics categories this way:</p>
<p><img alt="" src="http://jorkin.reallydo.com/UPLOAD/month_1001/hierarchical-data-2.png" /></p>
<p>Notice how our hierarchy is still maintained, as parent categories envelop their children.We represent this form of hierarchy in a table through the use of left and right values to represent the nesting of our nodes:</p>
<pre>Create TABLE nested_category (
category_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20) NOT NULL,
lft INT NOT NULL,
rgt INT NOT NULL
);
Insert INTO nested_category
VALUES(1,'ELECTRONICS',1,20),(2,'TELEVISIONS',2,9),(3,'TUBE',3,4),
(4,'LCD',5,6),(5,'PLASMA',7,8),(6,'PORTABLE ELECTRONICS',10,19),
(7,'MP3 PLAYERS',11,14),(8,'FLASH',12,13),
(9,'CD PLAYERS',15,16),(10,'2 WAY RADIOS',17,18);
Select * FROM nested_category orDER BY category_id;
+-------------+----------------------+-----+-----+
| category_id | name                 | lft | rgt |
+-------------+----------------------+-----+-----+
|           1 | ELECTRONICS          |   1 |  20 |
|           2 | TELEVISIONS          |   2 |   9 |
|           3 | TUBE                 |   3 |   4 |
|           4 | LCD                  |   5 |   6 |
|           5 | PLASMA               |   7 |   8 |
|           6 | PORTABLE ELECTRONICS |  10 |  19 |
|           7 | MP3 PLAYERS          |  11 |  14 |
|           8 | FLASH                |  12 |  13 |
|           9 | CD PLAYERS           |  15 |  16 |
|          10 | 2 WAY RADIOS         |  17 |  18 |
+-------------+----------------------+-----+-----+
</pre>
<p>We use <b>lft</b> and <b>rgt</b> because left and right are reserved words in MySQL, see <a href="http://dev.mysql.com/doc/mysql/en/reserved-words.html" target="_blank">http://dev.mysql.com/doc/mysql/en/reserved-words.html</a> for the full list of reserved words.</p>
<p>So how do we determine left and right values? We start numbering at the leftmost side of the outer node and continue to the right:</p>
<p><img alt="" src="http://jorkin.reallydo.com/UPLOAD/month_1001/hierarchical-data-3.png" /></p>
<p>This design can be applied to a typical tree as well:</p>
<p><img alt="" src="http://jorkin.reallydo.com/UPLOAD/month_1001/hierarchical-data-4.png" /></p>
<p>When working with a tree, we work from left to right, one layer at a time, descending to each node's children before assigning a right-hand number and moving on to the right. This approach is called the modified <b>preorder tree traversal algorithm.</b></p>
<h3>Retrieving a Full Tree</h3>
<p>We can retrieve the full tree through the use of a self-join that links parents with nodes on the basis that a node's <b>lft</b> value will always appear between its parent's <b>lft</b> and <b>rgt</b> values:</p>
<pre>Select node.name
FROM nested_category AS node,
nested_category AS parent
Where node.lft BETWEEN parent.lft AND parent.rgt
AND parent.name = 'ELECTRONICS'
orDER BY node.lft;
+----------------------+
| name                 |
+----------------------+
| ELECTRONICS          |
| TELEVISIONS          |
| TUBE                 |
| LCD                  |
| PLASMA               |
| PORTABLE ELECTRONICS |
| MP3 PLAYERS          |
| FLASH                |
| CD PLAYERS           |
| 2 WAY RADIOS         |
+----------------------+
</pre>
<p>Unlike our previous examples with the adjacency list model, this query will work regardless of the depth of the tree. We do not concern ourselves with the rgt value of the node in our BETWEEN clause because the rgt value will always fall within the same parent as the lft values.</p>
<h3>Finding all the Leaf Nodes</h3>
<p>Finding all leaf nodes in the nested set model even simpler than the LEFT JOIN method used in the adjacency list model. If you look at the nested_category table, you may notice that the lft and rgt values for leaf nodes are consecutive numbers. To find the leaf nodes, we look for nodes where rgt = lft + 1:</p>
<pre>Select name
FROM nested_category
Where rgt = lft + 1;
+--------------+
| name         |
+--------------+
| TUBE         |
| LCD          |
| PLASMA       |
| FLASH        |
| CD PLAYERS   |
| 2 WAY RADIOS |
+--------------+
</pre>
<h3>Retrieving a Single Path</h3>
<p>With the nested set model, we can retrieve a single path without having multiple self-joins:</p>
<pre>Select parent.name
FROM nested_category AS node,
nested_category AS parent
Where node.lft BETWEEN parent.lft AND parent.rgt
AND node.name = 'FLASH'
orDER BY parent.lft;
+----------------------+
| name                 |
+----------------------+
| ELECTRONICS          |
| PORTABLE ELECTRONICS |
| MP3 PLAYERS          |
| FLASH                |
+----------------------+
</pre>
<h3>Finding the Depth of the Nodes</h3>
<p>We have already looked at how to show the entire tree, but what if we want to also show the depth of each node in the tree, to better identify how each node fits in the hierarchy? This can be done by adding a COUNT function and a GROUP BY clause to our existing query for showing the entire tree:</p>
<pre>Select node.name, (COUNT(parent.name) - 1) AS depth
FROM nested_category AS node,
nested_category AS parent
Where node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.name
orDER BY node.lft;
+----------------------+-------+
| name                 | depth |
+----------------------+-------+
| ELECTRONICS          |     0 |
| TELEVISIONS          |     1 |
| TUBE                 |     2 |
| LCD                  |     2 |
| PLASMA               |     2 |
| PORTABLE ELECTRONICS |     1 |
| MP3 PLAYERS          |     2 |
| FLASH                |     3 |
| CD PLAYERS           |     2 |
| 2 WAY RADIOS         |     2 |
+----------------------+-------+
</pre>
<p>We can use the depth value to indent our category names with the CONCAT and REPEAT string functions:</p>
<pre>Select CONCAT( REPEAT(' ', COUNT(parent.name) - 1), node.name) AS name
FROM nested_category AS node,
nested_category AS parent
Where node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.name
orDER BY node.lft;
+-----------------------+
| name                  |
+-----------------------+
| ELECTRONICS           |
|  TELEVISIONS          |
|   TUBE                |
|   LCD                 |
|   PLASMA              |
|  PORTABLE ELECTRONICS |
|   MP3 PLAYERS         |
|    FLASH              |
|   CD PLAYERS          |
|   2 WAY RADIOS        |
+-----------------------+
</pre>
<p>Of course, in a client-side application you will be more likely to use the depth value directly to display your hierarchy. Web developers could loop through the tree, adding &lt;li&gt;&lt;/li&gt; and &lt;ul&gt;&lt;/ul&gt; tags as the depth number increases and decreases.</p>
<h3>Depth of a Sub-Tree</h3>
<p>When we need depth information for a sub-tree, we cannot limit either the node or parent tables in our self-join because it will corrupt our results. Instead, we add a third self-join, along with a sub-query to determine the depth that will be the new starting point for our sub-tree:</p>
<pre>Select node.name, (COUNT(parent.name) - (sub_tree.depth + 1)) AS depth
FROM nested_category AS node,
nested_category AS parent,
nested_category AS sub_parent,
(
Select node.name, (COUNT(parent.name) - 1) AS depth
FROM nested_category AS node,
nested_category AS parent
Where node.lft BETWEEN parent.lft AND parent.rgt
AND node.name = 'PORTABLE ELECTRONICS'
GROUP BY node.name
orDER BY node.lft
)AS sub_tree
Where node.lft BETWEEN parent.lft AND parent.rgt
AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt
AND sub_parent.name = sub_tree.name
GROUP BY node.name
orDER BY node.lft;
+----------------------+-------+
| name                 | depth |
+----------------------+-------+
| PORTABLE ELECTRONICS |     0 |
| MP3 PLAYERS          |     1 |
| FLASH                |     2 |
| CD PLAYERS           |     1 |
| 2 WAY RADIOS         |     1 |
+----------------------+-------+
</pre>
<p>This function can be used with any node name, including the root node. The depth values are always relative to the named node.</p>
<h3>Find the Immediate Subordinates of a Node</h3>
<p>Imagine you are showing a category of electronics products on a retailer web site. When a user clicks on a category, you would want to show the products of that category, as well as list its immediate sub-categories, but not the entire tree of categories beneath it. For this, we need to show the node and its immediate sub-nodes, but no further down the tree. For example, when showing the PORTABLE ELECTRONICS category, we will want to show MP3 PLAYERS, CD PLAYERS, and 2 WAY RADIOS, but not FLASH.</p>
<p>This can be easily accomplished by adding a HAVING clause to our previous query:</p>
<pre>Select node.name, (COUNT(parent.name) - (sub_tree.depth + 1)) AS depth
FROM nested_category AS node,
nested_category AS parent,
nested_category AS sub_parent,
(
Select node.name, (COUNT(parent.name) - 1) AS depth
FROM nested_category AS node,
nested_category AS parent
Where node.lft BETWEEN parent.lft AND parent.rgt
AND node.name = 'PORTABLE ELECTRONICS'
GROUP BY node.name
orDER BY node.lft
)AS sub_tree
Where node.lft BETWEEN parent.lft AND parent.rgt
AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt
AND sub_parent.name = sub_tree.name
GROUP BY node.name
HAVING depth &lt;= 1
orDER BY node.lft;
+----------------------+-------+
| name                 | depth |
+----------------------+-------+
| PORTABLE ELECTRONICS |     0 |
| MP3 PLAYERS          |     1 |
| CD PLAYERS           |     1 |
| 2 WAY RADIOS         |     1 |
+----------------------+-------+
</pre>
<p>If you do not wish to show the parent node, change the <b>HAVING depth &lt;= 1 line to HAVING depth = 1</b>.</p>
<h3>Aggregate Functions in a Nested Set</h3>
<p>Let's add a table of products that we can use to demonstrate aggregate functions with:</p>
<pre>Create TABLE product(
product_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(40),
category_id INT NOT NULL
);
Insert INTO product(name, category_id) VALUES('20&quot; TV',3),('36&quot; TV',3),
('Super-LCD 42&quot;',4),('Ultra-Plasma 62&quot;',5),('Value Plasma 38&quot;',5),
('Power-MP3 5gb',7),('Super-Player 1gb',8),('Porta CD',9),('CD To go!',9),
('Family Talk 360',10);
Select * FROM product;
+------------+-------------------+-------------+
| product_id | name              | category_id |
+------------+-------------------+-------------+
|          1 | 20&quot; TV            |           3 |
|          2 | 36&quot; TV            |           3 |
|          3 | Super-LCD 42&quot;     |           4 |
|          4 | Ultra-Plasma 62&quot;  |           5 |
|          5 | Value Plasma 38&quot;  |           5 |
|          6 | Power-MP3 128mb   |           7 |
|          7 | Super-Shuffle 1gb |           8 |
|          8 | Porta CD          |           9 |
|          9 | CD To go!         |           9 |
|         10 | Family Talk 360   |          10 |
+------------+-------------------+-------------+
</pre>
<p>Now let's produce a query that can retrieve our category tree, along with a product count for each category:</p>
<pre>Select parent.name, COUNT(product.name)
FROM nested_category AS node ,
nested_category AS parent,
product
Where node.lft BETWEEN parent.lft AND parent.rgt
AND node.category_id = product.category_id
GROUP BY parent.name
orDER BY node.lft;
+----------------------+---------------------+
| name                 | COUNT(product.name) |
+----------------------+---------------------+
| ELECTRONICS          |                  10 |
| TELEVISIONS          |                   5 |
| TUBE                 |                   2 |
| LCD                  |                   1 |
| PLASMA               |                   2 |
| PORTABLE ELECTRONICS |                   5 |
| MP3 PLAYERS          |                   2 |
| FLASH                |                   1 |
| CD PLAYERS           |                   2 |
| 2 WAY RADIOS         |                   1 |
+----------------------+---------------------+
</pre>
<p>This is our typical whole tree query with a COUNT and GROUP BY added, along with a reference to the product table and a join between the node and product table in the Where clause. As you can see, there is a count for each category and the count of subcategories is reflected in the parent categories.</p>
<h3>Adding New Nodes</h3>
<p>Now that we have learned how to query our tree, we should take a look at how to update our tree by adding a new node. Let's look at our nested set diagram again:</p>
<p><img alt="" src="http://jorkin.reallydo.com/UPLOAD/month_1001/hierarchical-data-5.png" /></p>
<p>If we wanted to add a new node between the TELEVISIONS and PORTABLE ELECTRONICS nodes, the new node would have lft and rgt values of 10 and 11, and all nodes to its right would have their lft and rgt values increased by two. We would then add the new node with the appropriate lft and rgt values. While this can be done with a stored procedure in MySQL 5, I will assume for the moment that most readers are using 4.1, as it is the latest stable version, and I will isolate my queries with a LOCK TABLES statement instead:</p>
<pre>LOCK TABLE nested_category WRITE;
Select @myRight := rgt FROM nested_category
Where name = 'TELEVISIONS';
Update nested_category SET rgt = rgt + 2 Where rgt &gt; @myRight;
Update nested_category SET lft = lft + 2 Where lft &gt; @myRight;
Insert INTO nested_category(name, lft, rgt) VALUES('GAME CONSOLES', @myRight + 1, @myRight + 2);
UNLOCK TABLES;
We can then check our nesting with our indented tree query:
Select CONCAT( REPEAT( ' ', (COUNT(parent.name) - 1) ), node.name) AS name
FROM nested_category AS node,
nested_category AS parent
Where node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.name
orDER BY node.lft;
+-----------------------+
| name                  |
+-----------------------+
| ELECTRONICS           |
|  TELEVISIONS          |
|   TUBE                |
|   LCD                 |
|   PLASMA              |
|  GAME CONSOLES        |
|  PORTABLE ELECTRONICS |
|   MP3 PLAYERS         |
|    FLASH              |
|   CD PLAYERS          |
|   2 WAY RADIOS        |
+-----------------------+
</pre>
<p>If we instead want to add a node as a child of a node that has no existing children, we need to modify our procedure slightly. Let's add a new FRS node below the 2 WAY RADIOS node:</p>
<pre>LOCK TABLE nested_category WRITE;
Select @myLeft := lft FROM nested_category
Where name = '2 WAY RADIOS';
Update nested_category SET rgt = rgt + 2 Where rgt &gt; @myLeft;
Update nested_category SET lft = lft + 2 Where lft &gt; @myLeft;
Insert INTO nested_category(name, lft, rgt) VALUES('FRS', @myLeft + 1, @myLeft + 2);
UNLOCK TABLES;
</pre>
<p>In this example we expand everything to the right of the left-hand number of our proud new parent node, then place the node to the right of the left-hand value. As you can see, our new node is now properly nested:</p>
<pre>Select CONCAT( REPEAT( ' ', (COUNT(parent.name) - 1) ), node.name) AS name
FROM nested_category AS node,
nested_category AS parent
Where node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.name
orDER BY node.lft;
+-----------------------+
| name                  |
+-----------------------+
| ELECTRONICS           |
|  TELEVISIONS          |
|   TUBE                |
|   LCD                 |
|   PLASMA              |
|  GAME CONSOLES        |
|  PORTABLE ELECTRONICS |
|   MP3 PLAYERS         |
|    FLASH              |
|   CD PLAYERS          |
|   2 WAY RADIOS        |
|    FRS                |
+-----------------------+
</pre>
<h3>Deleting Nodes</h3>
<p>The last basic task involved in working with nested sets is the removal of nodes. The course of action you take when deleting a node depends on the node's position in the hierarchy; deleting leaf nodes is easier than deleting nodes with children because we have to handle the orphaned nodes.</p>
<p>When deleting a leaf node, the process if just the opposite of adding a new node, we delete the node and its width from every node to its right:</p>
<pre>LOCK TABLE nested_category WRITE;
Select @myLeft := lft, @myRight := rgt, @myWidth := rgt - lft + 1
FROM nested_category
Where name = 'GAME CONSOLES';
Delete FROM nested_category Where lft BETWEEN @myLeft AND @myRight;
Update nested_category SET rgt = rgt - @myWidth Where rgt &gt; @myRight;
Update nested_category SET lft = lft - @myWidth Where lft &gt; @myRight;
UNLOCK TABLES;
</pre>
<p>And once again, we execute our indented tree query to confirm that our node has been deleted without corrupting the hierarchy:</p>
<pre>Select CONCAT( REPEAT( ' ', (COUNT(parent.name) - 1) ), node.name) AS name
FROM nested_category AS node,
nested_category AS parent
Where node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.name
orDER BY node.lft;
+-----------------------+
| name                  |
+-----------------------+
| ELECTRONICS           |
|  TELEVISIONS          |
|   TUBE                |
|   LCD                 |
|   PLASMA              |
|  PORTABLE ELECTRONICS |
|   MP3 PLAYERS         |
|    FLASH              |
|   CD PLAYERS          |
|   2 WAY RADIOS        |
|    FRS                |
+-----------------------+
</pre>
<p>This approach works equally well to delete a node and all its children:</p>
<pre>LOCK TABLE nested_category WRITE;
Select @myLeft := lft, @myRight := rgt, @myWidth := rgt - lft + 1
FROM nested_category
Where name = 'MP3 PLAYERS';
Delete FROM nested_category Where lft BETWEEN @myLeft AND @myRight;
Update nested_category SET rgt = rgt - @myWidth Where rgt &gt; @myRight;
Update nested_category SET lft = lft - @myWidth Where lft &gt; @myRight;
UNLOCK TABLES;
</pre>
<p>And once again, we query to see that we have successfully deleted an entire sub-tree:</p>
<pre>Select CONCAT( REPEAT( ' ', (COUNT(parent.name) - 1) ), node.name) AS name
FROM nested_category AS node,
nested_category AS parent
Where node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.name
orDER BY node.lft;
+-----------------------+
| name                  |
+-----------------------+
| ELECTRONICS           |
|  TELEVISIONS          |
|   TUBE                |
|   LCD                 |
|   PLASMA              |
|  PORTABLE ELECTRONICS |
|   CD PLAYERS          |
|   2 WAY RADIOS        |
|    FRS                |
+-----------------------+
</pre>
<p>The other scenario we have to deal with is the deletion of a parent node but not the children. In some cases you may wish to just change the name to a placeholder until a replacement is presented, such as when a supervisor is fired. In other cases, the child nodes should all be moved up to the level of the deleted parent:</p>
<pre>LOCK TABLE nested_category WRITE;
Select @myLeft := lft, @myRight := rgt, @myWidth := rgt - lft + 1
FROM nested_category
Where name = 'PORTABLE ELECTRONICS';
Delete FROM nested_category Where lft = @myLeft;
Update nested_category SET rgt = rgt - 1, lft = lft - 1 Where lft BETWEEN @myLeft AND @myRight;
Update nested_category SET rgt = rgt - 2 Where rgt &gt; @myRight;
Update nested_category SET lft = lft - 2 Where lft &gt; @myRight;
UNLOCK TABLES;
</pre>
<p>In this case we subtract two from all elements to the right of the node (since without children it would have a width of two), and one from the nodes that are its children (to close the gap created by the loss of the parent's left value). Once again, we can confirm our elements have been promoted:</p>
<pre>Select CONCAT( REPEAT( ' ', (COUNT(parent.name) - 1) ), node.name) AS name
FROM nested_category AS node,
nested_category AS parent
Where node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.name
orDER BY node.lft;
+---------------+
| name          |
+---------------+
| ELECTRONICS   |
|  TELEVISIONS  |
|   TUBE        |
|   LCD         |
|   PLASMA      |
|  CD PLAYERS   |
|  2 WAY RADIOS |
|   FRS         |
+---------------+
</pre>
<p>Other scenarios when deleting nodes would include promoting one of the children to the parent position and moving the child nodes under a sibling of the parent node, but for the sake of space these scenarios will not be covered in this article.</p>
<h3>Final Thoughts</h3>
<p>While I hope the information within this article will be of use to you, the concept of nested sets in SQL has been around for over a decade, and there is a lot of additional information available in books and on the Internet. In my opinion the most comprehensive source of information on managing hierarchical information is a book called <a href="http://www.openwin.org/mike/books/index.php/trees-and-hierarchies-in-sql" target="_blank">Joe Celko's Trees and Hierarchies in SQL for Smarties</a>, written by a very respected author in the field of advanced SQL, Joe Celko. Joe Celko is often credited with the nested sets model and is by far the most prolific author on the subject. I have found Celko's book to be an invaluable resource in my own studies and highly recommend it. The book covers advanced topics which I have not covered in this article, and provides additional methods for managing hierarchical data in addition to the Adjacency List and Nested Set models.</p>
<p>In the References / Resources section that follows I have listed some web resources that may be of use in your research of managing hierarchal data, including a pair of PHP related resources that include pre-built PHP libraries for handling nested sets in MySQL. Those of you who currently use the adjacency list model and would like to experiment with the nested set model will find sample code for converting between the two in the <a href="http://www.sitepoint.com/article/hierarchical-data-database" target="_blank">Storing Hierarchical Data in a Database</a> resource listed below.</p>]]></description>
		</item>
		
			<item>
			<link>http://Jorkin.ME/article.asp?id=654</link>
			<title><![CDATA[[原创]利用正弦函数Sin()真正实现ACCESS的随机选取记录]]></title>
			<author>Jorkin2000(AT)hotmail.com(Jorkin)</author>
			<category><![CDATA[技术天地]]></category>
			<pubDate>Fri,11 Dec 2009 16:35:33 +0800</pubDate>
			<guid>http://Jorkin.ME/default.asp?id=654</guid>
		<description><![CDATA[<p>不多说了.非常简单.</p>
<p>建一个ASP函数:<br /><a href="http://jorkin.reallydo.com/article.asp?id=653" target="_blank">http://jorkin.reallydo.com/article.asp?id=653</a></p>
<p>ASP代码:<br />&lt;%<br />sNewOrder = NewID(&quot;id&quot;) '这里的ID是数据类型为数字(最好用自动编号列)<br />Set ors = Exec(&quot;Select Top 20 id,compname,fund,foundyear,&quot; &amp; sNewOrder &amp; &quot; AS NewID From company <font color="#ff0000">where fund&gt;100</font> order By &quot; &amp; sNewOrder)<br />Trace(oRs)<br />%&gt;<br /><br />说明：这个方法如果在记录集过大的时候也会很费时间，所以请先通过Where条件筛选后再随机排序。</p>
<p><a href="http://bbs.blueidea.com/thread-2961671-1-1.html" target="_blank">实例下载</a></p>]]></description>
		</item>
		
			<item>
			<link>http://Jorkin.ME/article.asp?id=652</link>
			<title><![CDATA[[转]N个jQuery Datagrid插件 以及其他 Datagrid 脚本]]></title>
			<author>Jorkin2000(AT)hotmail.com(Jorkin)</author>
			<category><![CDATA[技术天地]]></category>
			<pubDate>Tue,17 Nov 2009 15:40:58 +0800</pubDate>
			<guid>http://Jorkin.ME/default.asp?id=652</guid>
		<description><![CDATA[<p>Review of 10 jQuery datagrid plugins... </p>
<p>jqGrid</p>
<p align="center"><a href="http://jorkin.reallydo.com/upload/month_0911/jqgrid.png" rel="lightbox" target="_blank"><img title="jqGrid plugin" border="0" alt="jqGrid plugin" src="http://jorkin.reallydo.com/upload/month_0911/jqgrid.png" width="644" height="232" /></a><br /><a href="http://www.trirand.com/blog/" target="_blank">HOME</a> | <a href="http://www.trirand.com/jqgrid35/jqgrid.html" target="_blank">DEMO</a> | Last Update: May 2009</p>
<ul>
    <li>paging functions </li>
    <li>sortable column headers </li>
    <li>add, edit, delete &amp; search records </li>
    <li>accepts XML, JSON, array or user data as input </li>
    <li>multiple selection of rows </li>
    <li>sub grid &amp; grid details </li>
    <li>support UI themes </li>
    <li>UI Datepicker integration </li>
    <li>API </li>
    <li>big size </li>
</ul>
<p>Flexigrid</p>
<p align="center"><a href="http://jorkin.reallydo.com/upload/month_0911/flexigrid.png" rel="lightbox" target="_blank"><img title="Flexigrid plugin" border="0" alt="Flexigrid plugin" src="http://jorkin.reallydo.com/upload/month_0911/flexigrid.png" width="700" height="316" /></a><br /><a href="http://www.flexigrid.info/" target="_blank">HOME</a> | Last Update: July 2008</p>
<ul>
    <li>paging functions </li>
    <li>sortable column headers </li>
    <li>add, edit, delete &amp; search records </li>
    <li>accepts XML, JSON, array or user data as input </li>
    <li>nice design </li>
    <li>API </li>
    <li>don't support last jQuery version </li>
</ul>
<p>Ingrid</p>
<p align="center"><a href="http://jorkin.reallydo.com/upload/month_0911/ingrid.png" rel="lightbox" target="_blank"><img title="Ingrid plugin" border="0" alt="Ingrid plugin" src="http://jorkin.reallydo.com/upload/month_0911/ingrid.png" width="600" height="266" /></a><br /><a href="http://reconstrukt.com/ingrid/" target="_blank">HOME</a> | Last Update: November 2007</p>
<ul>
    <li>paging functions </li>
    <li>sortable column headers </li>
    <li>nice design </li>
    <li>project is die </li>
</ul>
<p>jTPS</p>
<p align="center"><a href="http://jorkin.reallydo.com/upload/month_0911/jtps.png" rel="lightbox" target="_blank"><img title="jTPS plugin" border="0" alt="jTPS plugin" src="http://jorkin.reallydo.com/upload/month_0911/jtps.png" width="703" height="399" /></a><br /><a href="http://www.overset.com/2008/08/30/animated-sortable-datagrid-jquery-plugin-jtps/" target="_blank">HOME</a> | <a href="http://overset.com/upload/jTPS/jTPS.html" target="_blank">DEMO</a> | Last Update: August 2008</p>
<ul>
    <li>paging functions </li>
    <li>sortable column headers </li>
    <li>animate sorting and page navigation </li>
    <li>don't support AJAX </li>
</ul>
<p>FireScope Grid</p>
<p align="center"><a href="http://jorkin.reallydo.com/upload/month_0911/firescope_grid-720x283.png" rel="lightbox" target="_blank"><img title="FireScope Grid" border="0" alt="FireScope Grid" src="http://jorkin.reallydo.com/upload/month_0911/firescope_grid-720x283.png" width="720" height="283" /></a><br /><a href="http://www.firescope.com/OpenSource/Grid/" target="_blank">HOME</a> | Last Update: February 2009</p>
<ul>
    <li>paging functions </li>
    <li>sortable column headers </li>
    <li>search records </li>
    <li>support only HTML data source </li>
</ul>
<p>tgrid</p>
<p align="center"><a href="http://jorkin.reallydo.com/upload/month_0911/tgrid.png" rel="lightbox" target="_blank"><img title="tgrid" border="0" alt="tgrid" src="http://jorkin.reallydo.com/upload/month_0911/tgrid.png" width="476" height="460" /></a><br /><a href="http://dreakmore.info/tgrid/" target="_blank">HOME</a> | <a href="http://dreakmore.info/tgrid/demos/" target="_blank">DEMO</a> | Last Update: May 2009</p>
<ul>
    <li>paging functions </li>
    <li>sortable column headers </li>
    <li>update &amp; search records </li>
    <li>young </li>
    <li>young </li>
    <li>young </li>
</ul>
<p>Datacontrol</p>
<p align="center"><a href="http://jorkin.reallydo.com/upload/month_0911/datacontrol.png" rel="lightbox" target="_blank"><img title="Datacontrol" border="0" alt="Datacontrol" src="http://jorkin.reallydo.com/upload/month_0911/datacontrol.png" width="606" height="199" /></a><br /><a href="http://www.antolcms.com/datacontrol/" target="_blank">HOME</a> | Last Update: February 2009</p>
<ul>
    <li>paging functions </li>
    <li>sortable column headers </li>
    <li>add, edit, delete &amp; search records </li>
    <li>support only XML data source (but with XLS) </li>
    <li>don't allow source </li>
</ul>
<p>DataTables</p>
<p align="center"><a href="http://jorkin.reallydo.com/upload/month_0911/datatables.png" rel="lightbox" target="_blank"><img title="DataTables" border="0" alt="DataTables" src="http://jorkin.reallydo.com/upload/month_0911/datatables.png" width="700" height="302" /></a><br /><a href="http://www.datatables.net/" target="_blank">HOME</a> | <a href="http://www.datatables.net/examples/example_zero_config.html" target="_blank">DEMO</a> | Last Update: February 2009</p>
<ul>
    <li>paging functions </li>
    <li>sortable column headers </li>
    <li>add, edit, delete &amp; search records </li>
    <li>accepts only JSON as input </li>
    <li>API </li>
    <li>fast data search </li>
</ul>
<p>Snowcore Datagrid</p>
<p align="center"><a href="http://jorkin.reallydo.com/upload/month_0911/snowscore.png" rel="lightbox" target="_blank"><img title="snowcore" border="0" alt="snowcore" src="http://jorkin.reallydo.com/upload/month_0911/snowscore.png" width="354" height="120" /></a><br /><a href="http://snowcore.net/jquery-data-grid-пишем-плагин" target="_blank">HOME</a> | <a href="http://snowcore.net/grid/" target="_blank">DEMO</a> | Last Update: December 2008</p>
<ul>
    <li>add, edit &amp; delete records </li>
    <li>young </li>
</ul>
<p>JGridEditor</p>
<p>Plugin aviable only on <a href="http://plugins.jquery.com/project/jgrideditor" target="_blank">jQuery homepage</a>.</p>
<p>Sigma Grid</p>
<p><a href="http://www.sigmawidgets.com/" target="_blank">HomePage</a> | <a href="http://www.sigmawidgets.com/products/sigma_grid/demos/index.html" target="_blank">Demo</a> | <a href="http://www.sigmawidgets.com/download.html" target="_blank">Download</a></p>]]></description>
		</item>
		
			<item>
			<link>http://Jorkin.ME/article.asp?id=650</link>
			<title><![CDATA[JavaScript Framework Matrix]]></title>
			<author>Jorkin2000(AT)hotmail.com(Jorkin)</author>
			<category><![CDATA[技术天地]]></category>
			<pubDate>Wed,23 Sep 2009 23:06:34 +0800</pubDate>
			<guid>http://Jorkin.ME/default.asp?id=650</guid>
		<description><![CDATA[<p>JavaScript Framework Matrix是一个比较当前各种流行JavaScript框架功能的矩阵。所举的例子几乎涵盖了所有的功能，并提供链接指向原始文档。</p>
<p><a href="http://matthiasschuetz.com/javascript-framework-matrix/en/">http://matthiasschuetz.com/javascript-framework-matrix/en/</a></p>
<p><a href="http://jorkin.reallydo.com/upload/month_0909/1200992323614.jpg" rel="lightbox"><img alt="" src="http://jorkin.reallydo.com/upload/month_0909/1200992323614.jpg" border="0" /></a></p>
<p><strong><font style="BACKGROUND-COLOR: #999999" color="#ffffff">目前支持的库:</font></strong></p>
<ul>
    <li>jQuery </li>
    <li>MooTools </li>
    <li>The Dojo Toolkit </li>
    <li>Prototype </li>
    <li>Script.aculo.us </li>
    <li>Ext.JS </li>
    <li>Adobe Spry </li>
    <li>BBC Glow </li>
    <li>Yahoo UI! Library </li>
</ul>]]></description>
		</item>
		
			<item>
			<link>http://Jorkin.ME/article.asp?id=646</link>
			<title><![CDATA[小技巧:使用CSS预加载图片]]></title>
			<author>Jorkin2000(AT)hotmail.com(Jorkin)</author>
			<category><![CDATA[技术天地]]></category>
			<pubDate>Tue,11 Aug 2009 22:49:38 +0800</pubDate>
			<guid>http://Jorkin.ME/default.asp?id=646</guid>
		<description><![CDATA[这是个很实用的小技巧,下面的代码可以使浏览器从缓存里读取图片.<br/><br/>#preloadImages {<br/>&#160;&#160;&#160;&#160;width: 0px;<br/>&#160;&#160;&#160;&#160;height: 0px;<br/>&#160;&#160;&#160;&#160;display: inline;<br/>&#160;&#160;&#160;&#160;background-image: url(path/to/image1.jpg);<br/>&#160;&#160;&#160;&#160;background-image: url(path/to/image2.jpg);<br/>&#160;&#160;&#160;&#160;background-image: url(path/to/image3.jpg);<br/>&#160;&#160;&#160;&#160;background-image: url(path/to/image4.jpg);<br/>}]]></description>
		</item>
		
			<item>
			<link>http://Jorkin.ME/article.asp?id=645</link>
			<title><![CDATA[用localeCompare实现中文排序]]></title>
			<author>Jorkin2000(AT)hotmail.com(Jorkin)</author>
			<category><![CDATA[技术天地]]></category>
			<pubDate>Wed,05 Aug 2009 01:14:39 +0800</pubDate>
			<guid>http://Jorkin.ME/default.asp?id=645</guid>
		<description><![CDATA[<div class="UBBPanel"><div class="UBBTitle"><img src="http://Jorkin.ME/images/html.gif" style="margin:0px 2px -3px 0px"> HTML代码</div><div class="UBBContent"><TEXTAREA rows="8" id="temp18165">
<script type=&#34;text/javascript&#34;>
var title=&#34;Kin,JAVA,日志,-27℃,为了谁,为了什么,值不值得,为什么别人那么幸福,ReallyDo,Com&#34;.split(&#34;,&#34;);
function defaultSort(){
	title.sort();
	alert(title);
}
function localeSort(){
	title.sort(function(a,b){
		return a.localeCompare(b);
	});
	alert(title);
}
</script>

<a href=&#34;#&#34; onClick=&#34;defaultSort();&#34;>默认排序</a><br>
<a href=&#34;#&#34; onClick=&#34;localeSort();&#34;>拼音排序</a>

</TEXTAREA><br/><INPUT onclick="runEx('temp18165')"  type="button" class="userbutton" value="运行此代码"/> <INPUT onclick="doCopy('temp18165')"  type="button" class="userbutton" value="复制此代码"/> <INPUT onclick="saveCode('temp18165')" type="button" class="userbutton" value="保存此代码"><br/> [Ctrl+A 全部选择 提示：你可先修改部分代码，再按运行]</div></div>]]></description>
		</item>
		
			<item>
			<link>http://Jorkin.ME/article.asp?id=634</link>
			<title><![CDATA[List of Image Cropping Scripts]]></title>
			<author>Jorkin2000(AT)hotmail.com(Jorkin)</author>
			<category><![CDATA[技术天地]]></category>
			<pubDate>Mon,15 Jun 2009 22:34:14 +0800</pubDate>
			<guid>http://Jorkin.ME/default.asp?id=634</guid>
		<description><![CDATA[<p>After looking for awhile for a script that will crop your image in the browser I decided to put a list together. I found various types of scripts that will accomplish this. The list below is a list of image cropping scripts.</p>
<ol>
    <li><a title="cfImageCropper" href="http://cfimagecropper.riaforge.org/" target="_blank"><strong>cfImageCropper</strong></a> - This script is written in Coldfusion. The Demo of this script works very well and the code is very simple to implement. </li>
    <li><strong><a title="jsCropper" href="http://www.defusion.org.uk/code/javascript-image-cropper-ui-using-prototype-scriptaculous/" target="_blank">jsCropper</a></strong> - This javascript image cropping script is based on the <a href="http://prototype.conio.net/">Prototype JavaScript framework</a> and <a href="http://script.aculo.us/">script.aculo.us</a>. jsCropper is one of my favorite copping script. It is very easy to use and its a great unobtrusive script. jsCropper has tons of great features you should check it out. </li>
    <li><a title="mooImageCrop" href="http://www.artviper.net/crop.php" target="_blank"><strong>mooImageCrop</strong></a> - mooImageCrop is based on the mootools framework and php. It is very easy to implement. </li>
    <li><strong><a title="Image Crop" href="http://www.dhtmlgoodies.com/index.html?whichScript=image-crop" target="_blank">Image Crop</a></strong> - This is a great script written in Javascript and PHP. It requires the install of ImageMagick server component. </li>
    <li><strong><a title="Ajax Image editor" href="http://www.ajaxprogrammer.com/?p=9" target="_blank">Ajax Image Editor</a></strong> - Is a very powerful image editor script that allows you to crop, resize, and rotate the image. It is fairly easy to implement and it isn&rsquo;t written with any frameworks. </li>
    <li><strong><a title="Flash Image Crop" href="http://www.sephiroth.it/file_detail.php?pageNum_comments=10&amp;id=109#" target="_blank">Flash Image Crop</a></strong> - Is a very nice flash image crop tool written in Actionscript and PHP. The only problem I have with this script is that you have to use the space bar to accept the cropped area and not the enter key. But overall it works very well. </li>
    <li><strong><a title="Flash Based Cropping too" href="http://flashrocket.worldoptimizer.com/article/23/flash-based-cropping-tool-released-lgpl" target="_blank">Flash Based Cropping tool</a></strong> - This tool is also written in Actionscript and PHP is a very nice script. You can also resize the image with this script. </li>
    <li><a title="MooCrop" href="http://www.nwhite.net/MooCrop/" target="_blank"><strong>MooCrop</strong></a> -MooCrop is an Image Cropping utility that uses <a href="http://www.mootools.net/">mootools</a> javascript framework.&nbsp; MooCrop works very fast and you can even edit the color of the mask. </li>
</ol>]]></description>
		</item>
		
			<item>
			<link>http://Jorkin.ME/article.asp?id=633</link>
			<title><![CDATA[10 Auto Complete Ajax Scripts]]></title>
			<author>Jorkin2000(AT)hotmail.com(Jorkin)</author>
			<category><![CDATA[技术天地]]></category>
			<pubDate>Sun,14 Jun 2009 22:24:53 +0800</pubDate>
			<guid>http://Jorkin.ME/default.asp?id=633</guid>
		<description><![CDATA[<p>In 2005 when Google implemented Google Suggest, Ajax took off. Every web developer was trying to duplicate what Google accomplished. Its now 2008 and there are tons of ways to accomplish Google Suggest. Below is a list of 10 Auto Complete Scripts with various frameworks. The list below is in no particular order.</p>
<ol>
    <li><strong><a title="jqac" href="http://code.google.com/p/jqac/" target="_blank">jqac </a></strong>- Is jQuery plugin for autocomplete. jqac is very easy to implement and has a scrollable suggests list. It also allows for multiple suggests support and is tested in all major browsers. </li>
    <li><strong><a title="AutoComplete" href="http://webeaters.blogspot.com/2007/11/ajax-powered-autocomplete-for-prototype.html" target="_blank">AutoComplete (for Prototype)</a></strong> - This is a script built for the prototype framework and it allows multiple column support. It also is a very nice style built with it. </li>
    <li><strong><a title="YUI Autocomplete" href="http://developer.yahoo.com/yui/autocomplete/" target="_blank" rel="bookmark">YUI Autocomplete</a></strong> - This script is built with the Yahoo! UI Library. The AutoComplete features navigation of the suggestion box via up/down arrow keys. It is very easy to configure with the Yahoo! UI Library. </li>
    <li><strong><a title="Ajax Autocomplete" href="http://www.jimroos.com/2007/05/ajax-autocomplete.html" target="_blank">AJAX autocomplete</a></strong> - Is built with Easy Ajax framework by Jim Roos. It features the the up and down navigation and is fairly easy to implement. </li>
    <li><strong><a title="Autocomplete" href="http://www.beauscott.com/examples/autocomplete/" target="_blank">Another AutoComplete (prototype)</a> </strong>- This prototype framework autocomplete also uses scriptaculous. It has a nice fade in effect when the suggest box appears. It is easy to implement and works with XML data. </li>
    <li><strong><a title="autocomplete mootools" href="http://digitarald.de/playground/auto2.html" target="_blank">AutoComplete (mootools)</a> </strong>- A MooTools Autocomplete widget that creates a unobtrusive and customizable suggestion box from variable data sources. It also has nice fade in effect. </li>
    <li><strong><a title="dhtmlxCombo" href="http://dhtmlx.com/docs/products/dhtmlxCombo/index.shtml" target="_blank">dhtmlxCombo</a></strong> - Is a different from the rest of these. dhtmlxCombo can be used in four modes: an editable select box, a read-only select box, a filter drop down box, and an autocomplete. It also allows for you to add icons to your drop down boxes. </li>
    <li><strong><a title="AutoSuggest" href="http://www.brandspankingnew.net/archive/2006/08/ajax_auto-suggest_auto-complete.html" target="_blank">AutoSuggest</a></strong> - This AutoSuggest script uses no frameworks. The script allows you to navigate either with the up or down arrows or just click. The script size is under 10k, it even has a fade in effect, and a great 2.0 style. </li>
    <li><strong><a title="Spry Auto Suggest" href="http://labs.adobe.com/technologies/spry/samples/autosuggest/SuggestSample.html" target="_blank">Spry Auto Suggest</a></strong> - This Auto Suggest script is written with Adobe&rsquo;s spry framework. It has works with all sorts of data formats and languages. It supports keyboard navigation and also allows for multiple suggestions. </li>
    <li><strong><a title="asp.net AutoComplete" href="http://lvildosola.blogspot.com/2007/01/how-to-get-smartautocompleteextender.html" target="_blank">ASP.Net AutoComplete</a></strong> - This script allows you to add AutoComplete to ASP.Net without using a webservice. This is a great way to add Autocomplete feature to ASP.net </li>
</ol>]]></description>
		</item>
		
</channel>
</rss>
