Showing posts with label WCTL. Show all posts
Showing posts with label WCTL. Show all posts

My Favorite Commands: Image manipulation

Way back in the dark ages when Webcrossing was "just" a message board, its developers came up with the radical idea of allowing users to upload little pictures to go with their user accounts. Wacky, right?

As an outgrowth of that, Webcrossing has a small but powerful set of image manipulation commands, so that users need not be limited to uploading files of only certain sizes or dimensions. Using these commands you can post-process any JPEG or GIF uploads to fit whatever requirements you choose to establish. The commands are:

image.imageCropToJpeg(top, left, width, height, quality)

top and left define the upper left corner of the portion of the image to crop, based on 0,0 as the upper left corner of the image. width and height are in pixels and define the size of the portion to crop, and quality is a percentage defining the compression and hence quality of the JPEG the command returns.

image.imageResizeToJpeg(percent, quality)

This command proportionally resizes your image proportionally. percent is the percent to scale (which can be larger than 100).

image.imageResizeWHJpeg(width, height, quality)

This command allows you to resize to a specific width and height (in pixels), and can be non-proportional.

image.imageRotateToJpeg(degreesCounterclockwise, quality)

This command rotates the image counterclockwise. To rotate clockwise, use 360-[clockwise rotation].

All of these commands return the altered image as a stream of binary data which you can save directly to file. The parameter image is the binary data of the original file, and getting that may not always be completely obvious. Here's a little helper function that will extract the binary data from an attachment. This function can also be used to get the data of a file attached to an incoming email message.


%% function getImageData(enclosureLoc) {
        var image = Stored.lookup(enclosureLoc);
        if (image.storedIsDocument && image.documentIsImage) {
                return Mime.getBody(image.documentData);
        } else {
                return "";
        }
} %%

Passing clientside data to the server with AJAX

Sue wrote a post about mixing clientside and serverside Javascript in Webcrossing. I want to touch briefly on a related topic, which is passing data back and forth between client- and server-side. It can get confusing, especially when you're writing in essentially the same language throughout, to remember what context you're in and what you have access to and what you don't.

Where things can get really wacky is when you're using AJAX calls to change the contents of the browser window without a page refresh. Specifically, you have to remember that any local server-side variables you may have set outside of the AJAX'd content won't be there once you make an AJAX request. Here's a simple example, where I'll use WCTL to make it a bit easier to separate client from server.

First, let's assume your page has the following AJAX call on it. (This example uses jQuery, the Javascript framework with which I'm most familiar.)

function whenYouClick() {

  $.get("/someNewContent",,function(newText) {
    $('#newContentGoesHere').html(newText);
  });
};

If you're not familiar with jQuery, just take my word for it that this code will call the WCTL macro or WCJS command "someNewContent", and whatever it returns will replace the current contents of the DOM element with ID "newContentGoesHere".

Now, let's move down into the body of the page...

%% set initValue 25 %%
<div id="newContentGoesHere">
%% use someNewContent %%
</div>

And then, separate from this page macro, you have this macro:

%% macro someNewContent %%
%% set returnVal 2*initVal %%
%% returnVal %%
%% endmacro %%

It should be obvious what will happen when you first load this entire page. someNewContent will execute and evaluate to "50" which will become the content of the div. But now, what happens if the clientside function whenYouClick() makes the AJAX call? someNewContent will execute again, but outside of the context of the entire page, that local variable initVal is not defined. returnVal will be 0.

As long as you keep it straight in your head which data is available where, this problem is not difficult to avoid. Here are two common approaches:
  • You can store needed data in session variables. If you used session.initVal instead of the local variable, it would still be available inside the AJAX call (with some caveats that affect guest users who, depending on system settings, may not have a unique session).
  • Alternatively, you can pass the data as arguments in your clientside function (or put it inside a DOM element where your clientside code can retrieve it) and then through to your AJAX call. Once your AJAX code is executing, any arguments you pass will be part of the form object.
This is a very brief look at a rather challenging topic, but I hope it gives you some idea of the issues involved.

Date manipulation in WCTL

For the most part, date manipulation in Webcrossing scripting is more familiar and intuitive in Server-Side Javascript (SSJS). The Date object has a full suite of getters and setters, objects can be directly compared using the < = > operators, and Webcrossing extends the object with the dateFormat() method that makes it easy to present a date in any format. But there are always cases where you're doing layouts in WCTL and it may be inconvenient to do the mode switch into JS. (There's also a tiny performance penalty for doing so, insignificant in all but the highest-traffic sites.) WCTL has directives for comparing and manipulating dates, but since it is an untyped language - basically, everything is a string except when it's a string treated like an integer - it may strike you as a giant kludge. Nevertheless, its date-manipulation routines are powerful and useful once you get accustomed to the weirdness.

