<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Learn dotCMS</title>
	
	<link>http://learndotcms.com</link>
	<description>Just another WordPress weblog</description>
	<lastBuildDate>Fri, 19 Aug 2011 15:47:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/LearnDotcms" /><feedburner:info uri="learndotcms" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>dotCMS and Mobile Techniques: Notes from Boot Camp 2011</title>
		<link>http://feedproxy.google.com/~r/LearnDotcms/~3/1070_aJ7a-k/</link>
		<comments>http://learndotcms.com/2011/08/dotcms-and-mobile-techniques/#comments</comments>
		<pubDate>Thu, 18 Aug 2011 15:56:36 +0000</pubDate>
		<dc:creator>Michael Fienen</dc:creator>
				<category><![CDATA[Front End]]></category>
		<category><![CDATA[Velocity]]></category>
		<category><![CDATA[mobile]]></category>

		<guid isPermaLink="false">http://learndotcms.com/?p=427</guid>
		<description><![CDATA[At dotCMS Boot Camp 2011, I was invited to come and talk about mobile implementation techniques using dotCMS. Luckily, this isn&#8217;t as much as issue with trying to pull off clever dotCMS tricks as it is just knowing good mobile techniques. Below are a number of links and examples from my talk. This isn&#8217;t so [...]]]></description>
			<content:encoded><![CDATA[<p>At dotCMS Boot Camp 2011, I was invited to come and talk about mobile implementation techniques using dotCMS. Luckily, this isn&#8217;t as much as issue with trying to pull off clever dotCMS tricks as it is just knowing good mobile techniques. Below are a number of links and examples from my talk. This isn&#8217;t so much about a full blown tutorial, as much as it is just a quick reference for those that attended my session.  A more complete tutorial will come at a later date.</p>
<h3>Mobile Detection Using the Clickstream</h3>
<p>By accessing the user&#8217;s clickstream data, and pulling out the isMobile() flag, we can create a conditional environment to do redirects, apply different stylesheets, change layout, etc.</p>
<pre class="brush: xml; title: ; notranslate">## GET CLICKSTREAM SO WE CAN CHECK OUT THE DEVICE
#set($clickstream  = $session.getAttribute('clickstream'))
## IS THIS A MOBILE DEVICE?
#if($clickstream.mobileDevice &amp;&amp; $clickstream.mobileDevice == 'true')
  ## GET THE REDIRECT COOKIE
  #set($goToMobile = $cookietool.get('goToMobile').value)
  #if($goToMobile == 'true')
    ## SEND THE USER TO THE MOBILE SITE, THIS MUST BE DONE BEFORE
    ## ANY DATA IS SENT TO THE BROWSER
    #$response.sendRedirect('http://m.yoursite.com/')
  #else
    ## IF IT'S MOBILE, BUT THEY WANT THE NORMAL SITE, SEE IF IT
    ## SHOULD BE DISPLAYED LIKE MOBILE OR LIKE NORMAL
    #set($displayMobile = $cookietool.get('displayMobile').value)
  #end
#end</pre>
<p>By setting a cookie at the same time as the check, you can prevent users from having to go through the selection each time if they prefer the normal site over the mobile site. You could set the cookie with some simple JavaScript.</p>
<h3>Creating a Mobile Template</h3>
<p>Creating a mobile template is no different from any other template. If you&#8217;re using a framework like jQuery Mobile, you can build all the necessary parts right into the template.</p>
<pre class="brush: xml; title: ; notranslate">## Container: General Template Includes
#parseContainer('e97bda22-33e8-4b9d-9508-0aefb4c899d6')
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta charset=&quot;utf-8&quot;&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;
  &lt;meta name=&quot;apple-mobile-web-app-capable&quot; content=&quot;yes&quot; /&gt;
  &lt;meta name=&quot;apple-mobile-web-app-status-bar-style&quot; content=&quot;black&quot;/&gt;

  &lt;title&gt;$!{pageTitle}&lt;/title&gt;

  &lt;link rel=&quot;apple-touch-icon&quot; href=&quot;/global/images/app-icon.png&quot; /&gt;
  &lt;link rel=&quot;apple-touch-startup-image&quot;href=&quot;/global/images/app-splash.png&quot; /&gt;
  &lt;link rel=&quot;stylesheet&quot;href=&quot;http://code.jquery.com/mobile/1.0b2/jquery.mobile-1.0b2.min.css&quot; /&gt;
  &lt;link rel=&quot;stylesheet&quot; href=&quot;/global/css/custom.css&quot; /&gt;

  &lt;script src=&quot;http://code.jquery.com/jquery-1.6.2.min.js&quot;&gt;&lt;/script&gt;
  &lt;script src=&quot;http://code.jquery.com/mobile/1.0b2/jquery.mobile-1.0b2.min.js&quot;&gt;&lt;/script&gt;
&lt;/head&gt;

&lt;body&gt;
&lt;div data-role=&quot;page&quot;&gt;
  &lt;div data-role=&quot;header&quot;&gt;
    &lt;h1&gt;$!{pageTitle}&lt;/h1&gt;
  &lt;/div&gt;&lt;!-- /header --&gt;

  &lt;div data-role=&quot;content&quot;&gt;
    ##Body Container 1
    #parseContainer('93cf710e-fbbb-4d32-a5fb-974dcac38c96')
  &lt;/div&gt;&lt;!-- /content --&gt;

  &lt;div data-role=&quot;footer&quot;&gt;
    &lt;h4&gt;Copyright &amp;copy;2011&lt;/h4&gt;
  &lt;/div&gt;&lt;!-- /footer --&gt;

&lt;/div&gt;&lt;!-- /page --&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<h3>jQuery Mobile and the #navigation() Macro</h3>
<p>If you want to use the #navigation() macro and take advantage of jQuery Mobile tooling, you just need to add a little extra JavaScript into the mix to ensure the list is picked up and styled correctly. A single line of JavaScript will get you rolling.</p>
<pre class="brush: jscript; html-script: true; title: ; notranslate">&lt;div id=&quot;navList&quot;&gt;
  #navigation(1 1)
&lt;/div&gt;  &lt;!-- ${esc.h}navList --&gt;
&lt;script&gt;
 $('${esc.h}navList&gt;ul').attr('data-role','listview');
&lt;/script&gt;</pre>
<p>By using the .attr() method, we can add in any of the data-roles or other attributes that can be used to control how the list navigation looks and behaves as a result of jQuery Mobile. (<em>Note: as seen in the above example, when writing code inline on the page and referencing ID&#8217;s, I replace all #s with ${esc.h}. This is the Velocity tool for printing out a hash, and is good for preventing accidental collisions in normal velocity code.</em>)</p>
<h3>Building a News Page</h3>
<p>In this example, I pull in a list of recent news headlines and spit them out readily formatted for my jQuery Mobile stylesheet (<em>Note: My code uses 1.7 syntax. However the principle remains unchanged for 1.9.</em>)</p>
<pre class="brush: xml; title: ; notranslate">#set($lastArticleDate = '0')
#set($today = $date.format('MM/dd/yyyy HH:mm:ss',$date.getDate()))
## FILTER DOWN TO A SPECIFIC SET OF NEWS CATEGORIES
#set($newsCatList = $categories.getChildrenCategoriesByKey('sections'))
#set($newsCats = &quot;+(&quot;)
#foreach($cat in $newsCatList)
  #set($newsCats = &quot;${newsCats}c${cat.inode}c:on &quot;)
#end
#set($newsCats = &quot;${newsCats})&quot;)
#set($query = &quot;+structureInode:5 ${newsCats} +date1:[1/1/2010 00:00:00 TO ${today}] +languageId:1* +deleted:false +live:true&quot;)
#pullContent(&quot;${query}&quot; '10' &quot;date1 desc&quot;)

&lt;div class=&quot;info&quot;&gt;
  The latest campus news from public relations.
&lt;/div&gt;

&lt;ul data-role=&quot;listview&quot;&gt;
#foreach($article in $list)
  ## SET DATE FOR COMPARISON
  #set($thisArticleDate = $date.format('EEEE, MMMM d, yyyy',$article.NewsPublishDate))
  ## IF CURRENT DATE IS DIFFERENT THAN THE LAST ARTICLE, PRINT OUT A DATE DIVIDER
  #if($thisArticleDate != $lastArticleDate)
	&lt;li data-role=&quot;list-divider&quot;&gt;${thisArticleDate}&lt;/li&gt;
  #end
	&lt;li&gt;&lt;a href=&quot;/news/detail.dot?id=${article.identifier}&quot;&gt;${article.NewsHeadline}&lt;/a&gt;&lt;/li&gt;
  #set($lastArticleDate = $date.format('EEEE, MMMM d, yyyy',$article.NewsPublishDate))
#end
&lt;/ul&gt;</pre>
<h3>Links, Tools, and Resources</h3>
<p>I mentioned several sites and tools when talking about mobile, here are many of them:</p>
<ul>
<li><a href="http://www.jquerymobile.com">jQuery Mobile</a> &#8211; A JavaScript framework that extends jQuery and helps add a number of mobile features to your site.</li>
<li><a href="http://www.phonegap.com/">PhoneGap</a> &#8211; Utility for compiling a web app into a wrapper so that you can deploy it as a native app for a number of mobile platforms.</li>
<li><a href="http://developer.android.com/sdk/index.html">Android SDK</a> &#8211; Free SDK for Android that comes with a mobile phone simulator, useful for testing.</li>
<li><a href="http://css-tricks.com/6731-css-media-queries/">CSS Media Queries &amp; Using Available Space</a> &#8211; Guide to how to implement CSS media queries for changing CSS rules based on display conditions reported by the browser.</li>
<li><a href="http://jquery-ui-map.googlecode.com/svn/trunk/demos/jquery-mobile-example.html">jQuery Mobile Google Maps Examples</a> &#8211; Nice list of ways to build on jQuery Mobile with Google Maps (i.e. pulling content from a buildings structure to populate a map)</li>
</ul>
<img src="http://feeds.feedburner.com/~r/LearnDotcms/~4/1070_aJ7a-k" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://learndotcms.com/2011/08/dotcms-and-mobile-techniques/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://learndotcms.com/2011/08/dotcms-and-mobile-techniques/</feedburner:origLink></item>
		<item>
		<title>Legacy Form Submission Security Patch</title>
		<link>http://feedproxy.google.com/~r/LearnDotcms/~3/M4SGKx31aIQ/</link>
		<comments>http://learndotcms.com/2011/06/legacy-form-submission-security-patch/#comments</comments>
		<pubDate>Mon, 27 Jun 2011 13:00:35 +0000</pubDate>
		<dc:creator>Michael Fienen</dc:creator>
				<category><![CDATA[Downloads]]></category>
		<category><![CDATA[Plugins]]></category>
		<category><![CDATA[exploit]]></category>
		<category><![CDATA[form]]></category>
		<category><![CDATA[patch]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[spam]]></category>

		<guid isPermaLink="false">http://learndotcms.com/?p=414</guid>
		<description><![CDATA[A while back, it was exposed that if using the legacy form submission struts path (e.g. /sendEmail, /submitWebForm, etc), a spammer could remotely invoke the tool and use it to send spam emails to people. While this wasn&#8217;t exactly a bug in the strictest sense, it could prove to be a headache for users should [...]]]></description>
			<content:encoded><![CDATA[<p>A while back, <a href="http://dotcms-users-forum-mailing-list.1045721.n5.nabble.com/dotCMS-hacked-We-are-under-attack-td3967554.html">it was exposed</a> that if using the legacy form submission struts path (e.g. /sendEmail, /submitWebForm, etc), a spammer could remotely invoke the tool and use it to send spam emails to people. While this wasn&#8217;t exactly a bug in the strictest sense, it could prove to be a headache for users should their server be targeted.</p>
<p>Enter <a href="http://costarica.com">costarica.com</a>. Thanks to their effort, a patch has been made available (for 1.9) that will force the server check the referring HTTP request against a list of approved server names and IPs. As a result, attempts to access the tool directly will be denied &#8211; the tool has to be invoked by a request originating from your site. This has been set up as a plugin for easy installation.</p>
<p><strong>Instructions:</strong></p>
<ol>
<li>Edit <code>conf/plugin.properties</code> to include your list of approved hostname (you&#8217;ll have to do this each time you add or remove hosts in dotCMS)</li>
<li>Copy the plugin to the <code>plugins/</code> folder of your dotCMS installation</li>
<li>Shut down dotCMS</li>
<li>Do an <code>ant clean-plugins deploy-plugins</code></li>
<li>Start up dotCMS</li>
</ol>
<p style="text-align: center;"><strong><a href="http://learndotcms.com/wp-content/plugins/download-monitor/download.php?id=18">[ DOWNLOAD Legacy Form Submission Security Patch 1.0 for dotCMS 1.9 ]</a></strong></p>
<img src="http://feeds.feedburner.com/~r/LearnDotcms/~4/M4SGKx31aIQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://learndotcms.com/2011/06/legacy-form-submission-security-patch/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://learndotcms.com/2011/06/legacy-form-submission-security-patch/</feedburner:origLink></item>
		<item>
		<title>JSON and AJAX and XML, Oh My!</title>
		<link>http://feedproxy.google.com/~r/LearnDotcms/~3/TjkiJVgm9MU/</link>
		<comments>http://learndotcms.com/2011/02/json-and-ajax-and-xml-oh-my/#comments</comments>
		<pubDate>Tue, 22 Feb 2011 18:49:17 +0000</pubDate>
		<dc:creator>Michael Fienen</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://learndotcms.com/?p=393</guid>
		<description><![CDATA[A question that has been coming up with some regularity lately has to do with doing dynamic, AJAX based work with the content engine in dotCMS. For some time, dotCMS has offered DWR as a means of handling those needs, but ultimately, DWR is a cumbersome, limited tool. In the end, there are two other [...]]]></description>
			<content:encoded><![CDATA[<p>A question that has been coming up with some regularity lately has to do with doing dynamic, AJAX based work with the content engine in dotCMS. For some time, dotCMS has offered <a href="http://directwebremoting.org/">DWR</a> as a means of handling those needs, but ultimately, DWR is a cumbersome, limited tool. In the end, there are two other ways of getting similar results which are much easier for most people to implement.</p>
<p>Since we&#8217;re going to ignore the existence of DWR, you&#8217;re going to need to be familiar with something like <a href="http://api.jquery.com/category/ajax/">jQuery for doing AJAX</a> work. You&#8217;re not going to get away from using JavaScript (it&#8217;s&#8230; you know&#8230; sort of integral to the whole concept of AJAX), but we can at least use something that&#8217;s more common and familiar. It doesn&#8217;t have to be jQuery, but that&#8217;s what I&#8217;ll be using here.</p>
<h3>Calling a Proxy Page</h3>
<p>This is the simplest way of handling AJAX needs. First, we&#8217;ll assume that you already know the context that the AJAX response is going to be used in. In that case, we&#8217;ll return some actual HTML ready to be inserted into a page. Set up a purely blank template if you don&#8217;t already have one (e.g. it has no other HTML on the page besides that supplied from its container), and include a single container. Now, make a page with that template, add a Simple Widget, and code it out to pull some content.</p>
<pre class="brush: xml; title: ; notranslate">## CHECK TO SEE IF A CATEGORY FILTER WAS SUPPLIED
#if($UtilMethods.isSet($request.getParameter('cat')) &amp;&amp; $request.getParameter('cat').length() &gt; 0)
	#set($queryParams = &quot; +categories:${request.getParameter('cat')}&quot;)
#end
## PULL THE LIST OF PRODUCT CONTENTLETS
#set($productList = $dotcontent.pull(&quot;+structureName:Product$!{queryParams}&quot;,0,&quot;modDate desc&quot;))
#if($productList.size() &gt; 0)
	#set($numResults = &quot;$!{productList.size()} product&quot;)
	## CHECK TO PLURALIZE 'product'
	#if($productList.size() &gt; 1)
		#set($numResults = &quot;$!{numResults}s&quot;)
	#end
#else
	#set($numResults = 'Sorry, no products were found in that category')
#end
&lt;p&gt;Found: $!{numResults}&lt;/p&gt;
&lt;ol&gt;
## SHOW THE LIST OF PRODUCTS
#foreach($con in $productList)
	&lt;li&gt;&lt;a href=&quot;/products/$!{con.urlTitle}&quot;&gt;$!{con.title}&lt;/a&gt;&lt;/li&gt;
#end
&lt;/ol&gt;</pre>
<p>This is a very simple example of an HTML response you could build to have the page return. Realistically, you can include as much or as little information here as you want, it just depends on what you plan to do with the data on the page where it ends up. In this case, assume it&#8217;s a basic search filter to show products on a page, allowing the visitor to filter based on the available categories. The result is a basic ordered list of links to the products that matched the search.</p>
<p>Next it&#8217;s all about setting up your front end page where visitors will view the content. Create a second page (using a normal template), and we&#8217;ll add in a search dropdown box and a little JavaScript to run things.</p>
<pre class="brush: xml; title: ; notranslate">&lt;form id=&quot;productSearch&quot; method=&quot;get&quot; action=&quot;&quot;&gt;
	&lt;label for=&quot;productCats&quot;&gt;Filter by:&lt;/label&gt;
	&lt;select id=&quot;productCats&quot;&gt;
		&lt;option value=&quot;&quot;&gt;ALL&lt;/option&gt;
#foreach($cat in $categories.getChildrenCategoriesByKey('productTypes'))
		&lt;option value=&quot;${cat.key}&quot;&gt;${cat.categoryName}&lt;/option&gt;
#end
	&lt;/select&gt;
&lt;/form&gt;  &lt;!-- ${esc.h}productSearch --&gt;

&lt;div id=&quot;productSearchResults&quot;&gt;&lt;/div&gt;

&lt;script type=&quot;text/javascript&quot;&gt;
	${esc.d}(document).ready(function() {
		var showProducts = function(cat) {
			${esc.d}.ajax({
				type: 'GET',
				url: 'product-response.dot',
				data: 'cat=' + cat,
				dataType: 'html',
				success: function(data) {
					${esc.d}('${esc.h}productSearchResults').html(data);
				}
			});
		};
		$('${esc.h}productCats').change(function() {
			var cat = $(this).val();
			showProducts(cat);
		});
		showProducts(null);
	});
&lt;/script&gt;</pre>
<p>So, very simple &#8211; search happens, jQuery requests info, response is returned, HTML is inserted into div. It&#8217;s simple to do, and works great when you know how the HTML is going to be handled.</p>
<h3>The JSONContent Servlet</h3>
<p>In 1.9, there is a new servlet tool you can use now that will return content as either JSON <em>or</em> XML data on demand. This is perfect when you don&#8217;t necessarily know what the HTML markup is that will be needed. And better, simply calling <em>http://www.yoursite.com/JSONContent</em> will give you the basic instructions to using the servlet. It takes six different parameters:</p>
<ul>
<li><strong>q</strong>: URLEncoded lucene query (required, try the <code>$UtilMethods.encodeURL($query)</code> viewtool)</li>
<li><strong>type</strong>: json or xml (default: xml)</li>
<li><strong>limit</strong>: number of results (default: 10, max of 1000)</li>
<li><strong>offset</strong>: start at specific result number (default: 0)</li>
<li><strong>orderBy</strong>: field to order by (default: modDate)</li>
<li><strong>debug</strong>: true/false; if set, will return JSON as text/plain (defaults: false)</li>
</ul>
<p>By making an AJAX request to this servlet we can basically do the same job as above. For instance, instead of hitting the <em>product-response.dot</em> page in the JavaScript, we could do <em><a href="http://demo.dotcms.org/JSONContent/?type=json&#038;q=%2BstructureName:product">http://demo.dotcms.org/JSONContent/?type=xml&#038;q=%2BstructureName:product</a></em>. This returns all the info on the contentlets in JSON format (remember, you could change the <em>type</em> parameter if you want to stick with XML) that we could then parse into the page. By working this way, we can drop the need for the proxy page, and we only need our main page to send this query. For the same kind of page, the changes would look something like:</p>
<pre class="brush: xml; title: ; notranslate">&lt;form id=&quot;productSearch&quot; method=&quot;get&quot; action=&quot;&quot;&gt;
    &lt;label for=&quot;productCats&quot;&gt;Filter by:&lt;/label&gt;
    &lt;select id=&quot;productCats&quot;&gt;
        &lt;option value=&quot;&quot;&gt;ALL&lt;/option&gt;
#foreach($cat in $categories.getChildrenCategoriesByKey('productTypes'))
        &lt;option value=&quot;${cat.categoryVelocityVarName}&quot;&gt;${cat.categoryName}&lt;/option&gt;
#end
    &lt;/select&gt;
&lt;/form&gt;  &lt;!-- ${esc.h}productSearch --&gt;

&lt;div id=&quot;productSearchResults&quot;&gt;&lt;/div&gt;

&lt;script type=&quot;text/javascript&quot;&gt;
${esc.d}(document).ready(function() {
	var showProducts = function(cat) {
		var catQ = '';
		if(cat &amp;&amp; cat.length &gt; 0) {
			catQ = '%20%2Bcategories:' + cat;
		}
		${esc.d}.ajax({
			url: '/JSONContent/',
			data: 'type=json&amp;q=%2BstructureName:product' + catQ,
			dataType: 'json',
			success: function(data) {
				${esc.d}('${esc.h}productSearchResults').html('');
				${esc.d}('${esc.h}productSearchResults').append('&lt;p&gt;Found: ' + data.contentlets.length + ' products&lt;/p&gt;&lt;ol&gt;&lt;/ol&gt;');
				${esc.d}.each(data.contentlets, function(i, contentlet) {
					${esc.d}('${esc.h}productSearchResults ol').append('&lt;li&gt;' + contentlet.title + '&lt;/li&gt;');
				});
			}
		});
        };

	${esc.d}('${esc.h}productCats').change(function() {
		var cat = ${esc.d}(this).val();
		showProducts(cat);
	});
	showProducts(null);
});
&lt;/script&gt;</pre>
<p>This effectively produces the exact same results as above. The only change we made to the form itself was the dropdown values now use the category&#8217;s Velocity variable name (in the previous example, we used the category key). Otherwise we get a JSON data response back from the /JSONContent servlet, and use the jQuery to loop the results into the page.</p>
<h3>Conclusions</h3>
<p>Overall, either way works just as well as another, and it is up to you which works best for your style or application. Additionally, you could write your own custom tools to output XML or JSON from dotCMS for other applications. The first method works well when you know the context you&#8217;ll use the response in and when you want to limit the amount of JavaScript you&#8217;re using. The second way is good when you may not know how the response is used or if you need to manipulate the base data before displaying it.</p>
<hr />Photo Credit: <a href="http://creativecommons.org/licenses/by-nc-sa/2.0/"><img class="colorbox-393"  style="vertical-align: middle; border: none;" title="Attribution" src="http://l.yimg.com/g/images/cc_icon_attribution_small.gif" border="0" alt="Attribution" /><img class="colorbox-393"  style="vertical-align: middle; border: none;" title="Noncommercial" src="http://l.yimg.com/g/images/cc_icon_noncomm_small.gif" border="0" alt="Noncommercial" /><img class="colorbox-393"  style="vertical-align: middle; border: none;" title="Share Alike" src="http://l.yimg.com/g/images/cc_icon_sharealike_small.gif" border="0" alt="Share Alike" /></a> <a title="Attribution-NonCommercial-ShareAlike License" href="http://creativecommons.org/licenses/by-nc-sa/2.0/">Some rights reserved</a> by <a href="http://www.flickr.com/photos/zippy/">ptufts</a></p>
<img src="http://feeds.feedburner.com/~r/LearnDotcms/~4/TjkiJVgm9MU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://learndotcms.com/2011/02/json-and-ajax-and-xml-oh-my/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://learndotcms.com/2011/02/json-and-ajax-and-xml-oh-my/</feedburner:origLink></item>
		<item>
		<title>Building a Velocity Portlet Plugin for IRC</title>
		<link>http://feedproxy.google.com/~r/LearnDotcms/~3/TB23NvfuuK8/</link>
		<comments>http://learndotcms.com/2011/01/building-a-velocity-portlet-plugin-for-irc/#comments</comments>
		<pubDate>Sat, 08 Jan 2011 23:52:55 +0000</pubDate>
		<dc:creator>Michael Fienen</dc:creator>
				<category><![CDATA[Back End]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Plugins]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[portlet]]></category>
		<category><![CDATA[Velocity]]></category>
		<category><![CDATA[velocity portlet]]></category>

		<guid isPermaLink="false">http://learndotcms.com/?p=375</guid>
		<description><![CDATA[This post will be dual purpose: first, to announce the release of the dotCMS IRC Client plugin, and second to provide a tutorial explaining how to launch a Velocity portlet plugin. Velocity portlets are a relatively simple way of building tools that can be built into the backend of dotCMS and be used as tabs [...]]]></description>
			<content:encoded><![CDATA[<p>This post will be dual purpose: first, to announce the release of the <a href="http://learndotcms.com/wp-content/plugins/download-monitor/download.php?id=17">dotCMS IRC Client plugin</a>, and second to provide a tutorial explaining how to launch a Velocity portlet plugin. Velocity portlets are a relatively simple way of building tools that can be built into the backend of dotCMS and be used as tabs that users can access. In this case, this plugin builds a portlet that includes the Freenode web based IRC client and an extra collaboration tool. We will deconstruct the plugin piece by piece so that you can see the components needed for such a tool.</p>
<p>To start off, you&#8217;ll want to set up the files and folders that you&#8217;ll need for the plugin. A basic portlet only requires a handful of files. The files listed in italics are required for any plugin &#8211; the rest are specific to this one:</p>
<ul>
<li>com.learndotcms.plugins.ircsupport
<ul>
<li><em>/conf</em>
<ul>
<li>Language-ext.properties</li>
<li><em>plugin.properties</em></li>
<li>portal-ext.xml</li>
</ul>
</li>
<li>/static_velocity
<ul>
<li>/portlet
<ul>
<li>irc.vm</li>
</ul>
</li>
</ul>
</li>
<li><em><em>build.xml</em></em></li>
<li><em><em>MANIFEST.MF</em></em></li>
</ul>
</li>
</ul>
<p>The two files in the root of your plugin are required, and extremely straightforward. The <code>build.xml</code> file is just to name the plugin internally, and the <code>MANIFEST.MF</code> file carries the specific details of the plugin. We don&#8217;t need to define a deploy class in the manifest file for this plugin, because our portlet stands on its own and doesn&#8217;t need to do anything when it&#8217;s installed. Otherwise, you can use the Deploy-Class field to list a Java class provided in the plugin that should be ran when the plugin is deployed. This can be done to do things like build a structure, add content, or do anything else that requires API interaction necessary for the plugin.</p>
<p><strong>build.xml</strong></p>
<pre class="brush: xml; title: ; notranslate">&lt;project name=&quot;dotCMS IRC Channel Client&quot; default=&quot;build&quot;&gt;
    &lt;import file=&quot;../common.xml&quot;/&gt;
&lt;/project&gt;</pre>
<p><strong>MANIFEST.MF</strong></p>
<pre class="brush: xml; title: ; notranslate">Manifest-Version: 1.0
Deploy-Class:
Plugin-Name: dotCMS IRC Channel Client
Plugin-Version: 1.110106
Author: Michael Fienen (http://learndotcms.com)</pre>
<p>From there, you&#8217;ll set up the two folders: <code>/conf</code> for the configuration elements, and <code>/static_velocity/portlet</code> which will store the code for our portlet. There&#8217;s very little configuration needed, and if you use the Hello World plugin as an example, it&#8217;s easy to modify. The language extension file is used to define the name of the portlet that will be visible in the back end:</p>
<p><strong>Language-ext.properties</strong></p>
<pre class="brush: xml; title: ; notranslate">javax.portlet.title.EXT_IRC_SUPPORT=dotCMS IRC Client</pre>
<p>In our portal extension file, mostly we just set the portlet name and the path to our Velocity file that will be used for the portlet. Take note that the <code>portlet-name</code> node (line 3) corresponds to the portlet title value from <code>Language-ext.properties</code> file. You&#8217;ll also set the view-template value on line 8 to correspond to your path inside the <code>/static_velocity</code> folder of your plugin.</p>
<p><strong>portal-ext.xml</strong></p>
<pre class="brush: xml; title: ; notranslate">&lt;!-- Use this file to add portlets and extend the portlet file --&gt;
&lt;portlet&gt;
    &lt;portlet-name&gt;EXT_IRC_SUPPORT&lt;/portlet-name&gt;
    &lt;display-name&gt;dotCMS IRC Client&lt;/display-name&gt;
    &lt;portlet-class&gt;com.liferay.portlet.VelocityPortlet&lt;/portlet-class&gt;
    &lt;init-param&gt;
        &lt;name&gt;view-template&lt;/name&gt;
        &lt;value&gt;/static/plugins/com.learndotcms.plugins.ircsupport/portlet/irc.vm&lt;/value&gt;
    &lt;/init-param&gt;
    &lt;expiration-cache&gt;0&lt;/expiration-cache&gt;
    &lt;supports&gt;
        &lt;mime-type&gt;text/html&lt;/mime-type&gt;
    &lt;/supports&gt;
    &lt;resource-bundle&gt;com.liferay.portlet.StrutsResourceBundle&lt;/resource-bundle&gt;
    &lt;security-role-ref&gt;
        &lt;role-name&gt;CMS User&lt;/role-name&gt;
    &lt;/security-role-ref&gt;
&lt;/portlet&gt;</pre>
<p>Finally, the <code>plugin.properties</code> file is required, and can be left simply as:</p>
<p><strong>plugin.properties</strong></p>
<pre class="brush: xml; title: ; notranslate">## The default for the reload.force is true.  If it is set to false the properties will only load once from
## the file. After that they will be stored and maintained in the database.  If true every time the server
## restart the properties will be cleared and reloaded.
reload.force=true</pre>
<p>Now, the fun starts. The heavy lifting for this plugin happens almost entirely in the <code>irc.vm</code> file. As a Velocity portlet, dotCMS effectively takes the file you define above in the portal extension file and wraps it in the back end tab structure, making it look nice, and allowing you to use code you are familiar with. We&#8217;ll start the file with some simple Velocity code that takes care of checking some cookie values and setting up option defaults:</p>
<p><strong>irc.vm (part 1/3)</strong></p>
<pre class="brush: xml; title: ; notranslate">## SEE IF A DEFAULT IRC NICKNAME HAS BEEN SET
#set($dotCMSIRCNick = $cookietool.get('dotCMSIRCNick').value)
#if($dotCMSIRCNick)
    ## SET THE STRING USED IN THE iframe SOURCE URI FOR PRESET NICKNAME
    #set($enableNick = &quot;nick=$!{dotCMSIRCNick}&amp;&quot;)
#end
## LOOK FOR DEFAULT HEIGHT AND WIDTH FOR THE POPUP CHAT CLIENT
#set($ircPopupW = $cookietool.get('ircPopupW').value)
#set($ircPopupH = $cookietool.get('ircPopupH').value)
## IF NO HEIGHT OR WIDTH DETECTED, USE DEFAULTS
#if(!$ircPopupW || $ircPopupW.length() == 0)
     #set($ircPopupW = 640)
#end
#if(!$ircPopupH || $ircPopupH.length() == 0)
    #set($ircPopupH = 400)
#end
## ACCOUNT FOR THE INNER HEIGHT OF THE POPUP CHAT CLIENT
#set($ircPopupIframe = $math.sub($ircPopupH,22))</pre>
<p>Next, we hit some basic CSS for the layout, and a whole lotta JavaScript. The JavaScript handles the popups (for chat and the Collabedit windows), and setting values from the option popup.</p>
<p><strong>irc.vm (part 2/3)</strong></p>
<pre class="brush: xml; title: ; notranslate">&lt;style type=&quot;text/css&quot;&gt;
${esc.h}credit {
    font-size:.8em;
    position:absolute;
    right: 0;
}
${esc.h}ircButtons {
    position:relative;
    text-align:center;
}
${esc.h}ircContainer {
    margin:1em auto;
    width:80%
}
    ${esc.h}ircContainer iframe {
        border:1px solid #ccc;
        height:400px;
        margin:1em 0 2em;
        width:100%;
    }
.subNavCrumbTrail {
    margin:-7px 0px 10px;
}
&lt;/style&gt;

&lt;script type=&quot;text/javascript&quot;&gt;
dojo.require(&quot;dojo.cookie&quot;);
dojo.require(&quot;dijit.form.Button&quot;);
dojo.require(&quot;dijit.form.TextBox&quot;);

/* Set up configurable settings based on cookie default values */
var ircPopupH = '$!{ircPopupH}';
var ircPopupW = '$!{ircPopupW}';
var iframeH = '$!{ircPopupIframe}';
var nick = '$!{dotCMSIRCNick}';

/* Set the user options from the popup form */
setCookie = function() {
    /* Get config field values */
    var isValid = true;
    var nickVal = document.getElementById('ircNick').value;
    var popupW = document.getElementById('popupW').value;
    var popupH = document.getElementById('popupH').value;

    /* Validate the fields */
    if(!isAlpha(nickVal) || !isNumeric(popupW) || !isNumeric(popupH)) {
        isValid = false;
    }

    if(isValid) {
        /* Default IRC Nickname */
        nick = nickVal;
        dojo.cookie(&quot;dotCMSIRCNick&quot;, nick, {
            expires: 365
        });

        /* Default Chat Window Popup Width */
        ircPopupW = popupW;
        dojo.cookie(&quot;ircPopupW&quot;, popupW, {
            expires: 365
        });

        /* Default Chat Window Popup Height */
        ircPopupH = popupH;
        iframeH   = ircPopupH - 22;
        dojo.cookie(&quot;ircPopupH&quot;, popupH, {
            expires: 365
        });
        dijit.byId('optionsDiv').hide();
    } else {
        alert('Please check configuration settings');
    }
};

/* Open IRC chat popup window */
openIRCPopup = function() {
    newwindow = window.open('','irc','height=' + ircPopupH + ',width=' + ircPopupW + ',resizable=0');
    var tmp = newwindow.document;
    tmp.write('&lt;html&gt;&lt;head&gt;&lt;title&gt;dotCMS IRC Client&lt;/title&gt;');
    tmp.write('&lt;/head&gt;&lt;body style=&quot;margin:0;padding:10px;&quot;&gt;');
    tmp.write('&lt;iframe style=&quot;width:100%;height:' + iframeH + 'px;border:1px solid #ccc;&quot; src=&quot;http://webchat.freenode.net?nick=' + nick + '&amp;channels=dotcms&amp;uio=MTE9MjM20f&quot;&gt;&lt;/iframe&gt;');
    tmp.write('&lt;/body&gt;&lt;/html&gt;');
    tmp.close();
};

/* Open options popup */
showOptions = function() {
    dijit.byId('optionsDiv').show();
};

/* Open a collabedit popup */
collaborate = function() {
    window.open('http://collabedit.com/new','collabedit','top=200,left=200,height=600,width=800,resizable=1,status=0,location=1,menubar=0,directories=0');
}

/* Validator functions */
isNumeric = function(str) {
    return str.match(/^\d+$/);
};
isAlpha = function(str) {
    return str.match(/^[A-Za-z0-9_-]*$/);
};
&lt;/script&gt;</pre>
<p>Finally, we just need to lay out the HTML for the visible part of the portlet. In this case, we use an <code>iframe</code> embed for the Freenode web IRC client (based on <a href="http://qwebirc.org/">qwebirc</a>). Below that, a few buttons that allow the user to open a popup with the chat client in it (created using the <code>openIRCPopup()</code> function above on line 76), open a popup with a <a href="http://collabedit.com/">Collabedit</a> panel in it (useful for brainstorming or trying to get help from folks in the IRC channel), and finally the options popup. Be sure to note in the HTML the use of Dojo properties on the buttons and dialog to make the look and feel of everything blend in with the rest of the backend.</p>
<p><strong>irc.vm (part 3/3)</strong></p>
<pre class="brush: xml; title: ; notranslate">&lt;div class=&quot;subNavCrumbTrail&quot;&gt;
    &lt;ul&gt;
        &lt;li id=&quot;selectHostDiv&quot; style=&quot;&quot; onclick=&quot;window.location='/admin';&quot;&gt;&lt;img src=&quot;/html/images/icons/globe-grey.png&quot; width=&quot;16&quot; height=&quot;16&quot; title=&quot;global page&quot; align=&quot;absmiddle&quot; hspace=&quot;5&quot; /&gt;Home&lt;/li&gt;
        &lt;li&gt;&lt;span&gt;dotCMS IRC Chat&lt;/span&gt;&lt;/li&gt;
    &lt;/ul&gt;
    &lt;div class=&quot;clear&quot;&gt;&lt;/div&gt;
&lt;/div&gt;  &lt;!-- .subNavCrumbTrail --&gt;
&lt;div class=&quot;clear&quot;&gt;&lt;/div&gt;

&lt;div id=&quot;ircContainer&quot;&gt;
    &lt;iframe src=&quot;http://webchat.freenode.net?$!{enableNick}channels=dotcms&amp;uio=MTE9MjM20f&quot;&gt;&lt;/iframe&gt;

    &lt;div id=&quot;ircButtons&quot;&gt;
        &lt;div id=&quot;credit&quot;&gt;
            Brought to you by &lt;a href=&quot;http://learndotcms.com/&quot; target=&quot;_blank&quot;&gt;LearndotCMS.com&lt;/a&gt;
        &lt;/div&gt;  &lt;!-- ${esc.h}credit --&gt;

        &lt;button dojoType=&quot;dijit.form.Button&quot; iconClass=&quot;browseIcon&quot; onClick=&quot;openIRCPopup();&quot; tabindex=&quot;0&quot;&gt;Popout Chat&lt;/button&gt;
        &lt;button dojoType=&quot;dijit.form.Button&quot; iconClass=&quot;publishIcon&quot; onClick=&quot;collaborate();&quot; tabindex=&quot;1&quot;&gt;Collaborate&lt;/button&gt;
        &lt;button dojoType=&quot;dijit.form.Button&quot; iconClass=&quot;editIcon&quot; onClick=&quot;showOptions();&quot; tabindex=&quot;2&quot;&gt;Options&lt;/button&gt;
    &lt;/div&gt;  &lt;!-- ${esc.h}ircButtons --&gt;
&lt;/div&gt;  &lt;!-- ${esc.h}ircContainer --&gt;

&lt;div id=&quot;optionsDiv&quot; dojoType=&quot;dijit.Dialog&quot; title=&quot;IRC Options&quot; style=&quot;display:none;&quot;&gt;
    &lt;p&gt;&lt;label for=&quot;ircNick&quot;&gt;Default Nickname:&lt;/label&gt; &lt;input type=&quot;text&quot; name=&quot;ircNick&quot; id=&quot;ircNick&quot; tabindex=&quot;3&quot; value=&quot;$!{dotCMSIRCNick}&quot; /&gt;&lt;/p&gt;
    &lt;p&gt;&lt;label for=&quot;popupW&quot;&gt;Popup Size:&lt;/label&gt; &lt;input type=&quot;text&quot; name=&quot;popupW&quot; id=&quot;popupW&quot; tabindex=&quot;4&quot; value=&quot;$!{ircPopupW}&quot; placeholder=&quot;w&quot; size=&quot;3&quot; /&gt;px by &lt;input type=&quot;text&quot; name=&quot;popupH&quot; id=&quot;popupH&quot; tabindex=&quot;5&quot; value=&quot;$!{ircPopupH}&quot; placeholder=&quot;h&quot; size=&quot;3&quot; /&gt;px&lt;/p&gt;
    &lt;div style=&quot;text-align:center;&quot;&gt;
        &lt;button dojoType=&quot;dijit.form.Button&quot; iconClass=&quot;saveIcon&quot; onClick=&quot;setCookie();&quot; tabindex=&quot;6&quot;&gt;Save Options&lt;/button&gt;
        &lt;button dojoType=&quot;dijit.form.Button&quot; iconClass=&quot;cancelIcon&quot; onClick=&quot;dijit.byId('optionsDiv').hide();&quot; tabindex=&quot;7&quot;&gt;Cancel&lt;/button&gt;
    &lt;/div&gt;
    &lt;div&gt;
        &lt;small&gt;&lt;em&gt;Clear your cookies to reset IRC settings to their defaults.&lt;/em&gt;&lt;/small&gt;
    &lt;/div&gt;
&lt;/div&gt;</pre>
<p>Now, save all this stuff out, and dump your folder into the <code>/plugins</code> directory in your dotCMS install. From here on out, it&#8217;s all simply configuration. Start but shutting down your server, open a command prompt, navigate to the dotCMS directory and run the command:</p>
<ul>
<li><code>ant clean-plugins deploy-plugins</code></li>
</ul>
<div id="attachment_382" class="wp-caption alignleft" style="width: 310px"><a href="http://learndotcms.com/wp-content/uploads/2011/01/addPortletToTab.png"><img class="size-medium wp-image-382 colorbox-375" title="addPortletToTab" src="http://learndotcms.com/wp-content/uploads/2011/01/addPortletToTab-300x186.png" alt="Set up a new portlet on a tab" width="300" height="186" /></a><p class="wp-caption-text">Set up a new portlet on a tab</p></div>
<p>Then, start dotCMS back up, log in to the back end, and under the <em>CMS Admin</em> tab open up <em>Roles, Tabs, &amp; Tools</em>. How you deploy this particular portlet is up to you. For instance, you could create a new tab and dedicate it to the chat client, or make it a child of an existing tab, such as the <em>Home </em>tab. In the screenshot to the left we have opened up the <em>Home </em>tab and selected the new portlet from the <em>Tools </em>dropdown list. Click the <em>Add </em>button, and you can drag and drop the portlets in the order you want them to appear in the menu (if you create a dedicated tab, you can just put one portlet on it and there won&#8217;t be a menu, clicking the tab will just go straight to it.). Refresh the page, and you&#8217;re golden. You can repeat this process for whichever roles you want to have access to the client.</p>
<div id="attachment_384" class="wp-caption alignright" style="width: 310px"><a href="http://learndotcms.com/wp-content/uploads/2011/01/ircPortlet.png"><img class="size-medium wp-image-384 colorbox-375" title="ircPortlet" src="http://learndotcms.com/wp-content/uploads/2011/01/ircPortlet-300x196.png" alt="The IRC Portlet plugin" width="300" height="196" /></a><p class="wp-caption-text">The IRC Portlet plugin</p></div>
<p>Wherever you tell dotCMS to load the portlet, clicking on it will open a page that will read in the source VM file from your plugin. In our case, it shows our embedded chat client, and extra buttons. By researching the setup of other portlet pages in the backend, applying the appropriate markup to the buttons results in a very familiar feel, allowing you to build something that isn&#8217;t just crowbarred into the backend (though, nothing&#8217;s stopping you from doing it ugly, it&#8217;s just really easy to get that extra polish).</p>
<div id="attachment_383" class="wp-caption alignleft" style="width: 310px"><a href="http://learndotcms.com/wp-content/uploads/2011/01/ircOptions.png"><img class="size-medium wp-image-383 colorbox-375" title="ircOptions" src="http://learndotcms.com/wp-content/uploads/2011/01/ircOptions-300x145.png" alt="Options popup" width="300" height="145" /></a><p class="wp-caption-text">Options popup</p></div>
<p>We also added a <a href="http://dojotoolkit.org/reference-guide/dijit/info.html#dijit-info">Dijit</a> powered dialog box to control the portlet options. All it is needs is a hidden div with some markup, and Dojo handles the rest (lines 24-34 in <code>irc.vm</code> part 3). In some cases, you can hardcode plugin options into the plugin.properties file. That&#8217;s fine. In this case, I wanted the options to be specific per user, without going through the effort of tying into the user settings. The answer was simply adding in a little JavaScript to set up cookies that will last for a year on the machine. When the page loads, we read in those cookie values and use them to customize the chat client and its popup.</p>
<p>Overall, this is about as simple a process as you could ask for. Being Velocity powered, you can access anything you would normally be able to get into on web pages. That might be usage of viewtools, pulling content, or utilizing macros. Better yet, you don&#8217;t need to learn any complex Struts mapping or Java code to try it out.</p>
<p style="text-align: center;"><a href="http://learndotcms.com/wp-content/plugins/download-monitor/download.php?id=17"><strong>[ Download the IRC Plugin (v1.110106) ]</strong></a></p>
<h3>Image Gallery</h3>

<a href='http://learndotcms.com/2011/01/building-a-velocity-portlet-plugin-for-irc/ircfeature/' title='ircFeature'><img width="150" height="150" src="http://learndotcms.com/wp-content/uploads/2011/01/ircFeature-150x150.png" class="attachment-thumbnail colorbox-375" alt="ircFeature" title="ircFeature" /></a>
<a href='http://learndotcms.com/2011/01/building-a-velocity-portlet-plugin-for-irc/addportlettotab/' title='addPortletToTab'><img width="150" height="150" src="http://learndotcms.com/wp-content/uploads/2011/01/addPortletToTab-150x150.png" class="attachment-thumbnail colorbox-375" alt="Set up a new portlet on a tab" title="addPortletToTab" /></a>
<a href='http://learndotcms.com/2011/01/building-a-velocity-portlet-plugin-for-irc/ircoptions/' title='ircOptions'><img width="150" height="150" src="http://learndotcms.com/wp-content/uploads/2011/01/ircOptions-150x150.png" class="attachment-thumbnail colorbox-375" alt="Options popup" title="ircOptions" /></a>
<a href='http://learndotcms.com/2011/01/building-a-velocity-portlet-plugin-for-irc/ircportlet/' title='ircPortlet'><img width="150" height="150" src="http://learndotcms.com/wp-content/uploads/2011/01/ircPortlet-150x150.png" class="attachment-thumbnail colorbox-375" alt="The IRC Portlet plugin" title="ircPortlet" /></a>

<img src="http://feeds.feedburner.com/~r/LearnDotcms/~4/TB23NvfuuK8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://learndotcms.com/2011/01/building-a-velocity-portlet-plugin-for-irc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://learndotcms.com/2011/01/building-a-velocity-portlet-plugin-for-irc/</feedburner:origLink></item>
		<item>
		<title>Enter Nutch, Stage Left</title>
		<link>http://feedproxy.google.com/~r/LearnDotcms/~3/PANzM3ilidI/</link>
		<comments>http://learndotcms.com/2010/12/enter-nutch-stage-left/#comments</comments>
		<pubDate>Wed, 29 Dec 2010 15:00:09 +0000</pubDate>
		<dc:creator>Michael Fienen</dc:creator>
				<category><![CDATA[Back End]]></category>
		<category><![CDATA[Front End]]></category>
		<category><![CDATA[nutch]]></category>
		<category><![CDATA[search]]></category>
		<category><![CDATA[spindle]]></category>

		<guid isPermaLink="false">http://learndotcms.com/?p=323</guid>
		<description><![CDATA[Spindle sucked. Say it with me. Spindle sucked. As far as search goes, sure, it was better than nothing. The problem was that the Spindle backbone wasn&#8217;t very robust as far as search algorithms go, there was no UI for it, and the kind of results you could get were pretty limited. Not to mention [...]]]></description>
			<content:encoded><![CDATA[<p>Spindle sucked. Say it with me. <em>Spindle sucked</em>. As far as search goes, sure, it was better than nothing. The problem was that the Spindle backbone wasn&#8217;t very robust as far as search algorithms go, there was no UI for it, and the kind of results you could get were pretty limited. Not to mention development on the Spindle project seems to have ceased. Now, you could have always tied into Google Custom Search with the <code>$googleminiapi</code> viewtool, which was perfectly fine, but that then requires you to be set up in Google, and it takes some control out of your hands.</p>
<p><a href="http://nutch.apache.org/">Nutch</a> was introduced as the solution. Nutch is one of many Apache projects implemented within dotCMS. What makes Nutch powerful is that it is built on top of Lucene and Solr, it includes a crawler engine, and is capable of crawling web pages and documents alike. On top of all that, <a href="http://dotcms.com/docs/1.9/SiteSearch">dotCMS also implemented a portlet</a> to run it from (Technically, Spindle had one, but you had to manually call its URI, and all it did was instantiate it). In summation, you end up with a much nicer tool with a lot more flexibility if you need to add search to your site.</p>
<div id="attachment_347" class="wp-caption alignright" style="width: 310px"><a href="http://learndotcms.com/wp-content/uploads/2010/12/fig7-nutch.png"><img class="size-medium wp-image-347 colorbox-323" title="fig7-nutch" src="http://learndotcms.com/wp-content/uploads/2010/12/fig7-nutch-300x285.png" alt="The Site Search Portlet" width="300" height="285" /></a><p class="wp-caption-text">The Site Search Portlet</p></div>
<p>The Site Search portlet is available under the CMS Admin tab. You can enable or disable it per host if you choose, set up the crawl schedule (using a <a href="http://en.wikipedia.org/wiki/CRON_expression#Examples">cron expression</a>), and control exclusions. It&#8217;s powerful enough to be useful, but simple enough to not be intimidating. Some people experienced in search might find it a bit limiting, but that&#8217;s when you can switch to using Google or an appliance. This is a nice balance to being a tool more powerful than the default search in something like WordPress, and not being something that takes hours to figure out.</p>
<p>You interact with Nutch via the <code>$sitesearch</code> viewtool, which just has a single method to worry about: <code>$sitesearch.search($query, $sortBy, $startNum, $numRows, $request)</code>. This will return a <code>DotSearchResults</code> object that has a number of fields serialized in that you can call (assuming we&#8217;ve set the viewtool results to a Velocity variable called <code>$results</code>):</p>
<ul>
<li>$results.responseType</li>
<li>$results.query</li>
<li>$results.lang</li>
<li>$results.reverse</li>
<li>$results.start</li>
<li>$results.rows</li>
<li>$results.end</li>
<li>$results.totalHits</li>
<li>$results.hits</li>
<li>$results.details</li>
<li>$results.summaries</li>
<li>$results.withSummary</li>
<li>$results.misspellings</li>
</ul>
<p>Most of these are specifically details related to the search itself, such as the total hits it found, and alternative spelling suggestions. When you go to display the results, you&#8217;ll be working specifically with the <code>.details</code> and <code>.summaries</code> fields. For example:</p>
<pre class="brush: xml; title: ; notranslate">#* PERFORM THE SEARCH FOR THE QUERY, STARTING
AT THE BEGINNING, GETTING 10 RESULTS *#
#set($results = $sitesearch.search($request.getParameter('query'), null, 0, 10, $request))
## PULL OUT THE DETAIL SETS AND RESULT SUMMARIES
#set($details = $results.details)
#set($summaries = $results.summaries)
&lt;ol&gt;
#foreach ($i in [0..$math.sub($results.end,1)])
    &lt;li&gt;
        &lt;strong&gt;$!{details.get($i).getValue('title')}&lt;/strong&gt;&lt;br /&gt;
        $!{summaries.get($i).toHtml(true)}&lt;br /&gt;
        &lt;small&gt;&lt;a href=&quot;$!{details.get($i).getValue('url')}&quot;&gt;$!{details.get($i).getValue('url')}&lt;/a&gt;&lt;/small&gt;
    &lt;/li&gt;
#end
&lt;/ol&gt;</pre>
<p>Overall, implementing Nutch isn&#8217;t particularly any more difficult or easy than it was to use Spindle, but level of control and improved results are what make the difference. This also shows off a very nice foundation that we can hope is used to develop an even more robust featureset down the road. Below, you can catch Dean&#8217;s walkthrough of the tool as well, where he shows how you enable and setup Nutch.</p>
<p><embed src="http://blip.tv/play/he9%2BgoqXcwI%2Em4v" type="application/x-shockwave-flash" width="620" height="440" allowscriptaccess="always" allowfullscreen="true"></embed></p>
<p><strong>* NOTE: Windows users will need to install <a href="http://www.cygwin.com/">CYGWIN</a> in order to use Nutch on Windows based machines and servers, due to the linux tools Nutch uses natively.</strong></p>
<hr />
Photo Credit: <span class="ccIcn ccIcnSmall"><a href="http://creativecommons.org/licenses/by-nc-sa/2.0/"><img class="colorbox-323"  src="http://l.yimg.com/g/images/cc_icon_attribution_small.gif" border="0" alt="Attribution" title="Attribution" style="border:none;vertical-align:middle;"><img class="colorbox-323"  src="http://l.yimg.com/g/images/cc_icon_noncomm_small.gif"  border="0" alt="Noncommercial" title="Noncommercial" style="border:none;vertical-align:middle;"><img class="colorbox-323"  src="http://l.yimg.com/g/images/cc_icon_sharealike_small.gif"  border="0" alt="Share Alike" title="Share Alike" style="border:none;vertical-align:middle;"></a></span> <a href="http://creativecommons.org/licenses/by-nc-sa/2.0/" title="Attribution-NonCommercial-ShareAlike License">Some rights reserved</a> by <a href="/photos/morganfrederick94/">morgan frederick.</a> </p>
<img src="http://feeds.feedburner.com/~r/LearnDotcms/~4/PANzM3ilidI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://learndotcms.com/2010/12/enter-nutch-stage-left/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://learndotcms.com/2010/12/enter-nutch-stage-left/</feedburner:origLink></item>
		<item>
		<title>User Role Based Custom Content</title>
		<link>http://feedproxy.google.com/~r/LearnDotcms/~3/QLz7Ido6tAY/</link>
		<comments>http://learndotcms.com/2010/12/user-role-based-custom-content/#comments</comments>
		<pubDate>Tue, 28 Dec 2010 20:40:20 +0000</pubDate>
		<dc:creator>Michael Fienen</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Front End]]></category>
		<category><![CDATA[Viewtools]]></category>
		<category><![CDATA[CMSUserWebAPI]]></category>
		<category><![CDATA[content]]></category>
		<category><![CDATA[roles]]></category>
		<category><![CDATA[viewtool]]></category>

		<guid isPermaLink="false">http://learndotcms.com/?p=333</guid>
		<description><![CDATA[Today let&#8217;s take a look at a way of leveraging the CMSUserWebAPI in order to serve custom content to registered users on your site. The basic premise is quite simple: check for certain user roles in a loop, and conditionally pull content into a widget. For the sake of argument, we&#8217;ll assume you&#8217;re already versed [...]]]></description>
			<content:encoded><![CDATA[<p>Today let&#8217;s take a look at a way of leveraging the <a href="http://www.dotcms.org/api/com/dotmarketing/viewtools/CMSUsersWebAPI.html">CMSUserWebAPI</a> in order to serve custom content to registered users on your site. The basic premise is quite simple: check for certain user roles in a loop, and conditionally pull content into a widget. For the sake of argument, we&#8217;ll assume you&#8217;re already versed in setting up user registration in dotCMS. This tutorial will be set up around the idea of displaying ads to different users, but you could ultimately use it for any kind or format of content.</p>
<p>To start, we&#8217;ll set up a structure for advertising. This could just as easily be Web Page Content, or content that is hard coded into the widget. In this case, by creating the structure, it gives us some control over things like run dates, groupings, etc. This is just a suggestion for such a structure, you might add or remove fields to suit your needs. A couple comments: Ad Groups could be a custom field fed from another structure where you define the individual groups (such as header banner ads, sidebar ads, footer ads, interstitials, etc). You could also add a field for impressions, if you charge for a set number of views on an ad, and compare that against the results of <code>#getNumViews("$identifier")</code> before showing the ad. Both the checkboxes listed are just &#8220;Yes&#8221; fields that could allow you some control to override functionality.</p>
<div id="attachment_334" class="wp-caption aligncenter" style="width: 610px"><a href="http://learndotcms.com/wp-content/uploads/2010/12/adStructure.png"><img class="size-full wp-image-334 colorbox-333" title="adStructure" src="http://learndotcms.com/wp-content/uploads/2010/12/adStructure.png" alt="Ad Structure Configuration" width="600" /></a><p class="wp-caption-text">Ad Structure Configuration</p></div>
<p>Once you have the structure, toss some ads in to it so you have some content to work with. If you are using ad groups, you&#8217;ll need to build those in to your template/container/widget. The ad group set for that area will then be incorporated into your pull for that area. When I say &#8220;build the ad group in,&#8221; all I mean is setting up the space in your HTML (see example below). Alternatively, you may just pull ads based on size restrictions, or whatever other conditions you want to apply.</p>
<div id="attachment_337" class="wp-caption alignright" style="width: 265px"><a href="http://learndotcms.com/wp-content/uploads/2010/12/adlevels.png"><img class="size-full wp-image-337 colorbox-333" title="adlevels" src="http://learndotcms.com/wp-content/uploads/2010/12/adlevels.png" alt="View of user roles" width="255" height="278" /></a><p class="wp-caption-text">View of user roles</p></div>
<p>With that done, we&#8217;ll make some user roles. These will be applied to users based on whatever criteria you deem necessary. Perhaps you have paid accounts, or simply &#8220;honor&#8221; levels that are earned after a period of time. Under the user role manager, we&#8217;ll make a root role call &#8220;Ad View Levels&#8221; with two children: <em>Level 1 Ads</em> and <em>Level 2 Ads</em>. These will reflect which ads on your site users see. These can be completely arbitrary designations based on what you want. In our case, we&#8217;ll define the roles as follows:</p>
<ul>
<li><strong>CMS Anonymous &#8211; </strong>View All Ads</li>
<li><strong>Level 1 Ads &#8211; </strong>View Some Ads</li>
<li><strong>Level 2 Ads &#8211; </strong>View No Ads</li>
</ul>
<p>Now, we can start defining our Velocity blocks that will control the ad display. Depending on how you are showing ads (or whatever content) you can selectively make these blocks as complex or simply as necessary.  With three levels like what I&#8217;ve listed, some blocks would have a second check, while others don&#8217;t, based on what Level 1 is allowed to ignore or not.</p>
<p>To set up your code, we start by seeing if the user is logged in. Then we check the roles, then if necessary, show the ad. To simplify things, we&#8217;ll mostly separate the two steps in our code into the logic and the HTML, that way you don&#8217;t even get an empty ad block when it&#8217;s not included. There would simply be nothing in the DOM from the ads at all. So, here&#8217;s the basic logic.</p>
<p><strong>Logic Block:</strong></p>
<pre class="brush: xml; title: ; notranslate">## DEFAULT DISPLAY SETTINGS
#set($showAds = true)
#set($showNumAds = 2)
## CHECK FOR CHANGES TO DISPLAY DEFAULTS
#if($user)
    #if($cmsuser.isUserRole($user, &quot;Level 2 Ads&quot;))
        ## DISABLE ADS
        #set($showAds = false)
    #elseif($cmsuser.isUserRole($user, &quot;Level 1 Ads&quot;))
        ## REDUCE NUMBER OF ADS SHOWN
        #set($showNumAds = 1)
    #end
#end</pre>
<p>First, we assume by default (in other words, for CMS Anonymous users) that we want to show ads. We also say the default is to show two ads. Then, we check to see if a user is logged in and determine which level they are. For Level 2 users, just disable the display block. For Level 1 users, we&#8217;ll show them an ad here, but we&#8217;ll set it to only show one instead of two.</p>
<p><strong>HTML Block:</strong></p>
<pre class="brush: xml; title: ; notranslate">#if($showAds)
&lt;div id=&quot;adGroup1&quot;&gt;
    #foreach($ad in $dotcontent.pull('+structureName:Advertising +Advertising.adGroup:1',$showNumAds,'random'))
    &lt;div id=&quot;ad1-${velocityCount}&quot; class=&quot;ad&quot;&gt;
        &lt;a href=&quot;${ad.targetUri}&quot; target=&quot;_blank&quot;&gt;
            &lt;img src=&quot;${ad.adImage.getResizeUri(125,125)}&quot; alt=&quot;${ad.advertiser}&quot; height=&quot;125&quot; width=&quot;125&quot; /&gt;
        &lt;/a&gt;
    &lt;/div&gt;  &lt;!-- ${esc.h}ad1-${velocityCount} .ad --&gt;
    #end
&lt;/div&gt;  &lt;!-- ${esc.h}adGroup1 --&gt;
#end</pre>
<p>In the display block, the first thing we do is see if <code>$showAds</code> was disabled. If not, start up the HTML. Then do the content pull based on the ad group (in this case, we hard coded group 1 into the query, but it could just as easily be a variable with the whole pulling mechanism done as a macro if you have a lot of ad groups and don&#8217;t want to maintain this code everywhere), using the number variable for whether or not to pull one or two ads. From there, show the ad, use the target URI, and push the image through the image resizer to make sure it fits the space right.</p>
<p>There are a number of ways besides ads this could be used. Premium content, special promo codes, sneak peaks at content, or show administrative debug info without being in Edit Mode. Play with different applications, and pay attention to what other tools are available in the user API. If you want to see some other examples, be sure to review our <a href="/2010/07/interacting-with-user-accounts/">previous post on user accounts</a>.</p>
<hr />Photo Credit: <a href="http://creativecommons.org/licenses/by-nc-nd/2.0/"><img class="colorbox-333"  style="vertical-align: middle; border: none;" title="Attribution" src="http://l.yimg.com/g/images/cc_icon_attribution_small.gif" border="0" alt="Attribution" /><img class="colorbox-333"  style="vertical-align: middle; border: none;" title="Noncommercial" src="http://l.yimg.com/g/images/cc_icon_noncomm_small.gif" border="0" alt="Noncommercial" /><img class="colorbox-333"  style="vertical-align: middle; border: none;" title="No Derivative Works" src="http://l.yimg.com/g/images/cc_icon_noderivs_small.gif" border="0" alt="No Derivative Works" /></a> <a title="Attribution-NonCommercial-NoDerivs License" href="http://creativecommons.org/licenses/by-nc-nd/2.0/">Some rights reserved</a> by <a href="http://www.flickr.com/photos/kelvin255/">kelvin255</a></p>
<img src="http://feeds.feedburner.com/~r/LearnDotcms/~4/QLz7Ido6tAY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://learndotcms.com/2010/12/user-role-based-custom-content/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://learndotcms.com/2010/12/user-role-based-custom-content/</feedburner:origLink></item>
		<item>
		<title>Apache and dotCMS: Happily Ever After</title>
		<link>http://feedproxy.google.com/~r/LearnDotcms/~3/9HtV8g81wvc/</link>
		<comments>http://learndotcms.com/2010/10/apache-and-dotcms-happily-ever-after/#comments</comments>
		<pubDate>Thu, 21 Oct 2010 12:55:55 +0000</pubDate>
		<dc:creator>Xander Steinmann</dc:creator>
				<category><![CDATA[Administration]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[mod_jk]]></category>

		<guid isPermaLink="false">http://learndotcms.com/?p=253</guid>
		<description><![CDATA[dotCMS has many ways to handle multiple hosts, permission hosts and force https. But sometimes you just need more&#8230; For instance, you want a host to only be visible from certain IP&#8217;s or you want to password protect a site before it goes live. All things that could be handled by permissions or plugins if [...]]]></description>
			<content:encoded><![CDATA[<p>dotCMS has many ways to handle multiple hosts, permission hosts and force https. But sometimes you just need more&#8230; For instance, you want a host to only be visible from certain IP&#8217;s or you want to password protect a site before it goes live. All things that could be handled by permissions or plugins if you wanted to, but Apache is there to easily solve these issues for you and give you extra functionality. This post will show you some examples. To start I will show you how you can easily set-up Apache on your server.</p>
<h3>Hooking up Apache with dotCMS</h3>
<p>Apache will allow you to run multiple web containers on your server. This means that you can have multiple dotCMS instances on your server or, for instance, you can have <a href="http://jboss.org/">JBoss</a> running next to dotCMS. And you can have this running within an hour! The only things you need to is <a href="http://httpd.apache.org/">download Apache</a> plus <a href="http://tomcat.apache.org/download-connectors.cgi">mod_jk</a>, configure Apache and set up an <a href="http://tomcat.apache.org/connectors-doc-archive/jk2/common/AJPv13.html">AJP13 connector</a> in the dotCMS server.xml file. An example:</p>
<p><strong>workers.properties (Apache)</strong></p>
<pre class="brush: xml; title: ; notranslate"># Define workers
worker.list=dotcms

#Set properties for worker 'dotcms'
worker.dotcms.type=ajp13
worker.dotcms.host=localhost
worker.dotcms.port=28009

worker.dotcms.cachesize=10
worker.dotcms.cache_timeout=600
worker.dotcms.socket_keepalive=1
worker.dotcms.recycle_timeout=300</pre>
<p>The port 28009 in this case is the port of the AJP13 connector that you need to set in the server.xml of dotCMS. Note that since Apache will handle all the incoming HTTP calls, it should run on port 80 and DotCMS shouldn&#8217;t. On which port dotCMS runs is up to you (you can set it in the server.xml), as long as you match the AJP13 ports in the Apache workers.properties and the dotCMS server.xml and the port isn&#8217;t used already.</p>
<p><strong>server.xml</strong></p>
<pre class="brush: xml; title: ; notranslate">&lt;!-- Define an AJP 1.3 Connector on port 8009 --&gt;
&lt;Connector port=&quot;28009&quot; protocol=&quot;AJP/1.3&quot; redirectPort=&quot;28443&quot; /&gt;</pre>
<p><strong>Apache config</strong></p>
<p>In Apache you need to configure your sites. You can add the following code in httpd.conf, or when you have many sites you can add it in seperate configuration files using the include command: Include conf/vhosts/*.conf</p>
<pre class="brush: xml; title: ; notranslate">&lt;VirtualHost *:80&gt;
    ServerName myhost.com
    ServerAlias www.myhost2.com
    ErrorLog &quot;logs/myhost-error.log&quot;
    CustomLog &quot;logs/myhost-access.log&quot; common
	JkMount /* dotcms
&lt;/VirtualHost&gt;</pre>
<p>The virtualhost mentioned above listens om port 80 for all IP addresses, and matches myhost.com and www.myhost2.com. For those hosts it has its own Apache logs and all the URLs that match /* are sent to the dotcms worker. I have built sites where all traffic is sent to dotCMS except the /service directory, which was sent to a local JBoss. All that is possible. When you have multiple hosts they should all listen on *.80 but have a different ServerName. Note that for SSL you need to set-up another virtualhost with port 443.</p>
<p><strong>mod_jk</strong></p>
<p>Apache needs mod_jk for the connecting. It&#8217;s not more than downloading a module and adding it in the httpd.conf. You can find mod_jk and a quick way to install it <a href="http://tomcat.apache.org/connectors-doc/generic_howto/quick.html" target="_blank">here</a>.</p>
<p><strong>Example: Password protect a folder/site</strong></p>
<p>In Apache you can put a password on a (part of) a website. This is easily configurable and also easy to remove (no actual restart is needed!). This allows you to give a client access to a website without the entire world seeing it. You only need to add a few lines to your virtualhost in Apache, for instance using &#8216;location&#8217; (more info, see <a href="http://httpd.apache.org/docs/2.0/mod/mod_auth.html" target="_blank">here</a>):</p>
<pre class="brush: xml; title: ; notranslate">&lt;location /*&gt;
  AuthType Basic
  AuthName &quot;Please Log In&quot;
  AuthUserFile /password
  require valid-user
&lt;/location&gt;</pre>
<p>The above code adds a password to /* (everything), and the password file is located in /password. To create a password file, see <a href="http://httpd.apache.org/docs/2.0/mod/mod_auth.html#authuserfile" target="_blank">here</a>.</p>
<p><strong>Example: IP filter</strong></p>
<p>An IP filter can give certain IP&#8217;s access to certain sites. This is very useful when you&#8217;re working on a test server or when a site isn&#8217;t live yet but your client wants to see it. It can also be set-up with &#8216;location&#8217;:</p>
<pre class="brush: xml; title: ; notranslate">&lt;location /special&gt;
  Order deny,allow
  Deny  from all
  Allow from 1.2.3.4           #our IP
  Allow from 5.6.7.8           #client IP
&lt;/location&gt;</pre>
<p><strong>Example: Rewrite rules and https</strong></p>
<p>You can use the very powerful rewrite rules of Apache as virtual links, you can force HTTPS on certain files/folders/sites and you can also force HTTP. Furthermore, you only need to set-up SSL in Apache and not in dotCMS which allows you to easily use multiple SSL certificates for multiple sites. You&#8217;ll need to download the <a href="http://httpd.apache.org/docs/current/mod/mod_rewrite.html" target="_blank">mod_rewrite</a> module of Apache to make this work.</p>
<p>The following example may be a bit tough, but if you try this out a bit you&#8217;ll see it&#8217;s quite easy to use. For more info see <a href="http://httpd.apache.org/docs/current/mod/mod_rewrite.html" target="_blank">here</a>.</p>
<pre class="brush: xml; title: ; notranslate">&lt;VirtualHost 1.2.3.4:443&gt;
  ServerName www.myhost.com
  ServerAlias myhost.com

  # Force all url's into non-SSL, except the ones that must be SSL
  RewriteEngine on
  RewriteCond %{HTTPS} =on
  RewriteCond %{REQUEST_URI} !^/protected
  RewriteRule ^(.*)$ http://%{HTTP_HOST}$1 [R,L]

  # Force the use of the www. subdomain
  RewriteCond %{HTTP_HOST} ^myhost\.com
  RewriteRule ^(.*)https://www.myhost.com$1 [R]

  SSLEngine on
  SSLCertificateFile &quot;conf\ssl\mycertificate.crt&quot;
  SSLCertificateKeyFile &quot;conf\ssl\mycertificate.key&quot;
  SSLOptions +StdEnvVars +ExportCertData
  SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
&lt;/virtualhost&gt;</pre>
<p><strong>Example: Useful redirects</strong></p>
<p>When you migrate a website to dotCMS you lose some of the Google indexing since the names of the pages change (probably). In Apache you can define redirects so users get redirected (301) from .html, .jsp or .php to .dot. When you do that correctly Google moves the indexing data to the new URL, so your SEO doesn&#8217;t have to start from scratch.</p>
<pre class="brush: xml; title: ; notranslate">RewriteRule ^/home.aspx$        /home/index.dot [R=301]</pre>
<h3>Conclusion</h3>
<p>There is a downside in using Apache, even though it is not that big of a deal. You need to configure all the hosts of dotCMS in Apache as well (if you want to differentiate between hosts). But if you want to manage many hosts on one server, Apache is THE tool for you. And I always think that since dotCMS is a content management system, it should only worry about the content. Let other programs do what they&#8217;re good at. And the good part is that Apache has many other useful functions that you can use once you have it installed. It brings a lot of extra power and flexibility to using dotCMS.</p>
<p>(This isn&#8217;t all, by far. Don&#8217;t hesitate to post any other useful Apache functions that you use with dotCMS or comments about my examples)</p>
<hr />Photo Credit: <a href="http://creativecommons.org/licenses/by/2.0/deed.en"><img class="colorbox-253"  style="border: none;vertical-align: middle" src="http://l.yimg.com/g/images/cc_icon_attribution_small.gif" border="0" alt="Attribution" /></a> <a title="Attribution License" href="http://creativecommons.org/licenses/by/2.0/">Some rights reserved</a> by <a href="http://www.flickr.com/photos/igb/">igb</a></p>
<hr />
<img src="http://feeds.feedburner.com/~r/LearnDotcms/~4/9HtV8g81wvc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://learndotcms.com/2010/10/apache-and-dotcms-happily-ever-after/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://learndotcms.com/2010/10/apache-and-dotcms-happily-ever-after/</feedburner:origLink></item>
		<item>
		<title>oEmbed and JSON Plugins Available</title>
		<link>http://feedproxy.google.com/~r/LearnDotcms/~3/oZTeZSJ_Abk/</link>
		<comments>http://learndotcms.com/2010/09/oembed-and-json-plugins-available/#comments</comments>
		<pubDate>Tue, 14 Sep 2010 19:03:40 +0000</pubDate>
		<dc:creator>Michael Fienen</dc:creator>
				<category><![CDATA[Macros]]></category>
		<category><![CDATA[Plugins]]></category>
		<category><![CDATA[Viewtools]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[macro]]></category>
		<category><![CDATA[oembed]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[viewtool]]></category>

		<guid isPermaLink="false">http://learndotcms.com/?p=278</guid>
		<description><![CDATA[Today, I am announcing the release of two new plugins for dotCMS, available now. The reason I am announcing them together is because the macro relies on the viewtool, but the viewtool has applications beyond the macro, so I didn&#8217;t feel that it was right to make it one big plugin. Also, the viewtool is [...]]]></description>
			<content:encoded><![CDATA[<p>Today, I am announcing the release of two new plugins for dotCMS, available now. The reason I am announcing them together is because the macro relies on the viewtool, but the viewtool has applications beyond the macro, so I didn&#8217;t feel that it was right to make it one big plugin. Also, the viewtool is only necessary in dotCMS 1.9 or lower. It is built in to dotCMS 1.9.1.</p>
<p>The viewtool is a fairly simple, straightforward implementation of the <a href="http://www.json.org/java/index.html">JSON Java class</a>. Like the XML viewtool, it allows you to request JSON data via a URI, bring it into Velocity, and use it to manipulate information on a page. In the case of these plugins, the oEmbed macro uses it to request the JSON representation of an oEmbed object, and fetch out the values needed to display the content. As noted, this viewtool has been included in the trunk code for the upcoming 1.9.1 dotCMS update, so this plugin is only necessary if you are on 1.7 or the base 1.9 install. The viewtool plugin is mapped to the same key, so if you install it on a 1.7/9 system and then upgrade to 1.9.1, just remove the plugin and nothing should break. Beyond that, you can use it to process any other JSON data sources that you need.</p>
<p style="text-align: center;"><a href="http://learndotcms.com/wp-content/plugins/download-monitor/download.php?id=5"><strong>[ Download JSONTool Viewtool Plugin (v1.100914) ]</strong></a></p>
<pre class="brush: xml; title: ; notranslate">#set($jsonData = $json.fetch('http://oohembed.com/oohembed/?url=http%3A//www.amazon.com/Myths-Innovation-Scott-Berkun/dp/0596527055/'))
&lt;h1&gt;$!{jsonData.get('title')}&lt;/h1&gt;

#set($mymap = $contents.getEmptyMap())
#set($dummy = $mymap.put('one','value 1'))
#set($dummy = $mymap.put('two','value 2'))
#set($dummy = $mymap.put('three','value 3'))
#set($myjson = $json.generate($mymap))
&lt;p&gt;$!{myjson}&lt;/p&gt;
&lt;p&gt;The value of key 'one' is $!{myjson.get('one')}&lt;/p&gt;
-----------------------------------
AND THIS IS THE EXPECTED OUTPUT
The Myths of Innovation

{&quot;two&quot;:&quot;value 2&quot;,&quot;one&quot;:&quot;value 1&quot;,&quot;three&quot;:&quot;value 3&quot;}
The value of key 'one' is value 1</pre>
<p>The second plugin is a macro that allows you to add <a href="http://oembed.com/">oEmbed</a> sources of data to your site, and it requires the JSONTool viewtool, either as a plugin or in 1.9.1, because it uses the <a href="http://www.oohembed.com/">oohEmbed API</a> to set up the embed code which responds with JSON data. Using an oEmbed compatible URI, the <code>#oembed()</code> macro will fetch the applicable code and allow you to embed it on your page. This is great for a simple way of embedding YouTube or Vimeo videos, or images from Flickr, as well as many other services. The oohEmbed website lists all of the sites they currently support.</p>
<p style="text-align: center;"><a href="http://learndotcms.com/wp-content/plugins/download-monitor/download.php?id=6"><strong>[ Download oEmbed Macro Plugin (v1.100914) ]</strong></a> <em>(requires the JSON viewtool!)</em></p>
<p><strong>Macro Syntax:</strong></p>
<pre>#oembed('sourceURI')</pre>
<p><strong>Arguments</strong></p>
<ul>
<li> <em>sourceURI:</em><br />
This is the only require parameter and should represent a well-formed oEmbed compatible URI (see the respective web site for proper URI formatting).</li>
<li> <em>oembedH:</em><br />
Define the height of the oEmbed object (optional, velocity variable). Default: JSON oEmbed height value</li>
<li> <em>oembedW:</em><br />
Define the width of the oEmbed object (optional, velocity variable). Default: JSON oEmbed width value</li>
<li> <em>oembedClass:</em><br />
Provide a specific class name for the embed div wrapper (optional, velocity variable). Default: &#8216;oembedMedia&#8217;</li>
<li> <em>useThumbnail:</em><br />
Boolean value, allows you to display the thumbnail with a link to the resource url. Only works with &#8216;photo&#8217; type oEmbed data (optional, velocity variable). Default: false</li>
</ul>
<p><strong>Example:</strong></p>
<pre class="brush: xml; title: ; notranslate">#oembed('http://www.youtube.com/watch?v=dQw4w9WgXcQ')</pre>
<p><strong>Advanced Example:</strong></p>
<pre class="brush: xml; title: ; notranslate">#set($oembedH     = 267)
#set($oembedW     = 400)
#set($oembedClass = 'oembedFlickrPhoto')
#oembed('http://www.flickr.com/photos/fienen/4965817454')</pre>
<img src="http://feeds.feedburner.com/~r/LearnDotcms/~4/oZTeZSJ_Abk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://learndotcms.com/2010/09/oembed-and-json-plugins-available/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://learndotcms.com/2010/09/oembed-and-json-plugins-available/</feedburner:origLink></item>
		<item>
		<title>Email from Velocity</title>
		<link>http://feedproxy.google.com/~r/LearnDotcms/~3/hd4WEvrZjE0/</link>
		<comments>http://learndotcms.com/2010/09/email-from-velocity/#comments</comments>
		<pubDate>Wed, 01 Sep 2010 20:15:58 +0000</pubDate>
		<dc:creator>Chris Falzone</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Plugins]]></category>
		<category><![CDATA[Viewtools]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[Velocity]]></category>
		<category><![CDATA[viewtools]]></category>

		<guid isPermaLink="false">http://learndotcms.com/?p=266</guid>
		<description><![CDATA[The more applications I build in dotCMS, the more I find myself trying to accomplish them with just Velocity coding. This saves me from having to create a plugin and make sure it is maintained through my systems. However, lately I have needed to write a lot of Form Handling with dotCMS. Not your basic, [...]]]></description>
			<content:encoded><![CDATA[<p>The more applications I build in dotCMS, the more I find myself trying to accomplish them with just Velocity coding.  This saves me from having to create a plugin and make sure it is maintained through my systems.  However, lately I have needed to write a lot of Form Handling with dotCMS.  Not your basic, send an form to an email kind of thing either.  The stuff I have had to work on is more on piping the form entry through some logic and then starting some kind of workflow.  I have been fairly successful writing these forms up and handling them using the <a href="http://www.dotcms.org/documentation/ExecutingASQLQuery">#getSQLResults macro</a>.   The one piece that I have not been able to do with just velocity is send a notification or confirmation email.</p>
<p>The scenario is that we have a form, this form needs to be processed in some manner and then inserted/updated into a database table, and then an email needs sent to a specific person that there is a new or updated entry.  This is a very common scenario.  Currently to do this in dotCMS without Java Coding of some sort would be a challenge, if not impossible.  DotCMS does have some of it&#8217;s own form handlers, but I find that in many cases I need to perform some logic with the data before passing it on.  The new Form Handler in dotCMS 1.9 has a lot of promise, but unless you plan on paying for an Enterprise License, I am going to consider that option out.  That leaves me with building my own custom form handler.</p>
<p>Staying with the idea that I want a purely Velocity Form Handler; I can perform my logic, and use the SQL macro to insert or update my database (Note:  you cannot insert or update to the dotCMS tables, you will need to have your own tables or an external database).  The only thing I cannot do currently is send an email.  Unfortunately the answer is that I have to bring this functionality to Velocity in the form a ViewTool.  It&#8217;s going to take some Java, but my hope is that for anyone else looking to do similar things will be able to deploy my simple plugin and get moving.</p>
<p>The code for sending an email with Java can be found easily enough from Google.  It is a fairly simple matter to take this code and turn it into a usable viewtool.  Here is the plugin in all it&#8217;s glory:</p>
<p style="text-align: center; font-size: 1.25em;"><strong><a href="http://learndotcms.com/wp-content/plugins/download-monitor/download.php?id=4">[ Download the zip here ]</a></strong></p>
<p>To use this plugin simply download the zip file and extract it to your plugins directory.  You will need to edit the conf\plugin.properties file and change your mail stmp server setting.  Stop your dotCMS instance.  Then in a command prompt, in the base directory for your dotCMS install execute the following command:</p>
<p><code>ant clean-plugins build-plugins deploy-plugins</code></p>
<p>Once that is done, you can restart your dotCMS instance and you are ready to send emails from velocity.  Here is a quick code example to show you how.</p>
<pre class="brush: xml; title: ; notranslate">
#set($to   = &quot;cfalzone@edinboro.edu&quot;)
#set($from = &quot;test@edinboro.edu&quot;)
#set($subj = &quot;Testing Mailer&quot;)
#set($body = &quot;This is a test&quot;)
#set($html = &quot;&lt;h1&gt;This is a &lt;em&gt;Test&lt;/em&gt;&lt;/h1&gt;&quot;)

#set($err = $mailer.sendEmail($to, $from, &quot;$subj (TEXT)&quot;, $body, false))
#if($UtilMethods.isSet($err))
  &lt;p&gt; TEXT Error:  $err &lt;/p&gt;
#else
  &lt;p&gt; TEXT sent ok &lt;/p&gt;
#end

#set($err = $mailer.sendEmail($to, $from, &quot;$subj (HTML)&quot;, $html, true))
#if($UtilMethods.isSet($err))
  &lt;p&gt; HTML Error:  $err &lt;/p&gt;
#else
  &lt;p&gt; HTML sent ok &lt;/p&gt;
#end
</pre>
<p>As you can see the simpleMailer plugin will allow you to send either Plain Text or simple HTML messages.  I have not implemented file attachments.  One thing to note is, due to the way dotCMS works, when you hit a page in the editor, it loads it once for Edit Mode, once for Preview Mode, and once for Live Mode.  This means if you put this code in a page you will get the emails 3 times each.</p>
<p>I hope it helps someone out there trying to do the same thing as I am.  I think this is pretty essential tooling for dotCMS, so hopefully I can convince the folks at dotCMS to include this viewtool with the standard set in the future.  There are of course many improvements you could make to this.  You could add the ability to add attachments.  You could add the ability to use a dotCMS page or template as a wrapper for your email.</p>
<hr />Photo Credit: <a href="http://creativecommons.org/licenses/by-nd/2.0/"><img class="colorbox-266"  style="border: none; vertical-align: middle;" title="Attribution" src="http://l.yimg.com/g/images/cc_icon_attribution_small.gif" border="0" alt="Attribution" /><img class="colorbox-266"  style="border: none; vertical-align: middle;" title="No Derivative Works" src="http://l.yimg.com/g/images/cc_icon_noderivs_small.gif" border="0" alt="No Derivative Works" /></a> <a title="Attribution-NoDerivs License" href="http://creativecommons.org/licenses/by-nd/2.0/">Some rights reserved</a> by <a href="http://www.flickr.com/photos/soapbeard/">soapbeard</a></p>
<hr />
<img src="http://feeds.feedburner.com/~r/LearnDotcms/~4/hd4WEvrZjE0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://learndotcms.com/2010/09/email-from-velocity/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://learndotcms.com/2010/09/email-from-velocity/</feedburner:origLink></item>
		<item>
		<title>Guide to Images</title>
		<link>http://feedproxy.google.com/~r/LearnDotcms/~3/2PleMf-0kXk/</link>
		<comments>http://learndotcms.com/2010/07/guide-to-images/#comments</comments>
		<pubDate>Thu, 22 Jul 2010 21:24:21 +0000</pubDate>
		<dc:creator>Michael Fienen</dc:creator>
				<category><![CDATA[Front End]]></category>
		<category><![CDATA[Velocity]]></category>
		<category><![CDATA[images]]></category>
		<category><![CDATA[randomImage()]]></category>
		<category><![CDATA[resize_image]]></category>

		<guid isPermaLink="false">http://learndotcms.com/?p=226</guid>
		<description><![CDATA[Images are highly important to web content. There are numerous ways in which one can incorporate them into a page to enhance what is there. In dotCMS, you are presented with several ways in which you can implement and manipulate image files in your system. Today, we&#8217;ll be reviewing several of them. First off, one [...]]]></description>
			<content:encoded><![CDATA[<p>Images are highly important to web content. There are numerous ways in which one can incorporate them into a page to enhance what is there. In dotCMS, you are presented with several ways in which you can implement and manipulate image files in your system. Today, we&#8217;ll be reviewing several of them.</p>
<p>First off, one of the most common ways that you will work with images is right in a structure. Structures support image specific upload fields that you can then access from the content map on a page or in a widget to display them. However, many newcomers quickly learn that it&#8217;s not as simple as just echoing out <code>$content.image</code> onto a page, since that only returns an identifier for the image. When an image is uploaded via a field in a structure, a number of fields are actually created and added to the contentlet, all of which you can access and use. Those fields are:</p>
<ul>
<li>ImageExtension</li>
<li>ImageFriendlyName</li>
<li>ImageIdentifier</li>
<li>ImageInode</li>
<li>ImageName</li>
<li>ImagePath</li>
<li>ImageTitle</li>
<li>ImageURI</li>
<li>ImageHeight</li>
<li>ImageWidth</li>
</ul>
<p>So in a page, assuming you have a structure with an image upload field simply named &#8220;image&#8221; an example of some of these fields in use would look like:</p>
<pre class="brush: xml; title: ; notranslate">## MAKE SURE AN IMAGE IS ACTUALLY SET
#if($UtilMethods.isSet($content.image) &amp;&amp; $content.image != '0')
&lt;img src=&quot;$!{content.imageImageURI}&quot; alt=&quot;$!{content.imageImageTitle}&quot; height=&quot;$!{content.imageImageHeight}&quot; width=&quot;$!{content.imageImageWidth}&quot; /&gt;
#end</pre>
<p>Alternatively, it&#8217;s possible to use dotCMS&#8217;s <code>/dotAsset</code> servlet functionality to get the same result using other fields:</p>
<pre class="brush: xml; title: ; notranslate">## MAKE SURE AN IMAGE IS ACTUALLY SET
#if($UtilMethods.isSet($content.image) &amp;&amp; $content.image != '0')
&lt;img src=&quot;/dotAsset/$!{content.imageImageIdentifier}.$!{content.imageImageExtension}&quot; alt=&quot;$!{content.imageImageTitle}&quot; height=&quot;$!{content.imageImageHeight}&quot; width=&quot;$!{content.imageImageWidth}&quot; /&gt;
#end</pre>
<p>Either example returns the same end result in the browser, all that changes is the path to the image. That&#8217;s all there is to basic image embedding. But, we&#8217;re not nearly done. Let&#8217;s say you have users who sometimes upload pictures that are way too big for a space, so you need to scale them down. That is where the <a href="http://www.dotcms.org/documentation/DisplayResizedImages"><code>/resize_image</code> servlet</a> comes in handy, which can create scaled versions of images on the fly for you.</p>
<p><strong>Example of conditional <code>/resize_image</code></strong></p>
<pre class="brush: xml; title: ; notranslate">#if($UtilMethods.isSet($content.image) &amp;&amp; $content.image != '0')
    ## SEE IF THE IMAGE IS OVER 250 PIXELS WIDE
    #if($content.imageImageWidth &gt; 250)
&lt;img src=&quot;/resize_image?id=$!{content.imageImageIdentifier}&amp;w=250&quot; alt=&quot;$!{content.imageImageTitle}&quot; /&gt;
    #else
&lt;img src=&quot;$!{content.imageImageURI}&quot; alt=&quot;$!{content.imageImageTitle}&quot; height=&quot;$!{content.imageImageHeight}&quot; width=&quot;$!{content.imageImageWidth}&quot; /&gt;
    #end
#end</pre>
<p>Using that example, we can restrict our code to a specific width, and if it&#8217;s over it, force it down to the maximum allowable size. But wait, there&#8217;s more! You can play values against each other:</p>
<pre class="brush: xml; title: ; notranslate">#if($UtilMethods.isSet($content.image) &amp;&amp; $content.image != '0')
    ## SEE IF THE IMAGE IS OVER 250 PIXELS WIDE
    #if($content.imageImageWidth &gt; 250)
        ## CHECK IF IT IS PORTRAIT OR LANDSCAPE
        #if($content.imageImageHeight &gt; $content.imageImageWidth)
&lt;img src=&quot;/resize_image?id=$!{content.imageImageIdentifier}&amp;maxw=250&amp;maxh=400&quot; alt=&quot;$!{content.imageImageTitle}&quot; /&gt;
        #else
&lt;img src=&quot;/resize_image?id=$!{content.imageImageIdentifier}&amp;w=250&quot; alt=&quot;$!{content.imageImageTitle}&quot; /&gt;
        #end
    #else
&lt;img src=&quot;$!{content.imageImageURI}&quot; alt=&quot;$!{content.imageImageTitle}&quot; height=&quot;$!{content.imageImageHeight}&quot; width=&quot;$!{content.imageImageWidth}&quot; /&gt;
    #end
#end</pre>
<div id="attachment_243" class="wp-caption alignright" style="width: 310px"><a href="http://learndotcms.com/wp-content/uploads/2010/07/resized.png"><img class="size-medium wp-image-243 colorbox-226" title="resized" src="http://learndotcms.com/wp-content/uploads/2010/07/resized-300x239.png" alt="Image resized based on width" width="300" height="239" /></a><p class="wp-caption-text">Depending on landscape or portrait, this image&#39;s size will change</p></div>
<p>Note that this time I see if the height is more than the width, if it is, I use the <code>maxw</code> and <code>maxh</code> values (If you use one of the max parameters, you <em>must</em> use them both, unlike <code>h</code> and <code>w</code>, which can be used individually). This kind of code can help prevent image blowouts if you are unable to predict whether a portrait or landscape image is going to be used, so that after scaling one side down, the other side can be kept within additional length constraints.</p>
<p>Now that you can use images from structures and do some manipulation with them, let&#8217;s look at a few other image tools in dotCMS. There are a couple servlets and macros that are designed to give you a means of putting images on pages and doing things with them. <code>/resize_image</code> you are already familiar with from the previous example. Another servlet is the <code>/thumbnail</code> servlet, which is very similar to <code>/resize_image</code> and is used as an <code>&lt;img src&gt;</code> exactly the same, except that it also is capable of producing a background fill around images by including the parameters <code>r</code>, <code>g</code>, and <code>b</code> to represent the RGB values you want to use for the border (each one from 0 to 255). Some macros to take note of are: <code>photoCarrousel()</code>, <code>titleImage()</code>, <code>slideshow()</code>, <code>photoGallery()</code>, and <code>randomImage()</code>. Usage of the macros is more extensively covered in the <a href="http://www.dotcms.org/documentation/dotCMSMacros">dotCMS documentation</a>, which will give you more information on customization variables.</p>
<div id="attachment_246" class="wp-caption alignright" style="width: 310px"><a href="http://learndotcms.com/wp-content/uploads/2010/07/thumbnail.png"><img class="size-medium wp-image-246 colorbox-226" title="thumbnail" src="http://learndotcms.com/wp-content/uploads/2010/07/thumbnail-300x232.png" alt="A 250x250 thumbnail with a blue RGB value" width="300" height="232" /></a><p class="wp-caption-text">A 250x250 thumbnail with a blue RGB value</p></div>
<p>The <code>/thumbnail</code> servlet has a fairly simple purpose: It scales an image down to fit inside the parameters you give it, and fills any remaining space around the image with the background color you set. For example, if you have an image that is 640&#215;480, you can set the height and width 320&#215;320. The resulting image will scale the longest side down to 320 (in this case the width), and the resulting space above and below the image would be filled in 40px above and below it (320 = (480/2) + (40*2)). The difference here between <code>/thumbnail</code> and <code>/resize_image</code> is that if you told <code>/resize_image</code> to have a height and width of 320, the image would get stretched and pulled out of proportion while /thumbnail will always scale the longest side to fit inside the proportions and fill the leftover.</p>
<p><strong>Thumbnail Example:</strong></p>
<pre class="brush: xml; title: ; notranslate">&lt;img src=&quot;/thumbnail?id=61560&amp;r=34&amp;g=126&amp;b=203&amp;h=250&amp;w=250&quot; alt=&quot;Image Thumbnail Using identifier&quot; /&gt;
...or...
&lt;img src=&quot;/thumbnail?path=/test/images/PICT1208.jpg&amp;r=34&amp;g=126&amp;b=203&amp;h=250&amp;w=250&quot; alt=&quot;Image Thumbnail Using path&quot; /&gt;</pre>
<p>Let&#8217;s try a somewhat more advanced example of image manipulation. Let&#8217;s say that you have a structure for products that includes a header image field. What you would like to do is put a widget on the page to display the product; it should show the specific header if one has been provided, and if one hasn&#8217;t, then show one at random from a group of generic banners you have already designed.</p>
<p><strong>Set up a header image based on conditionally supplied image with fallback:</strong></p>
<pre class="brush: xml; title: ; notranslate">&lt;div id=&quot;header&quot;&gt;
#if($UtilMethods.isSet($content.headerImage) &amp;&amp; $content.headerImage != '0')
    ## SEE IF THE HEADER WIDTH IS WHAT IT SHOULD BE, RESIZE IF NOT
    #if($content.headerImageImageWidth != 640)
    &lt;img src=&quot;/resize_image?id=$!{content.headerImageImageIdentifier}&amp;w=640&quot; alt=&quot;Buy $!{content.productName} from Company X&quot; /&gt;
    #else
    &lt;img src=&quot;$!{content.headerImageImageURI}&quot; alt=&quot;Buy $!{content.productName} from Company X&quot; /&gt;
    #end
## IF AN IMAGE ISN'T SET, USE A MACRO TO GET ONE AT RANDOM FROM A FOLDER
#else
    ## GETS A RANDOM IMAGE AND RETURNS IT AS $image
    #randomImage('/global/images/generic-product-headers')
    &lt;img src=&quot;/dotAsset/$!{image.identifier}.png&quot; alt=&quot;Buy Company X Products&quot; /&gt;
#end
&lt;/div&gt;  &lt;!-- #header --&gt;</pre>
<div id="attachment_242" class="wp-caption alignright" style="width: 310px"><a href="http://learndotcms.com/wp-content/uploads/2010/07/scaleAndCrop.png"><img class="size-medium wp-image-242 colorbox-226" title="scaleAndCrop" src="http://learndotcms.com/wp-content/uploads/2010/07/scaleAndCrop-300x269.png" alt="Example of an image resized down and then cropped with a div" width="300" height="269" /></a><p class="wp-caption-text">Example of an image resized down and then cropped with a div</p></div>
<p>I have one last trick that I want to share that&#8217;s part Velocity and part CSS. One thing that the <code>/resize_image</code> servlet can&#8217;t do is crop images, which is pretty handy when you need to fill a space that is a set size, and you can&#8217;t predict the height and width of an image. For instance, making a rectangular image fit a square, or vice versa, without it looking squished or stretched. There are some <a href="http://joanpiedra.com/jquery/thumbs/">jQuery tools</a> for this, but they have to use the original file, which if it is very large, can be inconvenient for download speeds. This method shrinks the image to the shortest side, and centers it using a <code>&lt;div&gt;</code> as a container.</p>
<p><strong>Scale and crop image using Velocity and CSS:</strong></p>
<pre class="brush: xml; title: ; notranslate">## MAKE SURE AN IMAGE IS THERE
#if($UtilMethods.isSet($content.imageImageURI))
    ## SEE IF IT'S TALLER OR WIDER AND SET THE APPROPRIATE SIDE MAX LENGTH
    #if($content.imageImageHeight &gt; $content.imageImageWidth)
        #set($imageSize = &quot;w=250&quot;)
    #else
        #set($imageSize = &quot;h=250&quot;)
    #end
&lt;style type=&quot;text/css&quot;&gt;
.scaleAndCenter {
    background-color:transparent;
    background-position:center;
    background-repeat:no-repeat;
    height:250px;
    width:250px;
}
&lt;/style&gt;
&lt;div class=&quot;scaleAndCenter&quot; style=&quot;background-image:url(/resize_image?$!{imageSize}&amp;id=${issue.imageImageIdentifier});&quot;&gt;&lt;/div&gt;
#end</pre>
<p>So that&#8217;s that, a look at getting images out of content and folders and into pages and widgets. Feel free to share any other tricks you&#8217;ve learned in the comments.</p>
<h3>Comparing /resize_image in 1.7 vs. 1.9</h3>
<div id="attachment_249" class="wp-caption alignright" style="width: 310px"><a href="http://learndotcms.com/wp-content/uploads/2010/07/resize-compare.png"><img class="size-medium wp-image-249 colorbox-226" title="resize-compare" src="http://learndotcms.com/wp-content/uploads/2010/07/resize-compare-300x127.png" alt="Both images resized from the same 606kB, 1024x768 pixel original file" width="300" height="127" /></a><p class="wp-caption-text">Both images resized from the same 606kB, 1024x768 pixel original file</p></div>
<p>There have been some questions recently regarding the quality of of images produced by the <code>/resize_image</code> servlet in 1.7, and if it has been improved in 1.9.  There have indeed <a href="http://jira.dotmarketing.net/browse/DOTCMS-3572">been changes in 1.9</a>. However, my understanding is that while the logic wrapping the servlet has been modified, the core library codec (sun.awt.image.codec.JPEGImageEncoderImpl) has not. So, what does this mean? Well, if you look at the comparison to the right, very little. Actually, it would seem the image quality has actually gone DOWN in 1.9, with more JPG artifacts being introduced than previously. However, this is offset by the fact that the image size has been substantially reduced. So it&#8217;s half of one, six of a dozen of another. There is now a config property in the 1.9 <code>dotmarketing-config.properties</code> file that sets <code>DEFAULT_KEY_ANTIALIASING=java.awt.RenderingHints.VALUE_ANTIALIAS_ON</code>, but looking at the final results, it doesn&#8217;t seem to be having an effect on smoothing the lines out or preventing hard, pixelated edges for the most part (though to be fair, the darkest, top part of the stem of the central flower does look slightly better in 1.9, that&#8217;s still offset by the fact that the highlights are clearly jaggy).</p>
<h3>Image Gallery Recap</h3>

<a href='http://learndotcms.com/2010/07/guide-to-images/3729849415_ff953145c6_z/' title='3729849415_ff953145c6_z'><img width="150" height="150" src="http://learndotcms.com/wp-content/uploads/2010/07/3729849415_ff953145c6_z-150x150.jpg" class="attachment-thumbnail colorbox-226" alt="3729849415_ff953145c6_z" title="3729849415_ff953145c6_z" /></a>
<a href='http://learndotcms.com/2010/07/guide-to-images/scaleandcrop/' title='scaleAndCrop'><img width="150" height="150" src="http://learndotcms.com/wp-content/uploads/2010/07/scaleAndCrop-150x150.png" class="attachment-thumbnail colorbox-226" alt="Example of an image resized down and then cropped with a div" title="scaleAndCrop" /></a>
<a href='http://learndotcms.com/2010/07/guide-to-images/resized/' title='resized'><img width="150" height="150" src="http://learndotcms.com/wp-content/uploads/2010/07/resized-150x150.png" class="attachment-thumbnail colorbox-226" alt="Image resized based on width" title="resized" /></a>
<a href='http://learndotcms.com/2010/07/guide-to-images/thumbnail/' title='thumbnail'><img width="150" height="150" src="http://learndotcms.com/wp-content/uploads/2010/07/thumbnail-150x150.png" class="attachment-thumbnail colorbox-226" alt="A 250x250 thumbnail with a blue RGB value" title="thumbnail" /></a>
<a href='http://learndotcms.com/2010/07/guide-to-images/resize-compare/' title='resize-compare'><img width="150" height="150" src="http://learndotcms.com/wp-content/uploads/2010/07/resize-compare-150x150.png" class="attachment-thumbnail colorbox-226" alt="Both images resized from the same 606kB, 1024x768 pixel original file" title="resize-compare" /></a>

<hr />Photo credit: <a href="http://creativecommons.org/licenses/by/2.0/deed.en"><img class="colorbox-226"  style="vertical-align: middle; border: none;" title="Attribution" src="http://l.yimg.com/g/images/cc_icon_attribution_small.gif" border="0" alt="Attribution" /></a> <a title="Attribution License" href="http://creativecommons.org/licenses/by/2.0/">Some rights reserved</a> by <a href="http://www.flickr.com/photos/djackmanson/">David Jackmanson</a></p>
<hr />
<img src="http://feeds.feedburner.com/~r/LearnDotcms/~4/2PleMf-0kXk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://learndotcms.com/2010/07/guide-to-images/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		<feedburner:origLink>http://learndotcms.com/2010/07/guide-to-images/</feedburner:origLink></item>
	</channel>
</rss>

