tag:blogger.com,1999:blog-192511932024-03-07T20:30:51.668-06:00Deran Schilling, LearnerDeran Schillinghttp://www.blogger.com/profile/06750574925211298370noreply@blogger.comBlogger99110tag:blogger.com,1999:blog-19251193.post-79810532781867126362016-03-11T14:04:00.000-06:002016-03-11T14:04:34.959-06:00Making Code Maintainable<p>One of the things I’ve learned over the years is to recognize when some code should be changed to be more maintainable. I’ll walk you through some code I saw during a pull request that we ended up refactoring to be more maintainable.</p> <p>We were calling an external API that returns string “yes” and “no” for a bool value sometimes, and other times it sends a “true” and “false”. Obviously we wanted to accept both and convert them appropriately. The first version to accept these values was to have a property that checked the values of itself to let us know if it was true or false, it looked like this:</p> <script src="https://gist.github.com/derans/db0567580d5db7664fc9.js"></script> <p>When we were mapping to our model, we were simply doing this:</p> <script src="https://gist.github.com/derans/882738eaea7716e3bcfa.js"></script> <p>When reviewing, we recognized two main issues. The first issue is that our values are duplicated, so if the API started sending us 1 and 0, then we might go update one area and forget to correct the other section. We could write some tests to let us know, but we didn't want to risk it, and of course there's a better way. There's always a better way. The other issue was that if one of the other fields that was sent to us was a "yes", but not actually a bool, then we'd be in trouble.</p> <p>So, how did we solve the two issues? This is how:</p> <script src="https://gist.github.com/derans/d851ed00b278ffc6ed5b.js"></script> <p>With the fix, you'll notice that we're checking our destination model type now instead of the field's IsABooleanProperty. This fixes our second issue of getting an invalid bool. Our first problem is fixed by having the valid bool values a single time in a convert to bool method, and getting rid of the IsABooleanProperty. If you have other approaches to how to solve this problem or more examples of making code maintainable, please comment!</p>Deran Schillinghttp://www.blogger.com/profile/06750574925211298370noreply@blogger.com0tag:blogger.com,1999:blog-19251193.post-53878026289182083922016-03-09T20:16:00.001-06:002016-03-09T20:16:21.391-06:00Good Ole Refactoring<p>I was talking with some co-workers about a pull request recently and we all decided we didn’t really like the look of some code.</p>
<p>Here's the code:</p> <script src="https://gist.github.com/derans/70fc81e6d613a5665066.js"></script>
<p>Our main issue with the code was that it was difficult to read and immediately understand what was going on.</p> <p>Here are the things you should know:</p> <ul> <li>The SystemClock is a <a href="https://github.com/HeadspringLabs/HeadspringTime">Headspring nuget package</a> </li> <li>IsDayOnWeekend just checks if the current day is a Saturday or Sunday </li> <li>IsHoliday checks whether or not the day falls on a holiday </li> </ul> <p>So we did a small refactoring to make the code more readable.</p> <script src="https://gist.github.com/derans/d674de6c3e502292c2f3.js"></script> <ul> <li>So we renamed the method to include GetPreviousBusinessDay </li> <li>We get the last 365 days, we could've just as easily gotten the last 30, but decided to just get the full year. </li> <li>After we get the last 365 days, we get only the valid business days </li> <li>Then we order those dates descendingly, skip the number of days back we want to go, and then grab the first date </li> </ul> <p>Our refactoring is more readable, has some "clever" code that we like, but aren't married to either. I'm curious to know other opinions, and other solutions that we could've used. </p>Deran Schillinghttp://www.blogger.com/profile/06750574925211298370noreply@blogger.com0tag:blogger.com,1999:blog-19251193.post-10382704499870047922013-01-07T22:44:00.000-06:002015-06-01T09:34:21.149-05:00What to do when you are locked out of SQL Server<div style="float: right;">
<a class="twitter-share-button" href="https://twitter.com/share">Tweet</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script></div>
I was recently helping out a fellow Headspringer when we realized we were locked out of his local SQL Express installation. We just needed to start SQL Server in single-user mode, give rights to whatever users we want, and then start back in normal mode. Here’s what we did:<br />
<ol>
<li>Launch SQL Server Configuration Manager (Run -> SQLServerManager11.msc) <br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnfiqrzW-ePBBGRdZ0QQg46e_vKXHHh4nMTDBmK8gPMVttw9NmcOKBXGqSOdFt156n1qwY3cht4LirG1-fdQT5RwLbVwWbjmICHtZh6ADdxcpmNvAmUeFayRj-wKPXMwoSfi0-aw/s1600-h/CropperCapture%25255B2%25255D%25255B3%25255D.jpg"><img alt="CropperCapture[2]" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgzXuFjZu5LrUVs6TWmMFp628kKA_zp2lduVUYo_rp7gjiejH5rj5m31tCo0e5ixlmYFwHwjPWqPek1r8cHzJiymwxTf6P2X6ormbeJ3mK08E5Ql-ZQDxqu4xTgmkUfxoNVsqtnQ//?imgmax=800" height="203" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="CropperCapture[2]" width="750" /></a> <br /> </li>
<li>Stop SQL Server (SQLEXPRESS) instance <br />(To stop: right-click stop or click then click the stop icon) <br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh380d9_32nHmRvpcLbgP1vrirQ-Xv_ExJ2kPDldagilpIQVi4eS4f7UzKfT8pKbf2AtncBdPRbuuCqn-oeodIKYUtNE05F6V5ELEvNwTpM5d8qi8_PaTDo-FCOtK0Yc8-yO_8ymQ/s1600-h/CropperCapture%25255B3%25255D%25255B4%25255D.jpg"><img alt="CropperCapture[3]" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpKmPVTwuz_gTSy44wOshy7snnJLHz2KxO7W0Ey46XUcfD0tnakiDc1K46FIUYZhBm6T5IQv1SjOMNwvH-_eTuLYLsU-_iGd3KzT5xfmCKdmRZEDmGDIrDRVx1kE9X1fL1E66-Tw//?imgmax=800" height="207" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="CropperCapture[3]" width="748" /></a> <br /></li>
<li>Go to the properties of SQL Server <br />(To get to properties: right-click click properties or click then press alt+enter) <br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEig29Hx3THiv5LKKgbnjTW057mPzjxH0SJUBayZw2Jt6PAvpz4ROJjlIFk7rWY5fawyl0FgRfRGvCOdLrj9Uo8POejlXdHaZtoZjrk9C8bXX30EKJ0G78M24v6yuqPtAzNlAaJpyg/s1600-h/CropperCapture%25255B4%25255D%25255B4%25255D.jpg"><img alt="CropperCapture[4]" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgT1fU1BzrHBGxE1CC39udEWid9MLa7-fpZmowg3X-6Q7AXzkTRP4gU-3qyp3Sinl9Ym_zUZ-XSRocNwrwyfI3old5hK7vDPU0eUFTOdw3HpsKBZzlyPGwq83ogeTQFvmuISa2c_Q//?imgmax=800" height="450" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="CropperCapture[4]" width="372" /></a> <br /></li>
<li><b>SQL Server 2012</b> <br />Click “Startup Parameters” tab and enter “–m” then press Add, Apply, and close the window <br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiA9MmD3r2mlBpYGVE0Kn24X0Nl9WQgk3dU83qIJ3f1rqD8FARlWMso86zbTocsIb73Ztw2D5-DhglT51M-dduP1aN6m_Ki-4LLcLeqObY_zDxwMqD1D4ulW0RdilU7ZsNa7me4Tw/s1600-h/CropperCapture%25255B5%25255D%25255B4%25255D.jpg"><img alt="CropperCapture[5]" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXGaq3KQGTrIh40HyGNn64V9iHHYyUEyyRtdFv5p3qkTWcAMVB8C3zk6MUH7094Dc7pOYIGOe6VH7c_v3FDovJPTdpvZ3L6OMgm1gznVMVdQQ9SyxjZH1OlqSvsH2mAx6Ov_H6lA//?imgmax=800" height="453" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="CropperCapture[5]" width="374" /></a> <br /> <br /><b>SQL Server 2008/2005 </b>Unfortunately I don’t have a screenshot of the 2008 or 2005 properties window, but I believe the startup parameters is under the advanced tab and <b>make sure to add separate the parameters by ; </b>(this bit me the first time around) <br /></li>
<li>Start the SQL Server (SQLEXPRESS) service <br />(To start: right-click and click Start or click then click the start icon) <br /></li>
<li>Run SQL Server Management Studio <br />(To start: win+r and type ssms press enter) <br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimnoJFTMBEMI5lYhiC9hb-dE0dKaD76bNpYzk7tXflqGFhepA5sIQlspIo3Wv-p1K_O0Ks-bt7HPhm_SEP4eTcqtW6wjcuBljIXgWVOHbBW6emxGQwkr6CRpVlEo8NRR30rdcocg/s1600-h/CropperCapture%25255B6%25255D%25255B3%25255D.jpg"><img alt="CropperCapture[6]" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwdYEHVjiGilVvegeC9tIoZsQbnnkuaSoTM1iseg-hPUrz6kT7QDwhWI_yrcZgTS8lnXETwE_rJcAHuoEvRNZVIJMo8WXE7vjdIicauXLw0U6CowN4qy0KaNn3gX9VekU9XVW-RQ//?imgmax=800" height="206" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="CropperCapture[6]" width="388" /></a> <br /></li>
<li>Connect and add the BUILTIN\Administrators or whatever users you prefer to add <br /> </li>
<li>Remove the –m startup parameter</li>
<ol>
<li>Stop SQL Server</li>
<li>Open Properties</li>
<li>Remove Startup Parameter</li>
<li>Start SQL Server</li>
<li>Good to go</li>
</ol>
</ol>
<a href="http://msdn.microsoft.com/en-us/library/dd207004.aspx" target="_blank">View more at microsoft.com</a>Deran Schillinghttp://www.blogger.com/profile/06750574925211298370noreply@blogger.com16tag:blogger.com,1999:blog-19251193.post-83593724481445793852012-10-12T17:35:00.000-05:002012-10-12T17:35:16.728-05:00Building a Feature Branch Configuration Template in TeamCity<div style="float: right"><a href="https://twitter.com/share" class="twitter-share-button">Tweet</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script></div><p>I don’t know about you, but sometimes we have frequent feature branches on our projects. Sometimes we don’t go through the trouble of setting up a build configuration in TeamCity if it’s a quick feature, but sometimes we like to see the pretty green checkbox in TeamCity when our build finishes successfully…especially when more than one person is working on the feature. We also like to deploy straight to our testing environments from a feature branch occasionally for testing, so it’s important for adding a build configuration quickly and accurately in TeamCity. I thought I’d give a demonstration on how to create one.</p> <p>There are two ways to make a template. From scratch and from an existing build configuration. I will not talk about the “Extract Template” option because it’s literally clicking a button and giving a name from within the “Edit Build Configuration” screen. However, there are two things you’ll need to look at in order to use the extracted template as a feature branch template. So look at steps 2 and 4 below for the details if you have an existing build to use as a template. </p> <p><strong>Step 1:</strong> Click “Create template” under “Edit Project Settings” (I’m using version 7.0.4 of TeamCity btw)</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidZy0ob1KWpS68j3b36n81arEaZ5iTP3ps-xN1uKhVMXuYNKrcBAJCmYojWy0ndN3lXKOT-Ht2cqeAOk_tLFG-oFaZuxaNZvrPmT6RkOpBHIG6WMX_Qzf1D9uDDpkqOFLNg376dQ/s1600-h/CropperCapture%25255B1%25255D%25255B2%25255D.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="CropperCapture[1]" border="0" alt="CropperCapture[1]" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-GmRIfCHQ2FlksTWa4HHIIgEoNFM-Cm8LAIfCMw2cj5wiBSayzhYBXBgGGECUwb63dOFqvZfbNMVpMZf83fd-O6ZPcG-vU5MOJCNJ7-TMpZKbNGREuiK2VSmb-PZSAzuhSCqG5Q//?imgmax=800" width="244" height="76" /></a></p> <p><strong>Step 2:</strong> Fill in the name…I called mine Feature Branch Template (original I know). If you have a different build number per feature branch, which we do on this project, you can put %BuildNumber%.{0}.0 for the “Build number format”, otherwise, just leave it as the default (like below). Specify your “Artifact paths”, ours usually looks something like “build\latest\*.zip”. Click “VCS settings”.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjB62N5CU6EIMlbQk3EsNYHxQfitCllTcjfR0mk2HgyErQaqLrfCtAj0ZHQgbr04FPj5yR_9hWJdSgrPVOboctaQ3sz4LPx-iOENr9db5TvN4-f3rqcFv1HtbCSlDjgN2UhVuZGgQ/s1600-h/CropperCapture%25255B3%25255D%25255B3%25255D.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="CropperCapture[3]" border="0" alt="CropperCapture[3]" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtDUIRWYc5wnAZggnlegAB6ghKgNg04KDOhPv3O-fvP-IM6iwlwqq1ywoEIVsEp_KYf7HW0VOWFojy-mQ4Okh0sggxY1Y0VHW2Bb6lBgGNG0d9uwoe-mqO7d6M0aYaPoRnga2G0g//?imgmax=800" width="846" height="411" /></a></p> <p><strong>Step 3:</strong> Here’s where the fun comes in…click “Create and attach new VCS root”.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhogbXoElGFU6w_0hi00dN82hDCBWEatfSa2v-LNRNMTpSx8MS6YEuFx1e2VKwGdwLgpcJ6jWMdoTXXg-rSYCKXJdchdbgtvuBtX1DKiyq7wbuLMowfFA-BsK0iIIjD3aqYJzwI7A/s1600-h/CropperCapture%25255B5%25255D%25255B3%25255D.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="CropperCapture[5]" border="0" alt="CropperCapture[5]" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOCm0qMTebdavBCVpvPvZGwcIxFz8InuteymMoP66lMA5FrsRBnjtuXxpMt9-dh7C6pdNbSkL7qnGutuf9mSRGjQsUnCIXOa85wXRVqLUSiuOkdMskrKVxDIwYQDywBvZU_PLn6Q//?imgmax=800" width="348" height="104" /></a></p> <p>Here you will select your VCS and fill in the appropriate information. The only VERY important thing you need to do is input “%BranchName%” into the Branch name. What this does is creates a parameter that will be required by your build configurations that use this template. Obviously we are using Mercurial, but you would just do the same as above for the equivalent of a branch in your source control.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWZzIT0tDOyY0V5livZ_4yfpTc84VoGYb5YYKMumxujaLkrsf0HnHXTM8dF2YeJs2NFD9xq7abxsiyGkHq5U_WGlAlQSBt3uVr0k-YEwOfpgrYb6a8eg6Ke50dJvFfYezo91WJXg/s1600-h/CropperCapture%25255B6%25255D%25255B3%25255D.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="CropperCapture[6]" border="0" alt="CropperCapture[6]" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-iUkt3YrhKli6wPcQvTBpUfhddC6FR4jL69XddKeljpjAT9ithV7kyDzQD6O2r5hGagF_kuCgI8Y1dWMm0k4FZJKhi-6BQfQqyE-fbm6G5DEO1ydJ4d1IeJrcWw0ihG4eTA4SSA//?imgmax=800" width="431" height="57" /></a></p> <p>When you’ve completed filling out the required information and tested the connection, Save. (Pro Tip: Don’t put %BranchName% in that field until after you’ve done “Test connection” with a real branch name.)</p> <p>You should see this after saving:</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkbG2xFqvW8qsM-mC-tsLohKGkqgiQqFkHHXcN8s-nrzHL543JkpeiDCjgUoA3tuMCBDkPSKni1nlqOWSmUbySLFZxGQQKcLcl69B_W-fDxknk5N5QA4NIGIrWZFsnLEz3QShvkA/s1600-h/CropperCapture%25255B7%25255D%25255B3%25255D.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="CropperCapture[7]" border="0" alt="CropperCapture[7]" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwuSwdCXjaS1L_kl7Sj_IgFb-PUC-BnpEJYFXYATLcUy0caiY1saJBPok_oRiZq8n_u6zwLgZJW_Y7_O1qxFTYDQD9HdxLGkiSR_jj98nB-WG2UHstUg8dzepZt89QoCMBzjFFTA//?imgmax=800" width="770" height="138" /></a></p> <p><strong>Step 4:</strong> I’ll just leave all the defaults on the “Version Control Settings” screen, but if you require any of those settings, please set them if they apply to all your feature branches. Click “Add Build Step”.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLIYPeqfhnL9bxp-fXTCCbfdjfOsU05MpAwMlLe4nP51oIO4k1hnDZ3l1pp_UsxS5xS24w6U9OAmGNfLuhTTS0fYkZsPGLqa5pEKR5MQM5F-syRw9krxKuW1kmJ4D4OnxBsOlrQQ/s1600-h/CropperCapture%25255B8%25255D%25255B3%25255D.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="CropperCapture[8]" border="0" alt="CropperCapture[8]" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQwLKPue33eC4mNLH7doE0R3n1OHLTU0MsnEAxQ3NeoKwofrRIhAMsgvAqcR9ys1K5btSemqQW4L7-mgXKemIPLLTnj8Um66kRdxdpqE_6a2qI0ASM_9aWhT8WWf4qAUewvtStjw//?imgmax=800" width="415" height="86" /></a></p> <p><strong>Step 5:</strong> Configure your build steps. We only have two steps because we use <a href="https://github.com/psake/psake">psake</a>…so basically we call the build.bat in our repo root with specific params and the other step just runs our unit tests with coverage.</p> <p><strong>Step 6 (optional):</strong> Configure fail conditions if needed…the most common condition I’ve seen is looking for specific text in the build log.</p> <p><strong>Step 7:</strong> Configure Build Triggering…we use the VCS Trigger, which detects when code is checked in. After clicking “Add new trigger”, you should see this:</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxJS4wpivTsd5MrM7r48rRvqHgy2j6XwwG3HcrAvfc75Y-VUXGzKTT74Asg-SiC0-qt_q0WVYJYhq8yp9EQlyTuJKLOM8Bmvga8Qezfb3yVm7eVc-vWW27-q_aNRi9PeWNF4kF1A/s1600-h/CropperCapture%25255B9%25255D%25255B4%25255D.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="CropperCapture[9]" border="0" alt="CropperCapture[9]" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjB5V6tqW89_TBKzjeysfvWAn9CW195DH_xi0wre7cOUfGq6CZnlDcp4KQdppHVV_ru09WlAP9QoakP0GTdoBji269vl9pCjzIK5-ssEhvR7XdquPoVVpaW1ta_NZOcewonJ66CDA//?imgmax=800" width="443" height="498" /></a></p> <p>I just use the default values. Click Save.</p> <p><strong>Step 8: </strong>Click Build Parameters – You should see BranchName <value is required> and BuildNumber if you specified that one in step 1.</p> <p>If no BuildNumber specified:</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZcPdmaDOxzAtYDlxXbkJWD7ri5PbIV4L5svETLdi6lXoQjD3eLFYpvH58WmdMu2WusjijbUBcCPiDMeR6Nb0O-7_AazAzLem1YOVUyNsd8Oqp7XEnEdao2cU51Q3PrdBrRIJY0w/s1600-h/CropperCapture%25255B11%25255D%25255B4%25255D.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="CropperCapture[11]" border="0" alt="CropperCapture[11]" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7kvfxe1qJR6nc3bXIzuSmB60mPkrbAW_9UEQkcxmKQ6l6hdPvjAy_DbpmyuEr0_l0Qx22IERRDiqxhwzS7X1I_RBbFryd9R9pSe9fuhA3cOUmb_arGxxM9D27LywPTxRJxozCog//?imgmax=800" width="554" height="107" /></a></p> <p>If BuildNumber specified:</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj06lwhtgHLweOyuoNCtty100x5sAaH3Wh1JCMLFAcf7BOWjd5FmMitSt53Z3yJoGcuYm4Mn3CoXWVbpPp49kx7tu1jsTcH9DAGwWNCg21L-xLQJdeJGj2RycvhyALy-v7iZGMGPA/s1600-h/CropperCapture%25255B12%25255D%25255B3%25255D.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="CropperCapture[12]" border="0" alt="CropperCapture[12]" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNGdlwPWummmJkRN16EtIZbcLeQODLeLAMpRAafVOjCmkeXvOGZTTCN22569qmcpjCMK7ZIP71nBeeSw00Zml3dx8r1i1NdgFu5J3oIwS88a3iPmAA8FVV6UdaXZUQCawUY9je7A//?imgmax=800" width="554" height="119" /></a></p> <p>Okay, you’re done. Now you can start using the template…here’s how:</p> <p>Under “Edit Project Settings”, click “Feature Branch Template”. In the bottom right, you should see this:</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCkhIgK5eSepAeOyrXtIR20m52f4AYCF3cScIFFz_iAx0smnYKmv0yaepoAU1KxYjle_IHCDAu2Zzd4R_BEXBNtvwv6tDRoJJUZhHOOmmncPlRxKJkJBOX9f1rpW7C3tR8qBzFFg/s1600-h/CropperCapture%25255B13%25255D%25255B3%25255D.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="CropperCapture[13]" border="0" alt="CropperCapture[13]" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYGJ3oEoBnQ-F94OhNSzLIZr9DLdVoSTWSq8Mn-noNj70OSXWn62Uby0aq4Y1n_g5qTjLc3dtVC_qWvrSfds0uKnm8gcLQv5HTm0gWIktRRFjJ2Bt1qWg0Wb7dz0XO5vAYHYBsBQ//?imgmax=800" width="299" height="113" /></a></p> <p><strong>Step 1: </strong>Click “Create Build Configuration from Template”</p> <p><strong>Step 2: </strong>Give it a name…typically I name it the branch name.</p> <p><strong>Step 3: </strong>Now click Build Parameters on the right</p> <p><strong>Step 4: </strong>Click the <value is required> for the parameters you specified above and set the value. Click Save.</p> <p>You’re done.</p> <p>The way we were handling this before was by copying the build configuration and then creating a new VCS root with the appropriate branch name and add to remember to change the build number…now it forces us to tell it and we don’t have to create the new VCS root.</p> <p>Please provide any feedback or post a comment if you have any questions.</p> Deran Schillinghttp://www.blogger.com/profile/06750574925211298370noreply@blogger.com1tag:blogger.com,1999:blog-19251193.post-26659557162986986992012-09-23T17:42:00.001-05:002012-09-23T17:45:04.047-05:00Export to Excel with MVC<div style="float: right"><a href="https://twitter.com/share" class="twitter-share-button">Tweet</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script></div><p>I’m sure you’ve all had to export to Excel at one point or another. I created a small wrapper around the <a href="http://nuget.org/packages/EPPlus/3.0.0.2" target="_blank">EPPlus library</a> for MVC. Basically my wrapper contains a few helpers for common formatting, an ActionResult, and a column definition. Here’s what the end result looks like in the simplest form:</p> <script src="https://gist.github.com/3773204.js?file=ExportToExcel_Sample_for_EPPlusForMVC.cs"></script><noscript> <pre> public ActionResult ExportToExcel()<br /> {<br /> var records = _getSampleInfoQuery.Execute();<br /> return new ExcelFileResult<SampleInfo>(records);<br /> }</pre><br /></noscript><p>Basically this exports all the columns and records in the SampleInfo collection. So if you want to specify the columns you want, you can do this:</p><br /><script src="https://gist.github.com/3773221.js?file=Specific_columns_and_formatting_export.cs"></script><noscript><br /> <pre>public ActionResult ExportToExcel()<br />{<br /> var records = _getSampleInfoQuery.Execute();<br /> var columns = new[]<br /> {<br /> ExcelColumnDefinition.Create<SampleInfo>(x => x.College),<br /> ExcelColumnDefinition.Create<SampleInfo>(x => x.Amount, ExcelFormat.Money),<br /> ExcelColumnDefinition.Create<SampleInfo>(x => x.CreatedDate, ExcelFormat.Date, "Date"),<br /> ExcelColumnDefinition.Create<SampleInfo>(x => x.CreatedBy),<br /> ExcelColumnDefinition.Create<SampleInfo>(x => x.CreatedDate, ExcelFormat.Time, "Time"),<br /> ExcelColumnDefinition.Create<SampleInfo>(x => x.PercentageExample, ExcelFormat.Percent),<br /> };<br /><br /> return new ExcelFileResult<SampleInfo>(records) {ColumnDefinitions = columns};<br />}</pre><br /></noscript><p>The ExcelColumnDefinition.Create<> is kinda ugly, so you could create a small helper method for readability like this:</p><br /><script src="https://gist.github.com/3773224.js?file=column_helper_method.cs"></script><noscript><br /> <pre>private static ExcelColumnDefinition Column(Expression<Func<SampleInfo, object>> member, string format = null, string header = null)<br />{<br /> return ExcelColumnDefinition.Create(member, format, header);<br />}</pre><br /></noscript><p>Now the above example looks like this:</p><br /><script src="https://gist.github.com/3773231.js?file=Specific_columns_and_formatting_with_method.cs"></script><noscript><br /> <pre>public ActionResult ExportToExcel()<br />{<br /> var records = _getSampleInfoQuery.Execute();<br /> var columns = new[]<br /> {<br /> Column(x => x.College),<br /> Column(x => x.Amount, ExcelFormat.Money),<br /> Column(x => x.CreatedDate, ExcelFormat.Date, "Date"),<br /> Column(x => x.CreatedBy),<br /> Column(x => x.CreatedDate, ExcelFormat.Time, "Time"),<br /> Column(x => x.PercentageExample, ExcelFormat.Percent),<br /> };<br /><br /> return new ExcelFileResult<SampleInfo>(records) {ColumnDefinitions = columns};<br />}</pre><br /></noscript><p>So this is what the ExcelColumnDefinition looks like:</p><br /><script src="https://gist.github.com/3773235.js?file=ExcelColumnDefinition.cs"></script><noscript><br /> <pre>public class ExcelColumnDefinition<br />{<br />public MemberInfo MemberInfo { get; set; }<br />public string Format { get; set; }<br />public string Header { get; set; }<br /><br />public static ExcelColumnDefinition Create<T>(Expression<Func<T, object>> member, string format = null, string header = null)<br />{<br /> return new ExcelColumnDefinition { MemberInfo = GetMemberInfo(member), Format = format, Header = header };<br />}<br /><br />private static MemberInfo GetMemberInfo<T>(Expression<Func<T, object>> expression)<br />{<br /> if (expression.Body is MemberExpression)<br /> return ((MemberExpression)expression.Body).Member;<br /><br /> return ((MemberExpression) ((UnaryExpression) expression.Body).Operand).Member;<br />}<br />}</pre><br /></noscript><p>Here’s the actual ActionResult:</p><br /><script src="https://gist.github.com/3773242.js?file=ExcelFileResult.cs"></script><noscript><br /> <pre>public class ExcelFileResult<T> : ActionResult<br />{<br /> private readonly IEnumerable<T> _records;<br /><br /> public ExcelFileResult(IEnumerable<T> records)<br /> {<br /> _records = records;<br /> }<br /><br /> public override void ExecuteResult(ControllerContext context)<br /> {<br /> using (var pck = new ExcelPackage())<br /> {<br /> var ws = pck.Workbook.Worksheets.Add(WorksheetName);<br /><br /> if (ColumnDefinitions == null)<br /> {<br /> ws.Cells["A1"].LoadFromCollection(_records, true, TableStyles.None);<br /> }<br /> else<br /> {<br /> ws.Cells["A1"].LoadFromCollection(_records, true, TableStyles.None, BindingFlags.Default, ColumnDefinitions.Select(x => x.MemberInfo).ToArray());<br /> Format(ws, ColumnDefinitions);<br /> }<br /><br /> const string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";<br /> var fileContentResult = new FileContentResult(pck.GetAsByteArray(), contentType) { FileDownloadName = FileDownloadName };<br /> fileContentResult.ExecuteResult(context);<br /> }<br /> }<br /><br /> private static void Format(ExcelWorksheet worksheet, IList<ExcelColumnDefinition> columnDefinitions)<br /> {<br /> worksheet.Row(1).Style.Font.Bold = true;<br /> for (var columnIndex = 1; columnIndex <= columnDefinitions.Count; columnIndex++)<br /> {<br /> var columnDefinitionIndex = columnIndex - 1;<br /> if (columnDefinitions[columnDefinitionIndex].Format != null)<br /> {<br /> worksheet.Column(columnIndex).Style.Numberformat.Format = columnDefinitions[columnDefinitionIndex].Format;<br /> }<br /> if (columnDefinitions[columnDefinitionIndex].Header != null)<br /> {<br /> worksheet.Cells[1, columnIndex].Value = columnDefinitions[columnDefinitionIndex].Header;<br /> }<br /> worksheet.Column(columnIndex).AutoFit();<br /> }<br /> }<br /><br /> public ExcelColumnDefinition[] ColumnDefinitions { get; set; }<br /><br /> private string _downloadName;<br /> public string FileDownloadName<br /> {<br /> get { return _downloadName ?? "ExcelFile"; }<br /> set { _downloadName = value; }<br /> }<br /><br /> private string _worksheetName;<br /> public string WorksheetName<br /> {<br /> get { return _worksheetName ?? "Sheet1"; }<br /> set { _worksheetName = value; }<br /> }<br />}</pre><br /></noscript><p>So that’s it. If you have any questions, please feel free to comment below. </p><p><strong><a href="https://github.com/derans/EPPlusForMVC" target="_blank">You can browse or download the source on GitHub.</a> The sample project has examples.</strong></p>
<a rev="vote-for" href="http://dotnetshoutout.com/Export-to-Excel-with-MVC"><img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Fderans.blogspot.com%2F2012%2F09%2Fexport-to-excel-with-mvc.html" style="border:0px"/></a>Deran Schillinghttp://www.blogger.com/profile/06750574925211298370noreply@blogger.com0tag:blogger.com,1999:blog-19251193.post-69628530885690581032012-08-30T00:21:00.001-05:002012-08-30T00:23:44.477-05:00Simple Way to Toggle on Hover with CSS<div style="float: right"><a href="https://twitter.com/share" class="twitter-share-button">Tweet</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script></div><p>Here’s a really simple way to toggle actions or more information to keep your pages clean.</p> <script src="https://gist.github.com/3522675.js?file=css_toggle.html"></script><noscript> <pre><html><br /><head><br /><style type="text/css"><br /> .toggle-me { display: none; }<br /> div:hover .toggle-me { display: inline-block; }<br /></style><br /><body><br /> <div>Most Important <span class="toggle-me">More Information</span></div><br /></body><br /></html></pre><br /></noscript><br /><p><a href="http://1pg.it/rw231nqo" target="_blank">View Demo</a></p> Deran Schillinghttp://www.blogger.com/profile/06750574925211298370noreply@blogger.com1tag:blogger.com,1999:blog-19251193.post-68091137691722781792012-08-25T02:42:00.002-05:002012-08-25T02:56:53.666-05:00A Method for Populating a Dropdown List in ASP.NET MVC<div style="float: right"><a href="https://twitter.com/share" class="twitter-share-button">Tweet</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script></div><p>I’m asked quite a bit how to bind a dropdown list in ASP.NET MVC. So there are about 10,000 ways to do it, but here’s one.</p> <p>First, we’ll create a simple interface to return a list of SelectListItem so we can use the built-in DropDownListFor() later on.</p> <script src="https://gist.github.com/3461708.js?file=Select_list_provider_interface"></script> <noscript> <pre>public interface ISelectListProvider<br />{<br /> IEnumerable<SelectListItem> Provide();<br />}</pre><br /></noscript><p>Then we can create a SelectListProviderAttribute to take in the Type of list provider we want. You can see in this example I'm instantiating the object with StructureMap...you could do this with Activator or something else.</p><br /><script src="https://gist.github.com/3461693.js?file=Select_list_provider_attribute.cs"></script><noscript><br /> <pre>[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]<br />public class SelectListProviderAttribute : Attribute<br />{<br /> public ISelectListProvider Provider { get; private set; }<br /><br /> public SelectListProviderAttribute(Type providerType)<br /> {<br /> if (typeof(ISelectListProvider).IsAssignableFrom(providerType))<br /> {<br /> Provider = (ISelectListProvider) ObjectFactory.GetInstance(providerType);<br /> }<br /> else<br /> {<br /> throw new ArgumentException("Provider type must be of type ISelectListProvider", "providerType");<br /> }<br /> }<br />}</pre><br /></noscript><br /><br />Now we just implement an ISelectListProvider and add the attribute to our model like this:<br /><script src="https://gist.github.com/3462086.js?file=CommunitySelectListProvider.cs"></script><br /><noscript><br /><pre>public class CommunitySelectListProvider : ISelectListProvider<br />{<br /> private readonly IGetCommunitiesQuery _getCommunitiesQuery;<br /><br /> public CommunitySelectListProvider(IGetCommunitiesQuery getCommunitiesQuery)<br /> {<br /> _getCommunitiesQuery = getCommunitiesQuery;<br /> }<br /><br /> public IEnumerable<SelectListItem> Provide()<br /> {<br /> var communities = _getCommunitiesQuery.Execute();<br /><br /> return communities.Select(community => new SelectListItem { Text = community.Name, Value = community.CommunityId.ToString() }).ToList();<br /> }<br />}</pre></noscript>
Sample property on view model:<pre>[SelectListProvider(typeof(CommunitySelectListProvider))]<br />[DisplayName("Community")]<br />public int CommunityId { get; set; }<br /></pre>Now we just call our new HtmlHelper in our view and we're done. So here's the helper:<br /><br /><script src="https://gist.github.com/3462135.js?file=DropDownListFor_SelectListProviderAttribute.cs"></script><br /><noscript><br /><pre>public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression) where TModel : class<br />{<br /> var property = expression.GetProperty();<br /> IEnumerable<SelectListItem> selectList;<br /><br /> var selectListProviderAttribute = property.GetAttribute<SelectListProviderAttribute>();<br /><br /> if (selectListProviderAttribute != null)<br /> {<br /> var provider = selectListProviderAttribute.Provider;<br /> selectList = provider.Provide();<br /> }<br /> else<br /> {<br /> throw new ArgumentException(string.Format("SelectListProvider not specified for property \"{0}\"", property.Name));<br /> }<br /><br /> return html.DropDownListFor(expression, selectList);<br />}</pre><br /></noscript>And now we just call it from the view like this:<br /><br />@Html.DropDownListFor(x => x.CommunityId)
<p>I'm sure you all realized that I used some additional helpers in code samples above. So for the curious few, I uploaded the full sample project to github. <a href="https://github.com/derans/PopulateDropdownSample" target="_blank">Browse the source now</a></p>
<a rev="vote-for" href="http://dotnetshoutout.com/A-Method-for-Populating-a-Dropdown-List-in-ASPNET-MVC"><img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Fderans.blogspot.com%2F2012%2F08%2Fa-method-for-populating-dropdown-list.html" style="border:0px"/></a>Deran Schillinghttp://www.blogger.com/profile/06750574925211298370noreply@blogger.com0tag:blogger.com,1999:blog-19251193.post-61439142618908188352012-07-31T00:37:00.001-05:002012-07-31T00:56:42.350-05:00Dynamically Generate Form with jQuery and ASP.NET MVC<div style="float: right"><a href="https://twitter.com/share" class="twitter-share-button">Tweet</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script></div><p>Hopefully it’s obvious that you probably won’t need to do this very often, but when it’s needed, it’s nice to have available. I thought I’d share this little helper to dynamically create a form, append it to body, and submit it...without AJAX.</p> <p>First I'll show you how I'm converting my view model to a parameter list and a query string. Basically I've created an extension method that loops through properties and checks if it's an IEnumerable or not. If it is, then I loop through the values of that property. Otherwise, I just add the value. This method does <em>not</em> work with complex types. Typically view models are flat, so this works well most of the time.</p> <p>The ToQueryString method just calls the ToParameterList, adds a ? to the front and then just selects what it needs from the parameter list.</p> <script src="https://gist.github.com/3213916.js?file=ObjectExtensions.cs"></script><noscript> <pre>public static class ObjectExtensions<br />{<br /> public static List<KeyValuePair<string, object>> ToParameterList(this object o)<br /> {<br /> var parameters = new List<KeyValuePair<string, object>>();<br /> var properties = o.GetType().GetProperties();<br /><br /> foreach (var property in properties)<br /> {<br /> var value = property.GetValue(o, null);<br /> if (value != null)<br /> {<br /> if (!(value is string) && value is IEnumerable)<br /> {<br /> foreach (var val in (IEnumerable)value)<br /> {<br /> parameters.Add(new KeyValuePair<string, object>(property.Name, val));<br /> }<br /> } else {<br /> parameters.Add(new KeyValuePair<string, object>(property.Name, value));<br /> }<br /> }<br /> }<br /><br /> return parameters;<br /> }<br /><br /> public static string ToQueryString(this object o)<br /> {<br /> var parameters = o.ToParameterList();<br /><br /> return "?" + string.Join("&", parameters.Select(x => x.Key + "=" + x.Value));<br /> }<br />}</pre><br /></noscript><p>The jQuery is pretty straight forward. I get the body, create a form with an action, loop through my param list creating a hidden input for each param, append the form to the body, and then submit it.</p><br /><script src="https://gist.github.com/3214005.js"> </script><noscript><br /> <pre>function GenerateAndSubmitForm(action) {<br /> var body = $('body');<br /> var form = $("<form method='post' action=" + action + "/>");<br /> @foreach(var param in Model.ToParameterList())<br /> {<br /> @Html.Raw("form.append($(\"<input type='hidden' name='" + @param.Key + "' value='" + @param.Value + "' />\"));")<br /> }<br /> body.append(form);<br /> form.submit();<br />}</pre><br /></noscript><p>As always, if you know of a different and/or better way, please let me know.</p><p>If you don't need to post, you can just use a get, you could do something like this:</p><br /><script src="https://gist.github.com/3214017.js"> </script><noscript><br /> <pre><a href="@Url.Action("ActionName")@Model.ToQueryString()">Link Name</a></pre><br /></noscript><p><strong><a href="https://github.com/derans/DynamicFormSample">You can download a sample project at GitHub.</a></strong></p><a rev="vote-for" href="http://dotnetshoutout.com/Dynamically-Generate-Form-with-jQuery-and-ASPNET-MVC"><img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Fderans.blogspot.com%2F2012%2F07%2Fdynamically-generate-form-with-jquery.html" style="border:0px"/></a>Deran Schillinghttp://www.blogger.com/profile/06750574925211298370noreply@blogger.com0tag:blogger.com,1999:blog-19251193.post-82556818277908312062012-06-11T22:42:00.000-05:002012-06-12T12:51:30.964-05:00Making Prettier Forms: Converting Checkboxes into Images<div style="float: right"><a href="https://twitter.com/share" class="twitter-share-button">Tweet</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script></div><p>A couple weekends ago I went to the <a href="bigdesignevents.com" target="_blank">Big Design Conference</a> in Dallas (recap coming soon), and I always come back inspired to help the user’s experience with the applications I write. One of the things mentioned (several times) was making forms simpler. Basically, you don’t have to make the end-user feel like they’re filling out a form. There are ways to make it seem less intimidating. One way is to swap out the typically hard-to-click checkbox or radio button with an image. It gives the user a larger click area and it looks nice…at least in my opinion.</p> <p>Basically, I’m helping a friend with a small project, and the image below is what I wanted to create.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiUJpn-T40ZZsI5d5GlBF8jvCVyessnhyRSzhfDdmh4KfCcXBo0AFTfgNPneYShsBUKu260rcjwtwsmeUs3jFdRiZucI1hEKEH9GbnLjzf4q7Q_Ghg-BHcsRFmLTS9Gyh3c_Rlbg/s1600-h/image%25255B3%25255D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsblTEs7-kwMQosaZzQ9ax51DFV1sjACTfR1JvQbAI8JtHveo3mISx8ixmb9VzOr5VGxo-9wp_uPZNxKlggNX3Q1L3_9NLst-SfMUrlH6hYP-6KNNeCaUQhE6h5_RpP2QsTsm0aQ//?imgmax=800" width="343" height="459" /></a></p>
<span style="font-size: .8em; color: #666;">If you buy <a href="http://www.amazon.com/Seductive-Interaction-Design-Effective-Experiences/dp/0321725522/ref=sr_1_1?ie=UTF8&qid=1339472295&sr=8-1" target="_blank">Stephen Anderson's book "Seductive Interaction Design"</a>, you will see a similar form to the one above...primarily just the name and contact info stuff. By the way, I definitely recommend this book.</span><p>As you can see, the “Select Classification” is not your typical radio button setup. I googled for a bit if there was already a jQuery plugin to do this type of thing and came up empty. I’m sure you almighty readers know of one, but I couldn’t find it…so I made one.</p> <p>So far I’ve tested it in Firefox, IE9, Chrome, and <a href="http://www.freedomscientific.com/products/fs/jaws-product-page.asp" target="_blank">JAWS</a>, and it works pretty good in all of them. The way I set it up to work is based on the input and label. So you’d have the most accessible standard markup with your preferred styles for the label, and that’s how you get the effect shown above. I think it’s probably better said with code:</p> <script src="https://gist.github.com/2914607.js"> </script><noscript><fieldset id="classification_radio_wrapper"> <br /><legend>Classification</legend> <br /><input id="Freshman" name="classification" checked="checked" type="radio" /> <label class="Freshman" for="Freshman">Freshman</label> <br /><input id="Sophomore" name="classification" type="radio" /> <label class="Sophomore" for="Sophomore">Sophomore</label> <br /><input id="Junior" name="classification" type="radio" /> <label class="Junior" for="Junior">Junior</label> <br /><input id="Senior" name="classification" type="radio" /> <label class="Senior" for="Senior">Senior</label> <br /></fieldset></noscript> <p>So it looks like a pretty typical setup so far, right? You have an input with a label. To make it more accessible, you wrap it with a fieldset and give it a legend. The primary reason you’d do this is to give screen readers some context. If you don’t need to worry about that, you could just as easy wrap it all with a div. You’re going to want to wrap it so your jQuery selector is more precise. After you markup the form, you just add the following JavaScript.</p> <script src="https://gist.github.com/2914634.js"> </script><noscript><script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> <br /><script type="text/javascript" src="jquery.checkmate.min.js"></script> <br /><script type="text/javascript"> <br />$('#classification_radio_wrapper label').checkMate(); <br /></script> </noscript> <p>Now you’re all wired up, and you just add in your styles to whichever stylesheet classes you specified. The default stylesheet class names I specified are:</p> <ul> <li>.Selected-Checkbox – this class is added to the label after it has been clicked</li> <li>.Checkbox-in-focus – this class is added to the label when the checkbox/radio button is in focus</li> </ul> <p>If you’re not sure the plugin is working properly, you can put it in “testMode”, like this:</p> <p>$('#classification_radio_wrapper label').checkMate({testMode: true });</p> <p>If you need to override my default class names, you can do that too by specifying class or focusClass in the options. I might rename class to selectedClass in the near future.</p> <p>Please leave a comment if you have any questions or feedback.</p> <strong><p>The source code is available on github at <a title="https://github.com/derans/checkMate" href="https://github.com/derans/checkMate">https://github.com/derans/checkMate</a></p> <p>The demo is located on 1pg.it at <a title="http://1pg.it/v9etvtn5" href="http://1pg.it/v9etvtn5">http://1pg.it/v9etvtn5</a> (also on github as the example.htm file)</p></strong>
<br/><br/><a rev="vote-for" href="http://dotnetshoutout.com/Making-Prettier-Forms-Converting-Checkboxes-into-Images"><img alt="Shout it" src="http://dotnetshoutout.com/image.axd?url=http%3A%2F%2Fderans.blogspot.com%2F2012%2F06%2Fmaking-prettier-forms-converting.html" style="border:0px"/></a>Deran Schillinghttp://www.blogger.com/profile/06750574925211298370noreply@blogger.com3tag:blogger.com,1999:blog-19251193.post-70132490672731668982012-05-22T00:21:00.000-05:002012-05-22T00:21:18.188-05:00File Icons using CSS Selectors<div style="float: right"><a href="https://twitter.com/share" class="twitter-share-button">Tweet</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script></div><p>This post is for a friend that was asking how to easily show icons with different file extensions. What I’ve setup are some styles that can just be copied over to any stylesheet and used. </p> <p>I converted the icons downloadable at famfamfam.com to base64 and placed them in the styles. Without further ado, here they are:</p> <script src="https://gist.github.com/2766637.js"> </script><noscript> <pre><style type="text/css"><br />a.with-icon <br />{<br /> padding-left: 20px;<br /> background-position: top left;<br /> background-repeat: no-repeat;<br />}<br /><br />a.with-icon[href$='.gif'],a.with-icon[href$='.png'],a.with-icon[href$='.jpg']<br />{<br /> background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHwSURBVDjLpZM9a1RBFIafM/fevfcmC7uQjWEjUZKAYBHEVEb/gIWFjVVSWEj6gI0/wt8gprPQykIsTP5BQLAIhBVBzRf52Gw22bk7c8YiZslugggZppuZ55z3nfdICIHrrBhg+ePaa1WZPyk0s+6KWwM1khiyhDcvns4uxQAaZOHJo4nRLMtEJPpnxY6Cd10+fNl4DpwBTqymaZrJ8uoBHfZoyTqTYzvkSRMXlP2jnG8bFYbCXWJGePlsEq8iPQmFA2MijEBhtpis7ZCWftC0LZx3xGnK1ESd741hqqUaqgMeAChgjGDDLqXkgMPTJtZ3KJzDhTZpmtK2OSO5IRB6xvQDRAhOsb5Lx1lOu5ZCHV4B6RLUExvh4s+ZntHhDJAxSqs9TCDBqsc6j0iJdqtMuTROFBkIcllCCGcSytFNfm1tU8k2GRo2pOI43h9ie6tOvTJFbORyDsJFQHKD8fw+P9dWqJZ/I96TdEa5Nb1AOavjVfti0dfB+t4iXhWvyh27y9zEbRRobG7z6fgVeqSoKvB5oIMQEODx7FLvIJo55KS9R7b5ldrDReajpC+Z5z7GAHJFXn1exedVbG36ijwOmJgl0kS7lXtjD0DkLyqc70uPnSuIIwk9QCmWd+9XGnOFDzP/M5xxBInhLYBcd5z/AAZv2pOvFcS/AAAAAElFTkSuQmCC)<br />}<br />a.with-icon[href$='.avi'],a.with-icon[href$='.mov'],a.with-icon[href$='.mpg'],a.with-icon[href$='.wmv']<br />{<br /> background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAIfSURBVDjLpZNPaBNBGMXfbrubzBqbg4kL0lJLgiVKE/AP6Kl6UUFQNAeDIAjVS08aELx59GQPAREV/4BeiqcqROpRD4pUNCJSS21OgloISWMEZ/aPb6ARdNeTCz92mO+9N9/w7RphGOJ/nsH+olqtvg+CYJR8q9VquThxuVz+oJTKeZ63Uq/XC38E0Jj3ff8+OVupVGLbolkzQw5HOqAxQU4wXWWnZrykmYD0QsgAOJe9hpEUcPr8i0GaJ8n2vs/sL2h8R66TpVfWTdETHWE6GRGKjGiiKNLii5BSLpN7pBHpgMYhMkm8tPUWz3sL2D1wFaY/jvnWcTTaE5DyjMfTT5J0XIAiTRYn3ASwZ1MKbTmN7z+KaHUOYqmb1fcPiNa4kQBuyvWAHYfcHGzDgYcx9NKrwJYHCAyF21JiPWBnXMAQOea6bmn+4ueYGZi8gtymNVobF7BG5prNpjd+eW6X4BSUD0gOdCpzA8MpA/v2v15kl4+pK0emwHSbjJGBlz+vYM1fQeDrYOBTdzOGvDf6EFNr+LYjHbBgsaCLxr+moNQjU2vYhRXpgIUOmSWWnsJRfjlOZhrexgtYDZ/gWbetNRbNs6QT10GJglNk64HMaGgbAkoMo5fiFNy7CKDQUGqE5r38YktxAfSqW7Zt33l66WtkAkACjuNsaLVaDxlw5HdJ/86aYrG4WCgUZD6fX+jv/U0ymfxoWVZomuZyf+8XqfGP49CCrBUAAAAASUVORK5CYII=)<br />}<br />a.with-icon[href$='.exe'] <br />{ <br /> background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAFiSURBVBgZpcEhbpRRGIXh99x7IU0asGBJWEIdCLaAqcFiCArFCkjA0KRJF0EF26kkFbVVdEj6/985zJ0wBjfp8ygJD6G3n358fP3m5NvtJscJYBObchEHx6QKJ6SKsnn6eLm7urr5/PP76cU4eXVy/ujouD074hDHd5s6By7GZknb3P7mUH+WNLZGKnx595JDvf96zTQSM92vRYA4lMEEO5RNraHWUDH3FV48f0K5mAYJk5pQQpqIgixaE1JDKtRDd2OsYfJaTKNcTA2IBIIesMAOPdDUGYJSqGYml5lGHHYkSGhAJBBIkAoWREAT3Z3JLqZhF3uS2EloQCQ8xLBxoAEWO7aZxros7EgISIIkwlZCY6s1OlAJTWFal5VppMzUgbAlQcIkiT0DXSI2U2ymYZs9AWJL4n+df3pncsI0bn5dX344W05dhctUFbapZcE2ToiLVHBMbGymS7aUhIdoPNBf7Jjw/gQ77u4AAAAASUVORK5CYII=)<br />}<br />a.with-icon[href$='.pdf'] <br />{<br /> background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHhSURBVDjLjZPLSxtRFIfVZRdWi0oFBf+BrhRx5dKVYKG4tLhRqlgXPmIVJQiC60JCCZYqFHQh7rrQlUK7aVUUfCBRG5RkJpNkkswrM5NEf73n6gxpHujAB/fOvefjnHM5VQCqCPa1MNoZnU/Qxqhx4woE7ZZlpXO53F0+n0c52Dl8Pt/nQkmhoJOCdUWBsvQJ2u4ODMOAwvapVAqSJHGJKIrw+/2uxAmuJgFdMDUVincSxvEBTNOEpmlIp9OIxWJckMlkoOs6AoHAg6RYYNs2kp4RqOvfuIACVFVFPB4vKYn3pFjAykDSOwVta52vqW6nlEQiwTMRBKGygIh9GEDCMwZH6EgoE+qHLMuVBdbfKwjv3yE6Ogjz/PQ/CZVDPSFRRYE4/RHy1y8wry8RGWGSqyC/nM1meX9IQpQV2JKIUH8vrEgYmeAFwuPDCHa9QehtD26HBhCZnYC8ucGzKSsIL8wgsjiH1PYPxL+vQvm5B/3sBMLyIm7GhhCe90BaWykV/Gp+VR9oqPVe9vfBTsruM1HtBKVPmFIUNusBrV3B4ev6bsbyXlPdkbr/u+StHUkxruBPY+0KY8f38oWX/byvNAdluHNLeOxDB+uyQQfPCWZ3NT69BYJWkjxjnB1o9Fv/ASQ5s+ABz8i2AAAAAElFTkSuQmCC)<br />}<br />a.with-icon[href$='.zip'] <br />{<br /> background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAKQSURBVDjLbZNNaJxVFIafe7/5KTPzpUloNK0tIsowCtbiQgRRQReudCMVqYrdiLgQ01UrWUgXXZQumoU2myyKii66dOFCEUo3IiL+VRMFHactYpsMmsy0mbnnx8X8tEn7wuHAudyH97zcG9wdgKWl9zNgl7vvrVar51T1PndHVQHDzBCRFGNhqd1ePXb06PF1gALAhbONF+7PanPtymtP9G2iVK3WmJjYibtjZuNupsWVlYtviaRTwABw4WzjEPDRVGMy/vt3QLpCu73G2toqZoKZE2Mkz3PyfBKxgKplDFUA3rz7wL5Y2lnigdrHiDhuRlaoYJslrv3cWb7cfehka/3BxUY93+EGqolbAU/tqz+K2V/MzFQAHZYQ4146v55v/NPd81UxL6uKQgyY2RgQB025fOUPCC9COAjhJVqt38BlcKpKb/M65kbq9YfB3nQAGOVSxqXWCXDBSZTLBWAAMDOKsYibYURE0naAMjOzC5gc2Pc0vDwApJTQGx3UDJHNLQ7GK1xq/Q7hFQivQjzMn82LY4CqhiwWw8BBQNW2OxBK5Yxm812whNNnx5YVtBBkoxICkLqYbcugt9Fh9+xj4/RHtblxA7EMVZsOYZC+qqMqWwBHfvr829OjgRNIWkIsIhb54cr+r7Ms+3Bqanr0GjHzm4AnDy8vAAujwfz83NTs7O7z3W7nYTOjH3uPp7RuWZYNHdhtDrZIVda/8+fPWa06nfWvfjJxdfFTEd2zvPzLZyn1CCHSrx954/UPWi8DC2H0G2/VM8ebzeceqd375fer/9WvnTgDVET0oLsWzJDmPe/lzx64K//ix43WHQH1t1fmgLkC/TNPy8lFM4vuWhGx6G72TXX+UAqVd4DT/wMfm3vSJoP5ygAAAABJRU5ErkJggg==)<br />}<br />a.with-icon[href$='.rss'] <br />{<br /> background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJFSURBVBgZBcHda5V1AADg5/d733Oc7tjOaNs5GC6KdrEwmpPRxG7spoKghOim7oK8y0MIEQRL+geGEIQ3UXQvSJ8IafZxUbjQhRDZoU60iYsSc9t5v87b84TsVe3mrBWpHoCICIAIACixYTUfOJM2Z62YO97TOULSIKaEQAyESAzEgISAgLpi48de87MLUqmezhGyhO4SCW7f4O81YiSJiCQIkbqmNcXMIjMXeilIGsQxDp8AnKDY5teL3PyU6h4CdY3Av7cYu58R0QghZWeT9fP0v2V7i8Y4j77As2c5sAwIFAXDgjInJxURAzub/PwxMZBGphZYeIWJWZ44xdo5bl4kK8kzioohUUREd4kXP+Kpd3nkee72+epNBleAxdfoLJBlDEuKkpxoBAkBjXGm53n8ZZ45S/shrr7P75eBo6eo9zAsKCqGRBEB/1zj89e5eo7tLRr7ePJtWg9wZZV7t2i2OPQcw5JiRE4UESN1ZPc2g0tceos/LtPYx9HTaPDNe8Dhl9gtyStyUiMIJDXLp2m0GHzN2gdMzdPq0F3k+pcc/4+x/UwepKzIiSDWTB/iwBLT8xw8xt07rJ8HHj7GbkX/B+DBxyhrciIQ2N2i2AG2fiPL+OsXoNVlWPDnDaC5l6qiJJWjLlHxxRs0JhhcIyvp/8SHJylKdiu++4Tr31NW7B8nkrwzp627d9nkHM0Wsea+GSY6tDvESEyY6TIxyZ4GSUp/nTubqyF7WrvZtaKrZ4QSQ+TIMUSJHCVypGhaHW448z+h1tLAgvKk7gAAAABJRU5ErkJggg==)<br />}<br />a.with-icon[href$='.js'] <br />{<br /> background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJ+SURBVBgZBcExbFRlAADg7//fu7teC3elQEoMgeDkYDQ6oMQQTYyGxMHZuDA6Ypw0cWI20cHJUdl0cJLIiomR6OACGhUCpqGWtlzbu/b97/3v9/tCKQVc/e7RRXz+7OrSpUXbW7S9tu8ddv0M+3iCjF1s42v8WAP0XffKi2eOXfro9dMAYJ766SL1092jfDa17DfZgycHfvh7/hau1QB9161PhgE8epoNQlAHqprRIDo3iqoYDSpeOjv2zHRl7atfNj6LALltJys1Xc9+CmYtTxtmR8yO2D7kv4MMPr7x0KULK54/NThdA+S2XTs+jOYN86MsxqBGVRErKkEV6BHynp//2fXbw9lGDZBTWp+OK7PDzqIpYiyqSMxBFakUVYVS2dxrfHHrrz1crQG6lM6vTwZmR0UHhSoHsSBTKeoS9YU8yLrUXfj+w9d2IkBOzfkz05F5KkKkCkFERACEQil0TSOnJkMNV67fHNdVHI4GUcpZVFAUZAEExEibs4P5osMeROiadHoUiIEeCgFREAoRBOMB2weNrkmbNz+9UiBCTs1yrVdHqhgIkRL0EOj7QGG5jrZ2D+XUbADEy9dunOpSun7xuXMe7xUPNrOd/WyeyKUIoRgOGS8xWWZ7b6FLaROgzim9iXd+vXvf7mHtoCnaXDRtkLpel3t9KdamUx+8fcbj7YWc0hZAndv25XffeGH8yfuvAoBcaHOROhS+vLlhecD+wUJu222AOrft/cdPZr65ddfqsbHVyZLVlZHpysjx5aHRMBrV0XuX141qtnb25bb9F6Duu+7b23funb195955nMRJnMAJTJeGg8HS0sBkZWx1suz3Px79iZ8A/gd7ijssEaZF9QAAAABJRU5ErkJggg==)<br />}<br />a.with-icon[href$='.cs'],a.with-icon[href$='.html'] <br />{<br /> background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAALESURBVBgZPcFLaJxlFIDh95zv+//MJZObITUUq/QSG42orcULSnQhgmRjQRCyqaC4qLqrLgQ34gV040JKcOGiEMS9C0E3iVGEWIu0pWClWAlpmsaZSRuTmfn+c8zY0ecRd6fr2XcXTpQH+mZVOAqUAKFLABdwI5n93tjw72Szfmrx9EybXeLudD3/wdLimTeOTqrKkEPA+Z87u5z1Wx3mlxtcu9r6++L5SyPfn55pRXo0yL15DEMXrhNUBATcoHAjJWe7U/D0oRqPTkR+svWK2+H69OtfDys9ItLv7iEPSqYQBYJCEBABRQBjfCBn5tg49xzsK8eB6hdKj4NstR0FVEBFUBFUBBVBg7D61zZ393e4b0R49fE7CFl4MdJjKB8tNGkWzqnHRvn0XIOYYHaqRgxC7srlDadtCbM2T+3vQ6ImZddDH14Z8YGxPGaKtkBFIEGtDGfONmm1nSwofXmglAdKeYajIIo++P6Vl6YOVVcm9/Vrs1HwyiMjqAgn7h9kvVFQKcPnP9dZ/m2LLCp5CPRFxQB30MkD5bl9tVBarXd4+UiF4VrEgeGKcnyixlozMV4Vlv7cQoCoQgxKYVAY6Lnlzdcur7Z2RvLA3GKTjUYHd2fjVuKrX+oMReWPtTZPjlfIVIkqBBVKmVAkRy99MvHl8lJ97/mLdSuVlM++uUZhMLdwg2pJ2dro8Ob0GE9MDeCAOTiQBSW1E+LudE2/88P2/jv3lm60oXJ4D62r62zehMGDo2gudLmDcdv8cxnPvLW4E+kxS7w3u4ePL+QcGVPswF0UDoWAOTjgDu7w6/WEm9PZSUR6UsssmXm7QH5cKTBxHKHLHATHHFwFNSFGsVRYivR0doq1ah5G336gXXV3xcG4bbAc6XKHciaIYFmQm0WyFXF3uo6d/PZk6vgLIvKw4xX+4+CA4/zL6doxs7MK8/8A73I7wFFcAY8AAAAASUVORK5CYII=)<br />}<br />a.with-icon[href$='.xlsx'],a.with-icon[href$='.xls'] <br />{<br /> background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAALDSURBVBgZBcFNiFVVAADg75x777z50RmdDJG0phpTIwq1cqP9IBqlLaxNpYVSVIvahLVLCqFFoGEZQkQhgdGilUghaqRNIKgUZEmQlCBlmmOm772Zd+85fV/IOVuz7ejmgeHWxhgsRz8CCMiBnNQp/Xbln3w4XJ18/die9dMAIefssXcmjn326vIlMYZZmUIGIGfILl7r2Xfiir/OTbV//unM6Hd71k9BCbEIi/rKYtbpvxUxBAI50eSkrrNOr/HQwplW3FE6ni4O5rR48sFXDsz+dve6qQghhBk556KviKpIGSgiRSAEooBk3nCf9ffNMzbeGiiHhz6F8NSO1WdTHh2bNZhCk4Nl44+7fP2Sb37cK6NVzdCk2rplz9j0wEtaVandnbbpvZP1wbdXVSVOvfzI5ls7rT/9fvmMUyf3q1PbsoX3mG5q7XZHMmp8wdOOn6ulNG3VbS2hjDVEbPzw64PNDXnc8NCwRXfNU8ZBl65e1m53lcVcW9a8b3hoRH9fob+vkkVCBPHz1w5NtZsne19M7LVkYLWZ/QPGF92i2+mq69ILa3caqFqqMuorCq0ySsgZiNBuHy6+//WIXQe2u3/OBk3ZceeSu031Jp3+45CyoCqCMgZlETWJJgHx3jduevFa5+NqxeKVchXs3P+WRxc8a9Il88du99WJDzy/a0zIQRmDIgb9VdDUGURsI5s4fcQvZ3/QmW58cuQjT4w9Z2TmbKM3L7D01pUyUiajKqJ6ugbliXfPz3/4zYnOvq3L+y9eq8C/1y/4cmK7691JIUQjgzeqIlUMIOWsN5VACXXdaBoARobm2rJ2NwAAgJyyXrcGEeqplOqUMgAAAABAWcZUN6mGEnrd5sJQXzFH6A3lnKNMAowMlCBnBqooBKkqwn9Nnc5DCSHkHWu3Ht0QQlia5UEAmYwsAxl0U0qnymgf/A8eWStYAg6kAQAAAABJRU5ErkJggg==)<br />}<br />a.with-icon[href$='.docx'],a.with-icon[href$='.doc'] <br />{<br /> background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAKbSURBVBgZBcFNiFVlGADg5/vOuffOdcb5cbKcjUn5V7poFJEiKMKybDYFgdSmKAiiokW1aNHSXWQQuGwR2KJFq2hTkFqUEbZRMzQIJS1nbPxjnHvvOd/b86SI8OSHx1/uT/ZeyslujCGBhEhE0ZTy5/Vr8V26ufzeiSMLQ4AUEQ4c+vHE52/tfiDnNB1UAoAICIu3R47+et0/FwcrZ0+fW/fDkYUB1JCrtK1bV9NnrqpySiSi0EbRNOHOqPX4lrX2bq2dLItromxffuzNr2eOffrsIENKaSIiqm6VdTJ1ospUiZTIEoq5ya6FPXM2be7168nxz6De+c7vhx+a39h/48tF8zN9nYqfrtyx956+4aj49swVMxPTtsyuc+9EpdepbXp41rGf/3oBL+ZmEKfunqiNBfv3TDl+acXqMDyxa8rlxaEUvH5gvQvXkpMXG9+fX9HrVFKdG8iKX26sFM/vGFen7PbSsq29WpWT01eW7Ns2Z02v0utWxrqVsW5HyKQM6mht7lX8duGOj7+5ZPv96y3913r/i8sU9j86Y9QGKUttEjkURAB1jMq4YClluWV6NUlTterSooN7N8opqasgEkFI2kJbgBxDvWiTs+evOvTKg/qdZDgqbq0Uj+yaBEmSIqlzUuVkrJO0TYC6jGKuSnSa0O9mf1weuNHe9PTWDUqEErSFQAki0amyZtiAOrVp6tz5qw6/ep8miqlOdnG59cy+WSWAKlOhkxMoEUaDAvKFr3Z+MBhdX51eW4PXDm7wyds7AAAAQJQwWm1AhmZQSlNKAAAAAADUdS5NWxqoYbTa/jvere6SRuMRkQUFMNWvQQT9TpaS0qnSrbYpf0MNKcVHT717/LmU0nyINQCCQAggwGop5VSdHYX/AYn4JwmEykruAAAAAElFTkSuQmCC)<br />}<br />a.with-icon[href$='.txt']<br />{<br /> background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAADoSURBVBgZBcExblNBGAbA2ceegTRBuIKOgiihSZNTcC5LUHAihNJR0kGKCDcYJY6D3/77MdOinTvzAgCw8ysThIvn/VojIyMjIyPP+bS1sUQIV2s95pBDDvmbP/mdkft83tpYguZq5Jh/OeaYh+yzy8hTHvNlaxNNczm+la9OTlar1UdA/+C2A4trRCnD3jS8BB1obq2Gk6GU6QbQAS4BUaYSQAf4bhhKKTFdAzrAOwAxEUAH+KEM01SY3gM6wBsEAQB0gJ+maZoC3gI6iPYaAIBJsiRmHU0AALOeFC3aK2cWAACUXe7+AwO0lc9eTHYTAAAAAElFTkSuQmCC)<br />}<br />a.with-icon[href~='mailto:'] <br />{<br /> background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAITSURBVBgZpcHLThNhGIDh9/vn7/RApwc5VCmFWBPi1mvwAlx7BW69Afeu3bozcSE7E02ILjCRhRrds8AEbKVS2gIdSjvTmf+TYqLu+zyiqszDMCf75PnnnVwhuNcLpwsXk8Q4BYeSOsWpkqrinJI6JXVK6lSRdDq9PO+19vb37XK13Hj0YLMUTVVyWY//Cf8IVwQEGEeJN47S1YdPo4npDpNmnDh5udOh1YsZRcph39EaONpnjs65oxsqvZEyTaHdj3n2psPpKDLBcuOOGUWpZDOG+q0S7751ObuYUisJGQ98T/Ct4Fuo5IX+MGZr95jKjRKLlSxXxFxOEmaaN4us1Upsf+1yGk5ZKhp8C74H5ZwwCGO2drssLZZo1ouIcs2MJikz1oPmapHlaoFXH1oMwphyTghyQj+MefG+RblcoLlaJG/5y4zGCTMikEwTctaxXq/w9kuXdm9Cuzfh9acujXqFwE8xmuBb/hCwl1GKAnGccDwIadQCfD9DZ5Dj494QA2w2qtQW84wmMZ1eyFI1QBVQwV5GiaZOpdsPaSwH5HMZULi9UmB9pYAAouBQbMHHrgQcnQwZV/KgTu1o8PMgipONu2t5KeaNiEkxgAiICDMCCFeEK5aNauAOfoXx8KR9ZOOLk8P7j7er2WBhwWY9sdbDeIJnwBjBWBBAhGsCmiZxPD4/7Z98b/0QVWUehjkZ5vQb/Un5e/DIsVsAAAAASUVORK5CYII=)<br />}<br />a.with-icon[href~='http://']<br />{<br /> background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAMtSURBVDjLVZNLa1xlAIafc5szk8xkMkkm5MKY2EpT2qa2MTVCmoLS2gq6EKooimAW7iQb/0I2bgTRIog0oFW7KQpCS7VqrSmmJGlSQtswqWlLLmbGmcmcZM6cy/edz00r6bt8eXh4N6+mlGJnxiZHR4APgSNAFjCBKjClInXm05Gzl3by2mPB2OSoCUwAp1/LHbcziSyO24gbgJAegg2urF8UUsifhZBvfvXK99v/C8YmRy3gt8G2/cMv517E8Wx8ApYcjZiyKbkRSgQkcFn3rzG9Nn1LhOLYt2/8UNUfLZkYaN0zfLRrkLIMCHUNIXTqIoZLjLJvU/ASrFQtnko+z2BH38HAD78DMConHh4FPn5nz6vGgqyxTp16JNj2kpR9C8eD/OoW1VoNO1NCS+d5oW0vV27f2PX11MS8MTR6+JOTXUMHNCPBui5AtdMpk8xsGNQ9ndur20TxCnbPIn5TnmJUwaxIDrTm9Jn7d1tM4EiuqZs5d41iXGefsZsIwYNCgOfVSXconJbLLEWb4CuahU2+6HO8d4DQF/0m0NpgNvLAXaPgu6QadrEZpKhUItJZj/aMS1EewvHnsdUWW/+WKG82kEykCAPRbCqlNE1B4DsocpiW5OJfIVoiyfqSQFdNdGXrpLZGcFZDPKYJg2VQCiGEZkoRlZ3A6W41mknFn2WlaOKFFrG4Tbw9wb2/S3g3miHySLdbNDd2kzYKVGpVpIiqugjF7P3yQ55pyLFWmCSyVokZPqHnEoYmsWQGuyWOGdexNIkRFOnqbGN5bRngjh4G4rMLd6+KnmQW012lWrpOJuNjCh9LU9i6gRkEZHIrpNv/QK8vcijXz5lfLijgS+PmuYV75+fPDXr1Wt9znfsouy5x+2miuoltW1iawBJV0o0/wT8lBvbv5WZ+gaWNlasz43MfmQChH777e37uT78eHDx5+BiLBROjqhDaFmGkQ1KS6+mlr7+XX2evc+nWVB54+4kznfr8pZQIxXkRyhPvDb9vIjtQqgFN12hLO2yUZ/ni8o8SuAa8NTM+t/GE4HGGx4del0J+IGXUH8ko86iuAneAszPjc9/s5P8DuO6ZcsXuRqAAAAAASUVORK5CYII=)<br />}<br /></style></pre><br /></noscript><p>These are all the basic file types I could think of and obviously you could add more to the list. I also added the with-icon, but this could be easily removed so it applies to all your hrefs all the time. There are a couple “special” styles at the bottom of the list for email and http links that use the ~=, which means starts with. All the rest of the styles work off the $= selector, which means ends with. To give the same icon to multiple file types, you just separate the selector with a comma.</p><p>In order to use these styles, you just do this:</p><br /><script src="https://gist.github.com/2766677.js?file=Links_to_files_with_icons.html"></script><noscript><br /> <pre><ul><br /> <li><a href="test.jpg" class="with-icon">Link to jpg</a></li><br /> <li><a href="test.exe" class="with-icon">Link to exe</a></li><br /> <li><a href="test.zip" class="with-icon">Link to zip</a></li><br /> <li><a href="test.rss" class="with-icon">Link to rss</a></li><br /> <li><a href="test.avi" class="with-icon">Link to avi</a></li><br /> <li><a href="test.html" class="with-icon">Link to html</a></li><br /> <li><a href="test.xls" class="with-icon">Link to xls</a></li><br /> <li><a href="test.docx" class="with-icon">Link to docx</a></li><br /> <li><a href="test.pdf" class="with-icon">Link to pdf</a></li><br /> <li><a href="test.txt" class="with-icon">Link to txt</a></li><br /> <li><a href="test.js" class="with-icon">Link to js</a></li><br /> <li><a href="mailto:" class="with-icon">Link to mailto</a></li><br /> <li><a href="http://" class="with-icon">Link to external site</a></li><br /></ul></pre><br /></noscript>This ends up looking like this: <br /><br /><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3ecekNaaR2n8xRF_kWW6kgg3a34-cF80_-8h2Fm2oMT-hoF8GY_YrjKaz9NMv93GTbsBIspGr65Z-taSpS4wSuWdLg70C5ZEZzdCDE1h5TirnIjd0srBVSyyM361SFb7qbmahAQ/s1600-h/links_with_icons%25255B3%25255D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="links_with_icons" border="0" alt="links_with_icons" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKWgrzMocOlSuSvdkkizpD1k1EItC1LWdb9kOzx8yel-sn2aBjF4bNLxnGD5EQzBY5bUAAGhnZaDm351T0x31GnqTtAKQXkFgYGrbnzqjcJjy-80NsdYhV8jp7SGUn6Fs-MzRB4g//?imgmax=800" width="174" height="297" /></a></p>Deran Schillinghttp://www.blogger.com/profile/06750574925211298370noreply@blogger.com0