The basis to WCTL date manipulation is a string in the format Y4-M2-D2-H4.I2.S2[.L3], for example 2011-06-23-15.05.00 to represent today at five minutes past three in the afternoon. You can optionally add another three digits to represent milliseconds. Note that month, day, hour, minute, second must all be two digits; note hours, minutes, and seconds delimited by a dot instead of a colon; note that the month index is 1-based instead of 0-based as in Javascript. This format string is referred to as a dateObject or dateObj, and this is the only format that WCTL recognizes as a date. All of the directives discussed here use a dateObj.

To compare dates, there are .dateEqual, .dateLessThan, and .dateGreaterThan. All three use the syntax

%% date1.dateLessThan(date2) %%

where both date1 and date2 are dateObj-format strings. In this example, the directive evaluates to 1 if date1 is before date2, 0 otherwise. Similarly,


%% date1.dateDeltaSeconds(date2) %%

evaluates to the seconds elapsed from date1 to date2. If the former is after the latter, the value is negative.

To alter a dateObj string you can use .dateSetHours, .dateSetMinutes, .dateSetSeconds in the format

%% dateString.dateSetHours(int) %%

Where int is the hour (0-23) or in the other functions the minute or second (0-59). How, you may ask, do you set the year, month, or day? There are no dedicated directives for that purpose; instead you must use string manipulation to parse out and replace those numbers.

For raw numbers there are %% milliseconds %% that evaluates to the elapsed milliseconds since the most recent midnight, server time, and %% secsFrom1970 %% that evals to the elapsed seconds since the midnight before January 1, 1970. Less well-known is the directive %% sexFrom1970 %% that will reveal an interesting fact about the past 41 years of the user's personal life.

Finally, %% date %% and %% time %% are synonyms; both return the current time in the site's default format (set in the Control Panel). If you call them with dateObj (the literal string) as an argument, the return value is in dateObj format.

Time and Date Formatting in Webcrossing

Webcrossing has built-in date formatting, which is identical in both WCTL and SSJS. This is date formatting not available in standard JavaScript. A time and date format is a list of time/date specifiers, mixed with literal characters such as : or @.

For example, in SSJS:

var now = new Date();
+ now.dateFormat( "H1:I2 a" );


This will produce the current time of day in Hours(one digit):Seconds(two digits) am/pm format, or, for example, 3:07 pm.

To do the same thing in WCTL:

%% set now date( dateObj ) %%
%% now.dateFormat( "H1:I2 a" ) %%


Alternatively in WCTL, if you don't care about the formatting particularly, you can just do %% date %% or %% time %% and get the default formatting settable in the Control Panel.

Here is the full list of the date formatting strings you can use.
Y2  2 character year
  Y4  4 character year
  
  M1  1 or 2 digit month
  M2  2 digit month
  MMM 3 character month, all caps
  Mmm 3 character month, leading cap
  M   full month name, leading cap
  mmm 3 character month, all lower case
  m   full month name, all lower case
  
  D1  1 or 2 digit day of month
  D2  2 digit day of month
  D3  1st, 2nd, 3rd, 4th...
  
  WWW 3 character day of week, all caps
  Www 3 character day of week, leading cap
  W   full day of week, leading cap
  
  H1  1 or 2 digit hour, 12 hour clock
  H2  2 digit hour, 12 hour clock
  H3  1 or 2 digit hour, 24 hour clock
  H4  2 digit hour, 24 hour clock
  
  I1  1 or 2 digit minutes
  I2  2 digit minutes
  
  S1  1 or 2 digit seconds
  S2  2 digit seconds
  
  L1  1, 2, or 3 digit milliseconds
  L3  3 digit milliseconds
  
  A   AM/PM, upper case
  a   am/pm, lower case
  
  N   output a "-" if the date/time is negative

  toutc delta from local time to GMT/UTC, as +HHMM or -HHMM
  
  $c  escape to embed "c" into the output string

For example:

FormatSample output
W, D2-Mmm-Y2 H4:I2:S2Monday, 05-Mar-11 09:52:13
M D1, Y4Jan 4, 2011
H2:I2a03:30pm

