In a good timing for the new year, I'm happy to announce new features to AspView.
I have dedicated a post for each so I'd have a way to reference those features, and for my dear readers to comment on each feature.
So, what's all the fuss about?
Downloads, as always, are from www.aspview.com
A cool feature, repeatedly asked for by users (of AspView, and of MonoRail in general).
When stating the layout name in the controller, you use a comma separated list of layouts to be applied, from the most general (outer) inward.
Example:
in the controller:
[Layout("Site, Admin")]
public class UsersController : SmartDispatcherController
{
public void Index() { }
}
and given those schematic templates:
We'd get:
Say you want to have the possibility to create a method to work in views.
for the sake of argument, let it be:
public string DoubleId(string s)
{
return s + s;
}
your options:
But what if it's simple enough (so you won't need a unit-test) and it's not supposed to be reused (so creating a Helper/Base class is an overkill)?
Now you can put it directly in your view template, and this is how:
<script runat="server">
public string DoubleId(string s)
{
return s + s;
}
</script>
Regular view code
<%=DoubleIt(view.Name) %>
Now the devil advocates would say that "Logic In View Is Evil". And I would concur. But it's not actually logic. It's supposed to be used for view-related string manipulations and such. And anyway you can do Evil Deeds without it, too. And you don't HAVE to use it if you don't want to.
The idea (and 99% of implementation) is by Gauthier Segay. Thanks dude !
It's been asked on the Castle mailing list, and was implemented for NVelocity (and for Brail too, I think), so now it works on AspView, too.
So, doing:
[Layout("\custom\layout")]
public class MyController ...
Would use the template from Views\Custom\Layout.aspx
The existing <%= %> syntax would keep output the raw strings, so it can be used to output properties that has markup inside, like CMS data, the ViewContents in layouts, CaptureFor data, etc.
If you want http encoded output, use <%# %> or ${} instead.
Example:
Given the following view template:
<%
string markup = "<span>";
%>
<%=markup%>
<%#markup%>
${markup}
The rendered output would be:
<span>
<span>
<span>
Have fun.
I found out that on many occasions I use stuff like:
<aspview:properties>
string message = "";
</aspview:properties>
To avoid the need of:
<% = message ?? "" %>
That's it.
From now on, null values would just be ignored.
Notice that it won't help you on
<%=post.Blog.Title %> if post.Blog is null ...
My personal preference in javascript framework is prototype + YUI.
I take the language enhancements of prototype (enumerable/array, extend, $/$$), and the richness of widgets and event handling of YUI. One might say that prototype is my Javascript2, and YUI is the BCL.
These days I'm with YUI 2.4.1 and prototype 1.6.0
This week I needed to put floating color pickers on a few screens in a system.
Usually, the easiest thing would be to copy a pre-existing demo fro YUI docs. However, the color picker in dialog demo there was about the dialog posting to the server it's results, while I needed just to save the value into form fields.
The sample also uses a preexisting markup, which was not good in this scenario.
Plus, since the said system have a very complicated (and fragile) styling and scripts happening on many pages, strange things have happened to the dialog if ran more than once on the same page, so I've added a "destroy" method that would cause the dialog to be rebuilt each time. It's lightning fast, and has no visible effects on the user experience.
Another major change I've made to the sample, is the use of methods on a 'global' static object (CP) instead creating an instance of a function() and add the methods there (like the guys at YUI likes). The latter is nice in it's increased encapsulation, however the need to deal with the scoping issues is making event registration and event handlers too awkward imo.
Anyway - that's the code, you can use it as you will. Just remember it's "as-is", "no-warrenty" BSD thing.
YAHOO.ColorPicker = {};
// alias
var CP = YAHOO.ColorPicker;
CP.dialog = null;
// creates the dialog with a color picker inside
CP.createPicker = function() {
CP.dialog = new YAHOO.widget.Dialog("yui-picker-panel", {
width : '500px',
close : false,
fixedcenter : true,
visible : false,
draggable : false,
modal : true,
constraintoviewport : true,
effect : {
effect : YAHOO.widget.ContainerEffect.FADE,
duration : 0.2
},
buttons : [
{ text:"Done", handler:this.handleOk, isDefault:true },
{ text:"Cancel", handler:this.handleCancel }
]
});
// dialog markup:
CP.dialog.setHeader('Pick a color:');// placeholder for the color picker
CP.dialog.setBody('<div id="yui-picker" class="yui-picker"></div>');
CP.dialog.render(document.body);
$(CP.dialog.element).addClassName('yui-picker-panel');
// create the picker
CP.picker = new YAHOO.widget.ColorPicker("yui-picker", {
showhexcontrols : true,
showhexsummary : false,
images : {
PICKER_THUMB : "/common/javascript/yui/colorpicker/assets/picker_thumb.png",
HUE_THUMB : "/common/javascript/yui/colorpicker/assets/hue_thumb.png"
}
});
}
// in here I have used prototype to get the hex data. you can of course use
// YUI's getElementsByClassName, jQuery, or your own method.
CP.handleOk = function() {
var hexField = $(CP.dialog.element).down('.yui-picker-hex');
var hex = hexField.value;
$(CP.targetId).value = '#' + hex;
CP.dialog.hide();
setTimeout(CP.destroy, 300);
}
// removes the dialog completely
CP.destroy = function() {
CP.dialog.destroy();
CP.dialog = null;
}
CP.handleCancel = function() {
CP.dialog.cancel();
setTimeout(CP.destroy, 300);}
// create the picker if needed, set it's value, and show
CP.showPicker = function(ev) {
if (CP.dialog === null) {
CP.createPicker();
}
var target = ev.target || ev.srcElement;
CP.targetId = target.id;
var val = target.value;
if (val.match(/#?[a-fA-F0-9]{6}/)) {
if (val.indexOf('#') === 0 && val.length > 1)
val = val.substring(1);
CP.picker.setValue(YAHOO.util.Color.hex2rgb(val));
}
CP.dialog.show();
}
// registering the pickers on our color fields
YAHOO.util.Event.onDOMReady(function() {
var fields = YAHOO.util.Dom.getElementsByClassName('color-picked');
YAHOO.util.Event.on(fields, "click", CP.showPicker);
});
You can try to clean the CP.destroy method and see if it works for your scenario.
hmm, ofcourse, needed YUI files are:
When I've started using feedburner (mid Sep.) there were about 160 subscribers.
Nowadays:
Next to super-blogers like Scott Hanselman or even local blog heros like Ayende, its nothing.
But it's mine.
I can also see a very (obvious) correlation between the amount of code posts per month and the growth in popularity.
That mean that people likes reading code samples, and that they find it useful, so I'd do my best to make more of these, should time permit.
If you know not what XSS is or how easily you can expose your application to XSS, take a short read at the next posts:
AspView was written by me, for my (and my employer at the time) use. Therefore, I did not make it 'secure by default' in terms of HttpEncode.
However, seeing now that the convention lean toward outputing HtmlEncode-ed by default, I'm adapting AspView to that.
The usage would be similar to the one suggested for Asp.NET MVC at http://blog.codeville.net/2007/12/19/aspnet-mvc-prevent-xss-with-automatic-html-encoding/
So,
<%="<tag>" %>
would output
<tag>
While
<%=RawHtml("<tag>") %>
would output
<tag>
The only exception here is ViewContents on layouts. since the view contents is 99% of the times made of markup, so in the layout would still write:
<%=ViewContents %>
All of that stuff is being implemented with AspView trunk (versions 1.0.4.x) that works with Castle trunk.
If anyone wishes me to bubble it down to the 1.0.3.x branch (for Castle RC3), please leave your comments here. Unless I'll see that people actually want that I would probably not make the effort.
Not MS-Excel.
As if it was not enough that wife has graduated her B.A. with honors, now she has just given a notice that she is about to gain honors on her M.A. studies, too.
And as if that's not enough, during the course of the studies, she has been employed at 80%-100%.
And now she starts looking at doing a Ph.D.
Now I feel the urge to complete my damn Bachelor's (and I'm around 84, so no honors for me), and learn so much, and code that much so I'd become a great good better-than-I-am-now developer, and just to try and keep up.
Usually I won't just link to another's post, but this one is a very good introductory level Unit Testing 101 Article, covering basics of the idea, and basic of nUnit and Rhino.Mocks.
A must read for Unit Testing newbies.
I really do not know how I missed this thread.
So funny, so true.
http://discuss.joelonsoftware.com/default.asp?joel.3.219431.12
If ever you need to convince someone to KISS, that's the source.
And if that's not enough, you have a shorter version at http://ayende.com/Blog/archive/2007/12/18/Choices.aspx
I'm pleased to announce that the first step of AspView refactoring is over. The pre-compilation process is now way more coherent and easy to follow and to test. Soon enough, as I'll complete adding a service locator to the mix, it would also be easily extensible.
What can you do now that you couldn't have done before? Use a custom base class for views.
For example: let's say that you have created a supercool helper. You'd probably name it SuperCoolHelper. Now you register that helper on the controller:
[Helper(typeof(SuperCoolHelper))]
public class MyController ...
You can, ofcourse declare it on every view:
<aspview:parameters>
<%
SuperCoolHelper SuperCoolHelper;
%>
</aspview:parameters>
<%=MyCoolHelper.CoolStuff() %>
You can also use the DictionaryAdapter and add the helper to the base view interface:
public interface IView
{
SuperCoolHelper SuperCoolHelper { get; set; }
}...
<% Page Language="C#" Inherits="Castle.MonoRail.Views.AspView.ViewAtDesignTime<IView>" %>...
<%=view.MyCoolHelper.CoolStuff() %>
But now you can create a base class for the view:
The base class:
public class MyView : AspViewBase
{
SuperCoolHelper SuperCoolHelper { get { return (SuperCoolHelper)Properties["SuperCoolHelper"]; } }
}
A mocked class that inherit from Web.UI.Page to make intellisense play nicely:
public class MyViewAtDesignTime : ViewAtDesignTime
{
SuperCoolHelper SuperCoolHelper { get { throw new NotImplementedException("useless"); } }
}
and in the view:
<% Page Language="C#" Inherits="MyViewAtDesignTime" %>
...
<%=MyCoolHelper.CoolStuff() %>
You can mix that with the DictionaryAdapter integration:
<% Page Language="C#" Inherits="MyViewAtDesignTime<IPostView>" %>
... <%=MyCoolHelper.CoolStuff(view.Post.Title) %>
As usual: http://www.aspview.com
After reading the challenge on Dror's blog (Hebrew) I decided to post my answer here.
In short, for non hebrew readers, Dror is asking for a markup+css solution for the next layout:
no javascript allowed for layout purposes.
Oh, and the center column can be long, so the left and right columns should stretch with it.
I have added another prequisite: the center content must come before the side contents (for accessibility).
That's my simplistic answer:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional-dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Dror Engel's blog rocks</title>
<style type='text/css'>
div, body {padding:0, margin:0}
#right-column
{
background-color:#FFA
}#left-column
{
float:left;
width: 500px;
background-color:#FAF
}#center-column
{
float:right;
width:400px;
background-color:#AFF
}
div.break
{
clear:left;
}</style>
<script type='text/javascript'>
function stretchCenter() {
var center = document.getElementById('center-column');
center.innerHTML += '<br /> Blah blah blah';
}
</script>
</head>
<body>
<div id='right-column'>
<div id='left-column'>
<div id='center-column'>
<button onclick='stretchCenter();'>Streach Center</button> <br />
Center <br />
Center <br />
Center <br />
</div>
Left
</div>
right <br />
<div class='break'></div>
</div>
</body>
</html>
demo is here.
77 tests, all green.
That's all new tests from the last week.
I think it's almost stable enough for releasing it on aspview.com
I'll just put the old tests back in (with Ignore) as regression tests, until I'm comfortable enough to remove.
So - custom base classes for views are just around the corner.
Right after that - better extensibility (through custom Pre Compilation Steps provider and MarkupTransformation Provider)
you can of course watch the progress on svn (it's all on the trunk, so if you're using trunk for production, please restrain yourself a few more days ...)
stay tuned ...
Have just read Ayende's post about C#/Java vs Boo/Ruby.
Tried to comment, but then I decided it's worth a post.
I'd say that the difference is MAF - Management Acceptance Factor
Boo is also a way too cool/strange/creepy name for a distinguished suit to grasp.
It's like when you're a collage girl, and you want to introduce your new boyfriend to your mama. It doesn't matter that he has a BSc and MBA plus 3 castles in the Swiss alps. If he'd first show up to the family on his way-too-cool motorcycle, then you're going to be grounded.
When I approached my last manager about MonoRail, and told him that the views will be written in 'Boo', he got all scared. Then I wrote AspView, views to be written in c#, and he gave consent to go MonoRail.
Even though, at least at that time, Brail was way more mature than AspView.
The 'cooler' languages needs to be marketed to management.
Ruby works in Eclipse. I wonder who is going to start an OSS effort to create a decent Boo plugin for VS2008 (based on the VS2008 shell).
Make it demoable, make it look 'official', and MAF would go way higher.