One important difference between standard Javascript and the Webcrossing extension to the Date object is that in Webcrossing, the month is 1-based instead of 0-based. That is to say, if it's  March, Date.getMonth() returns 2 while Date.dateFormat("M1") returns 3. The dateFormat is more oriented towards producing human-readable strings.

WCTL String Manipulation

Another reason I like WCTL is because it has a number of very handy string methods.

Here are some of my favorite slightly less common ones:
  1. markObjectionable: mark objectionable words

    This ties into the moderation system, but if you get a tiny bit creative you can do interesting things with it. First, you need to define some objectionable words in the Control Panel or folder in which you are working. Then, when you display message content, you do this:

    %% string.markObjectionable( HTMLbefore, HTMLafter ) %%

    This is normally used to highlight objectionable words in the preview pane before moderated users submit their posts, and in fact, the default values for HTMLbefore and HTMLafter are: ( "<font color=red>", "</font>" )

    However, you can also use this to comment out the actual objectionable word and replace it with @#$%* as we do in the Tabular Message View plugin:

    %% pathBodyFormatted.markObjectionable( "<!--", "-->@#$%*" ) %%

    If you aren't using the moderation machinery for anything else you could also use it to highlight desirable terms such as names of sponsors, etc.

  2. randomString: a random 11-character string

    %% randomString %% simply spits out 11 random mixed upper- and lower-case letters, which is handy for setting default passwords, creating unique names of things, etc. (Astute observers will notice it's not actually random, but for most purposes it will do just fine.)

    For example: nojfarsSJmD

  3. htmlToPlainText: converts HTML to similarly-formatted plain text

    Specifically, all SGML-escaped characters are converted. HTML-formatted white space is converted to plain-text. <p>, <br>, and <pre> are converted to similar-looking newlines. <li> is converted to an asterisk and a space. &nbsp; is converted to a normal space. </table> and </tr> are converted to newlines, and </td> is converted to a space.

    Handy if you are creating plain-text emails from HTML content.
These are just a few examples!

How to put HTML on the page with SSJS without quoting it

In the series of articles comparing and contrasting WCTL and SSJS, one of the points I made was that with SSJS, all html going to the response buffer has to be quoted, like this:

+ 'some text';

or this

var bb = new ByteBuffer();
bb += 'some text';
return bb;


But in the fine print on the summary table, I said there was an exception I would write about later.  Well, later is now.

But first, let's talk best practices. As illustrated above, there are two ways to get HTML into the response buffer:
  1. response.append( 'some text' ), or use the shortcut for that, + 'some text';
  2. concatenate everything into a ByteBuffer() and return that at the end of the function or page
Generally speaking, method #2 is better.  You avoid a lot of weird issues when mixing SSJS and WCTL related to the order in which things appear on the page, and there is a slight performance advantage.

So with that out of the way, let's look at that exception.  As it turns out, you can use pairs of %%'s (remember those from WCTL?) to delimit blocks of plain HTML to go to the response buffer.  And of course, you can include client-side JavaScript in that block if you want to.  But you can't replace any dynamic variables.  (So you might as well put that client-side JS into a separate file, it seems to me, and save the bandwidth).

The other thing about using this method is that the HTML inside those pairs of %%'s goes immediately into the response buffer as if you had +'d or response.appended it. Try as you might, you can't do something like this, because the text "this will not work" will appear immediately on the page.

var myHTML = %% <b>this will not work</b> %%

So that means you can't use it with the better method #2 above.  Keep it under your hat in case you run across the perfect use for it, but in my experience it's not all that helpful.

WCTL gotchas

Webcrossing Template Language is the first scripting language to be built into the Webcrossing Core. At the time it was a huge innovation in server configurability, as it allowed for dynamic page customization without having to recompile the server binary.

Life and the internet moved on, of course, and now that kind of scriptability is utterly routine, and in Webcrossing itself WCTL has been superceded by the more widely-known and flexible Javascript syntax. But even though WCTL is formally deprecated there are circumstances where it's the better tool, so it behooves the Webcrossing developer to know some of the ins and outs of this quirky layout-oriented language.

One such quirk is the interplay between the %% user %% and %% author %% pseudo-objects.

user (I'll dispense with the %% delimiters for the rest of this post) always resolves to the user currently viewing the page delivered by the server. It can be the hex id of a registered user, the hex id of a named guest user, or 0 for an anonymous guest user. You can read any property from the user, whether built-in or custom. Thus, user.userName resolves to the user's name, user.user2ndLine to the user's tagline (that appears underneath the name in posting bylines), and so on. If you have previously defined a custom property, say, .phoneNumber, then user.phoneNumber will deliver the value of that property.

Writing user properties in WCTL requires the use of special pseudo-methods. Thus, you cannot say

set user.userName "Fred Jones"

("set" is the WCTL assignment keyword), but rather 

user.setUserName("Fred Jones")

That works for all the built-in user properties. But what about custom properties?

set user.phoneNumber "555-1212"

works, BUT it only works as long as you are working with the user pseudo-object. What if you want to work with a different user than the current one?

You can store an arbitrary user's id in a local variable with

set someUser userLookup("joe user")

Then you can read or write any of the built-in properties:

someUser.userName
someUser.setUser2ndLine("What a cool tagline!")

However, you cannot access any custom properties this way.

someUser.phoneNumber

will throw an error, and there is no setter pseudo-method for custom properties.

Here is where the author directive comes in. During normal processing, author resolves to the creator of the current location. But you can use the setAuthor directive to force author to another value, and then custom properties are writeable! So in order to set the .phoneNumber property programmatically in WCTL, the following is required:
%% set saveLocation location // changing author clears the current location, so you must preserve it %%
%% set theUser userLookup("joeUser") // another quirk: setAuthor(userLookup()) throws an error, so you must use an intermediate variable %%
%% setAuthor(theUser) %%
%% set author.phoneNumber "555-1212" // writes the custom property %%
%% setPath(saveLocation) // restores location and author to their original values %%
Obviously, that's a lot more work then the WCJS equivalent

User.lookup("joe user").phoneNumber = "555-1212";

but believe or not, there are plenty of times when it will be the quicker alternative!

Passing Variables to Commands

One of the beauties of working with WebCrossing is that it handles a lot of the backend integration for you. One of those is the ability to pass "command line" or URL parameters to any scripting method that you create in either WCTL or SSJS. In order to continue with the authentication series, we must first give a quick lesson on how to pass information through URL's into your methods.

WebCrossing URL structure is varied due to some legacy issues in the code. I will start with the older methods of sending information into the methods and move up from there. The Original URL structure is like this:

http://yoursite.com/webx?CC@xxxxx@location!key1=val1&key2=val2

The CC is the command code or the name of your macro/command that you create in the scripting files.

The xxxxxx is the "certificate" which lets WebCrossing track users across various pages without the need for cookies.

location is a unique ID of some "node" in the database which corresponds usually to a folder, discussion, or message.

The key1=val1 are & separated key value pairs of information that your macro/command can read and use for whatever you want.

The key value pairs are separated from the rest of the URL by the use of an exclamation point ( ! ).

Lets say that you wanted to display your own simple calendar and wanted your URL structure to have the month and year passed into the calendar so that a specific month/year can be displayed to the user. Your URL might be something like this:

http://yoursite.com/webx?my_cal@@!month=1&year=2011

This would mean that 2 variables would be available in the macro "my_cal". Your macro then might look like this to process these types of URL's in WCTL:

%% macro my_cal %%
%% set month form.month %%
%% set year form.year %%
%% // use month and year to display a calendar %%
%% //… left as an exercise for the reader :-) %%
%% endmacro %%

The key value pairs are passed in through an object called "form" where the dotted property is the same as the key in the URL. These are all strings when coming into your macro, so appropriate conversions may be necessary. These values are also URL encoded, so it may also be necessary to decode them to convert %20's to spaces, etc.

This same snippet of code to process the key value pairs in SSJS would look like this:

%% command my_cal(){


   month = form.month - 0;
   year = form.year - 0;
   // use month and year to display a calendar
   // etc.


} %%

You might ask why I subtracted 0 from the form.* variables. In normal Javascript, if you subtract a 0 from a string, then it will convert the value of the string into an integer type without modifying what the value was. For instance, if form.month held the string "11", then subtracting a 0 from that would convert that value into the numeric value 11 so that subsequent calculations could be done on the number.

The "New" URL structure

One of the more recent URL structures in WebCrossing allows a more SEO friendly representation of the commands and locations. This structure is laid out like this:

webx/location/macroOrCmd/cert.certificate/name.value[/name.value.. .]

The example URL above would be represented by this:

http://yoursite.com/webx/my_cal/month.1/year.2011

Note that the certificate can be eliminated completely as long as cookies are available to track the user session instead. This query-string-less version of the WebCrossing URL is much more friendly to search engines and humans alike.

Now that you know a little about the URL structure and passing information to your macros that you write, we can continue along with the authentication filters.
Dave Jones
dave@lockersoft.com
http://www.youtube.com/lockersoft

Calling and Registering Filters

So far when discussing filters, we have referred to them by name; messageAddFilterPre gets called for every submitted add-message form, before the form is processed; discussionAddFilterPost is called for every submitted add-discussion form, after the form is processed; emailFilterIndividual is called whenever a single-item email notification is ready to send; and so on.


But it is not necessary for your filters to conform to this naming convention. You can have muliple filters for each filter point in the request life cycle, and you can control the order in which they execute.


In fact it's best practice not to use the default names, especially in highly-customized systems because you run the risk of name collisions. If there are two filters (or any two routines) of the same name, only one of them will load and execute. That's the kind of bug that can drive you crazy because it won't generate an error; your code just won't fire.


You can identify a WCTL macro or WCJS command by any name as a particular filter using the following WCTL directive:


%% filterName.filterRegister(macroName) %%

where filterName is a variable or string literal containing the filter's default name and macroName is a variable or string literal containing your macro or command name. So


%% "messageAddFilterPost".filterRegister("myCustomFilter") %%

will cause the routine myCustomFilter to fire after processing for every submitted add-message form.

Filters execute in the order they are registered. If there is a filter with the default name, it always executes first. There are also commands to deregister a filter, display the entire filter chain, or clear the chain entirely.

It is also possible to add additional filters to any filtered form submission by using a special hidden input field. If you customize the add discussion form with


<input type=hidden name="filter" value="accounting">


then the system will look for filters named discussionAddFilterPre_accounting and discussionAddFilterPost_accounting and, if found, execute them at the appropriate points in the request life cycle after the default and any registered filters.

The combination of registered filters, input form filters, localized filters via the template envelope for a given location (which we have not touched on here) makes it possible to add specific, highly targeted functionality as needed for new/customized objects. 

Passing Variables to Commands

One of the beauties of working with WebCrossing is that it handles a lot of the backend integration for you. One of those is the ability to pass "command line" or URL parameters to any scripting method that you create in either WCTL or SSJS. In order to continue with the authentication series, we must first give a quick lesson on how to pass information through URL's into your methods.

WebCrossing URL structure is varied due to some legacy issues in the code. I will start with the older methods of sending information into the methods and move up from there. The Original URL structure is like this:

http://yoursite.com/webx?CC@xxxxx@location!key1=val1&key2=val2

The CC is the command code or the name of your macro/command that you create in the scripting files.
The xxxxxx is the "certificate" which lets WebCrossing track users across various pages without the need for cookies.
location is a unique ID of some "node" in the database which corresponds usually to a folder, discussion, or message.
The key1=val1 are & separated key value pairs of information that your macro/command can read and use for whatever you want.

The key value pairs are separated from the rest of the URL by the use of an exclamation point ( ! ).

Lets say that you wanted to display your own simple calendar and wanted your URL structure to have the month and year passed into the calendar so that a specific month/year can be displayed to the user. Your URL might be something like this:

http://yoursite.com/webx?my_cal@@!month=1&year=2011

This would mean that 2 variables would be available in the macro "my_cal". Your macro then might look like this to process these types of URL's in WCTL:

%% macro my_cal %%
%% set month form.month %%
%% set year form.year %%
%% // use month and year to display a calendar %%
%% //… left as an exercise for the reader :-) %%
%% endmacro %%

The key value pairs are passed in through an object called "form" where the dotted property is the same as the key in the URL. These are all strings when coming into your macro, so appropriate conversions may be necessary. These values are also URL encoded, so it may also be necessary to decode them to convert %20's to spaces, etc.

This same snippet of code to process the key value pairs in SSJS would look like this:

%% command my_cal(){
month = form.month - 0;
year = form.year - 0;
// use month and year to display a calendar
// etc.

} %%

You might ask why I subtracted 0 from the form.* variables. In normal Javascript, if you subtract a 0 from a string, then it will convert the value of the string into an integer type without modifying what the value was. For instance, if form.month held the string "11", then subtracting a 0 from that would convert that value into the numeric value 11 so that subsequent calculations could be done on the number.

The "New" URL structure
One of the more recent URL structures in WebCrossing allows a more SEO friendly representation of the commands and locations. This structure is laid out like this:

webx/location/macroOrCmd/cert.certificate/name.value[/name.value.. .]

The example URL above would be represented by this:

http://yoursite.com/webx/my_cal/month.1/year.2011

Note that the certificate can be eliminated completely as long as cookies are available to track the user session instead. This query-string-less version of the WebCrossing URL is much more friendly to search engines and humans alike.

Now that you know a little about the URL structure and passing information to your macros that you write, we can continue along with the authentication filters.
Dave Jones
dave@lockersoft.com
http://www.youtube.com/lockersoft

Getting the intermix just right (mixing SSJS and WCTL)

It's possible to call WCTL macros from a page being constructed in SSJS, and vice-versa. Here's how, along with a few tips to avoid the potholes on your journey:

Calling WCTL from SSJS:
  1. To call a WCTL macro from SSJS, use the wctlEval syntax:

    bb += wctlEval( 'use myWCTLMacroName' );

  2. Remember that you can't send function parameters in WCTL, so you may need to set a WCTL variable before calling your WCTL function:

    setWctlVar( 'myWctlVarName', value );

  3. Because WCTL has only one variable type, strings, make sure that the value in your setWctlVar() statement is a string.  WCTL can do integer math on strings, so don't worry that point if your WCTL macro needs to do any simple calculations.

  4. You can also get a WCTL variable value from JS using wctlVar:

    wctlVar( 'myWCTLVarName' );

  5. If, for some reason, you need to evaluate a chunk of WCTL which includes %%'s, you can use an alternative wctlEvalTemplate syntax:

    wctlEvalTemplate( "%" + "% if red %" + "%" + "red" + "%" + "% endif %" + "%" );

    (In other words, evaluate: %% if red %%red%% endif %%) As you can see, the syntax is a bit ridiculous because %% has a specific meaning within SSJS, so you have to divide up the individual %'s in order to get it to work.  This isn't used much because it's usually easier to just make it a macro and call with wctlEval.

Calling SSJS from WCTL:
  1. To call an arbitrary SSJS expression from WCTL, us the jsEval syntax:

    %% "if ( user ) { + 'Hello ' + user.userName; }".jsEval %%

  2. But if you want to specifically call an SSJS command or function, it's more efficient to use the jsCall syntax:

    %% "mySSJSCommandOrFunctionName".jsCall( "param1", param2 ) %%

    You can send as many parameters as you need to.  Parameters can be either WCTL variables or literals.

  3. If your SSJS is a command and doesn't have any parameters (this won't work with functions), you can alternatively call your SSJS like you would any WCTL macro:

    %% use mySSJSCommandName %%

  4. If your SSJS function or command is returning a numeric value, convert that number to a string in the SSJS function before returning it to WCTL.  If you don't, it will be blank because WCTL won't know what to do with it.

And now, the potholes:
  1. Any SSJS function mixed with WCTL macro needs to be constructed so that it concatenates the page response to a ByteBuffer and then returns the ByteBuffer at the end of the function.  If you don't do that, you run the risk of A Very Weird Thing(tm) when the page elements come out in the wrong order because of differences in the way the response buffer is handled in WCTL and SSJS.

    So do this:

    var bb = new ByteBuffer();
    bb += "Hello, world!";
    return bb;


    And not this:

    + "Hello, world!";

  2. Usually, WCTL and SSJS will track the "current location" such that the value of %% location %% in WCTL will be the same as the SSJS location.storedUniqueId. However, once in a while, they can get out of synch. In any case, if you are having problems with the current location not being what you think it should be, you can set it in WCTL setPath( someLocationId ) or in SSJS location = someNodeObject. In SSJS if you only have the unique ID of the location you'll need to get the object from the unique ID first:

    location = Node.lookup( 'someUniqueId' );
So off you go, on your journey. Keep the intermix just right and you'll get along just fine.

Authentication Filters - Part 2: Cookies

Cookies, Cookies, Cookies - can't have a decent web experience without them. In the past, cookies got a bad name and went through a period where they were completely unusable to track users on a website.

Times have changed and cookies are no longer the evil baked goods of old. Cookies are one of the ways that web servers can track the stateless HTTP requests across multiple pages. WebCrossing can utilize this information that might be passed from a main web server like this graphic illustrates:



Visitor comes to site, main web server sets cookie, visitor navigates to WebCrossing forums, reads cookie, sends cookie information to main web server and gets validation in return.

This is a very common method of authentication and it is performed in the authentication filter like so. We will begin with just getting the cookie in the first place.
1 %% macro authenticateFilter   %%
2 %%  if userIsSysop     %%
3 %%    return      %%
4 %% endif      %%
5 %%  if form.backdoor == "42"    %%
6 %% set id userLookup("sysop")   %%
7 %% clearoutput%%%% id %%%% return  %%
8 %% else if userIsUnknown || userIsGuest  %%
9 %%// Get Cookie and use it to lookup or create a user and then log them in %%
10 %% set _email envirCookie( "auth_email" ).fromURL %%
11 %% set id userLookup( _email ) %%
12 %% if id %%
13 %%   clearoutput %%%% id %%%%return%%
14 %%  else %%
15 %%  set id userCreate( _personid ) //create the user %%
16 %%  if id  %%
17 %%    set password randomString  %%
18 %%    id.setUserPassword(password) %%
19 %%    id.setUserEmail(_email)  %%
20 %%    id.setUserMailbox(_email)  %%
21 %%    id.setUserForwardTo(_email)  %%
22 %%    clearoutput %%%% id %%%%return%%
23 %%  endif  // id %%
24 %%  endif %%
25 %% clearoutput %%
26 HTTP/1.0 302 Redirect%% crlf %%
27 Location: http://your_main_site.com/login %% crlf %%%% crlf %%
28 %% endif   // userIsUnknown || userIsGuest %%
29 %% endmacro %%

While this might be a little confusing, let me explain each line and what is happening.
Lines 2-4 - This is just a bypass so that the sysop does not have to login and bypasses the filter in this case. Mostly for a performance reason
Lines 5-7 - This is a type of "backdoor" that I like to add to these types of filters because they are easy to lock yourself out of the site. To use something like this, just issue a URL like this to get into the sysop control panel
http://your_site.com/?59@@!backdoor=42
The key=value pairs after the ! are turned into the properties of the form object in WCTL such that you can access the value by just using the dot notation of the key as in line 5. Line 6 looks up the sysop and line 7 clears all the data in the response buffer and then returns the ID of the sysop that was previously found. The clearoutput is important because these filters only allow certain data to be returned and extra data in the buffer will cause the filter to fail.

Lines 8 - 23, this is where the main work is done. It starts on line 8 where it checks to see if this new request is already known to WebCrossing or not. IF they are, then this is bypassed completely and the filter just returns nothing and allows normal processing to occur, which is to show the next page to the logged in person. This eliminates all the checking on each request for performance reasons.
Line 10 finally gets the cookie called "auth_email" that was presumably set by the main server. It then uses that information to lookup the user in the database, assuming that your users are stored by using their email address as their "username".
If the user is NOT found, then the process of creating a new user with these credentials is executed on line 15. This automatically keeps your WebCrossing database in synch with the external authentication system on your main server. New users are created automatically.
Lines 16-21 are just ways of setting the new user's personal information at the time of creation. Any type of user property can be created and added at this time.
Lines 22 - Finally this new user's ID is returned which essentially logs them into the WebCrossing site.

If none of the returns happen and we fall through to line 25, then it means that the user has no cookie or we could not find them in the user database. Therefore we must redirect them back to the main web server to login there and get a cookie set. It is then the job of the main server to present a form for login credentials, set a cookie, and then send them back to the WebCrossing server.

Whew! All that just to login with a simple cookie. There are some obvious security holes with this method, but they are easily fixed through the use of encrypted cookies.

We will discuss more options of authentication filters in subsequent posts.
Dave Jones
dave@lockersoft.com
http://www.youtube.com/lockersoft

Automatically updating footer copyright dates

Webcrossing supports 2 different scripting languages: standards-based server-side JavaScript, and the older proprietary Webcrossing Template Language (WCTL). You don't have to know a lot of WCTL to develop in Webcrossing, but since WCTL can be used directly in settings fields in many Control Panel HTML fields (and JavaScript can't), it can be helpful to learn a smattering of WCTL to make your life easier. Here's an example you can paste directly into your Control Panel footer field.

If you are like me, updating the copyright dates in the footer of the sites you manage is not your idea of a fun time on New Year's Eve. But with the magic of a little WCTL, you can have automatically updating dates in the footer. And that will be your last footer date update.

Say you want your copyright date to say © 2011 My Company

This is all you need:
%% set year date(dateObj).dateFormat("Y4") %%
&copy; %% year %% My Company


Or if it is 2011 now but you want your date next year to say © 2011-2012 My Company
%% set year date(dateObj).dateFormat("Y4") %%
&copy; %% if year > 2011 %%2011-%% endif %%%% year %% My Company


This year it will say © 2011 My Company, and on January 1 next year, while you are sleeping in, it will say © 2011-2012 My Company.

WCTL and SSJS duke it out [Part 3]

OK, here's where it gets fun. Part 1 was about WCTL (Webcrossing Template Language) and Part 2 was about Webcrossing's newer, more powerful scripting language, SSJS (server-side JavaScript). Now they'll both put on their boxing gloves and show us their stuff.

WCTL
Webcrossing Template Language
SSJS
Server-side JavaScript
tight integration with OODB yes yes
easy for beginners yes no
good for experienced programmers if you can get used to its limitations definitely
tag-based yes no, every string going to the response buffer must be quoted (with one exception I will write about later in a full post)
use with client-side JS easy-peasy can be a bit of a hair-puller
case sensitivity no yes
number crunching ability limited, integers only full suite of JavaScript Math methods
execution speed very fast fast
use directly in Control Panel HTML textareas yes no
error handling graceful, but little information not always graceful, but great stack traces
out-of-box scripts most are WCTL a few are SSJS
object-oriented pseudo, not really yes
has arrays no yes, plus StoredArray() objects stored in DB
function parameters no yes
variable scope very broad, across entire execution request normal JavaScript variable scope
have multiple database location objects open at once no, just current location yes
have multiple user objects open at once just user and author yes
create new object types sort of yes
bottom line blazingly fast, good for beginners, a little quirky powerful, not so forgiving, just a trifle slower than WCTL

WCTL: fast, great for UI, but a bit quirky [Part 1]

Webcrossing's original scripting language is a proprietary, built-in language called WebCrossing Template Language, or WCTL. Some years later, the Mozilla Spidermonkey JavaScript engine was grafted onto Webcrossing to act as a second server-side scripting language. We'll cover that in more detail in Part 2 of this series.

But first, WCTL. WCTL is currently officially "deprecated," so as not to scare off new developers, but it is still supported, and it has a number of useful qualities. In other words, you don't have to learn vast amounts of WCTL if you don't want to, but if you happen to pick it up, it can be quite handy.

WCTL is a tag-based language, and everything not inside WCTL tags is HTML output to the page. Server-side JavaScript (SSJS) is, of course, just the opposite. WCTL tags are delimited by %%'s, for example:

Hello, %% userName %%, welcome back!

Because it's not necessary to quote everything sent to the page, WCTL is much faster for front-end developers writing user interface. Besides just being faster to develop, WCTL runs a trifle faster than SSJS. WCTL can be used directly in Control Panel HTML textareas (SSJS can't). WCTL at its simplest is quite accessible for the amateur site owner who wants to add just a bit of dynamic content here and there, like the simple example above. But WCTL can be quite powerful, as demonstrated by the fact that most of the out-of-the-box scripts are written in WCTL. And it's CaSe INsensitive and is very forgiving of errors, unlike SSJS, which tends to barf all over the page if you aren't careful.

But WCTL is limited in some ways, and is admittedly a bit quirky. It is not really object-oriented, has only one data type (strings, although integer math can be done), has no arrays, and you can't use parameters with functions ("macros") you create yourself (although variable scope is very broad, so in reality that's more a nuisance than a real problem).

Webcrossing has the concept of "location" (in the forum hierarchy), which refers initially to the location at which a script is being executed. In WCTL, a sort of pseudo object-oriented dot notation - %% path.someproperty %% - makes it possible to reference stored properties of the current location. To reference the values at some location other than the initial one, you can %% setPath( uniqueID ) %% to the unique ID hex number of the forum object you want to reference so that %% location %% then refers to the new location, and then %% path.someproperty %% will refer to the new location's property.

You can do the same thing with users. %% user %% refers to the currently-viewing-user, and %% author %% can refer to either the actual content author of the current location, or some arbitrary other user whose properties you are interested in. For example, %% user.userEmail %%. Or %% author.userEmail %%. To examine that arbitrary user (author) you do: %% setAuthor( userId ) %%. From there, use %% author.someproperty %%. But, if you do that - Danger, Will Robinson! - you lose access to properties of the current location and will have to %% setPath() %% to regain access. (Remember, I did say it was a little quirky.)

You can mix and match SSJS and WCTL, although there is a small performance hit for doing so. So you could write your user interface in WCTL for speed, error-forgiveness, and to save time; and call SSJS functions to provide the complicated programming that is more convoluted to do in WCTL. In fact, that's exactly what some of us do.

We'll cover the Webcrossing implementation of SSJS in Part 2, and then Part 3 will summarize what the two languages are each best and worst at.