User Tools

Site Tools


Sidebar

x2web:developer

Developing for X2Web

X2Web is the web interface system for XTension. It is a “preprocessor” for web pages and provides a relatively easy way to make custom interfaces to your house or other systems for display and control. The program ships with several, in browser editable templates that I called “instantx” that can get you up and running in a modern browser or on an iPhone in a hurry and without having to mess around with any html at all. All configuration of the data is handled in the browser. But for some people that wont be enough to satisfy or you’ll want to support a strange or early device and want to roll your own. This is completely possible and I’ll detail the tools available in X2Web and how to use them below.

Under The Hood

X2Web uses Apache as the web server. This is both good in that you get a time tested and regularly updated and security patched web server to handle everything but also can be a pain in that many of those changes and updates can break our configuration. X2Web needs 3 things (apart from the .x10 files) to work. The program itself which can be placed anywhere but might want to live inside a folder in your home folder or inside the applications folder (NOTE: due to legacy old school programming hold over from the pre-osx days the program still wants to make some folders for logs and such INSIDE the same folder it’s living in, so placing it naked in your applications folder the way most apps do is not a good idea. Create it a folder in there and put it in that instead or anywhere else in your user directory that is handy.) Then there is an apache configuration include file. Every version of Apache has a folder somewhere in it’s configuration directory where it will include any files ending in .conf X2Web creates one called x2web.conf and during the apache configuration process places it where you told it to. most times this gets it right, but if you’re running OSX server you may have to re-arrange things. This file contains only 3 or 4 lines of text that tells Apache that it should send the request to X2Web if the file ends in .x10 or .scpt. If you get unparsed .x10 files from apache without the scripts running then it’s likely this file that is not in the right place. The last part is the cgi stub program that needs to go into the cgi-bin folder. This is a simple app that just lets apache launch it as a regular cgi program and forwards the streams of data back and forth between apache and X2Web. That program comes and goes with every hit from the browser while X2Web stays running all the time. (yes, there are better ways to do this, fcgi for instance, but getting that configured and keeping it running turns out to be an order of magnitude more complicated)

Hello World

just to make sure your install is working you can do something like this saved into a hello.x10 file

<html>
  <body>
    <h1>This is a test of X2Web</h2>
    
    <AppleScript>
      return (current date)
    </AppleScript>
    
  </body>
</html>

If that replies with the current date/time displayed then it’s all working and you’ve gotten a script to run. Everything else is just passing data around and working with template data and filling in things to make it easier to display them and make them work.

External scripts

Editing complex apple scripts in an html editor is a nightmare, so dont. Use the XScript tag to run a script out of an external script file that you created and saved in the script editor.

<XScript path=“hello.scpt” handler=“dohello” data=“” />

will run a handler in a file in the same folder as the .x10 script so you can keep them separate and easy to edit. The data= parameter is optional and you can include it as many times as you need to in order to pass data. They will go in order to the handler in the script like:

<XScript path=“hello.scpt” handler=“datademo” data=“XTension” data=“is” data=“superior” />

will run a handler like this:

on datademo( ParamOne, ParamTwo, ParamThree)
  return “you passed me: “ & ParamOne & “ “ & ParamTwo & “ “ & ParamThree
end datademo

You can also directly link to a script in the browser and have it run and any data that results will be sent to the browser.

http://localhost/path/to/MyScript.scpt/handlername

Getting and Setting Properties in Scripts

Properties (variables) in appelscripts hang around and can be accessed after you run a handler, or set before you run a handler. X2Web will not preserve them between relaunches though so they aren’t good for persistent storage of information. There are X2Web tags for getting them and inserting them into a .x10 file going to a browser and also for setting them:

<XScript path=“MyTestScript.scpt” property=“SomePropertyName” />

will include in the html at that point whatever value is assigned to SomePropertyName in the script.

property SomePropertyName: “this would be returned”

Code for setting a variable in a tag is the same but includes the value parameter like:

<XScript path=“MyTestScript.scpt” property=“SomePropertyName” value=“The New Value” />

the ImportScript verb

It may be useful to include handlers from other scripts into the current one you’re working with to have often user handlers available without duplicating code in each script file you want to create. The ImportScript verb is low overhead and once called allows you to use handlers from one script in another as if they were local.

ImportScript “../relative/path/to/includeScript.scpt”

It doesn’t actually import and recompile the script or any such thing, just retrieves (or loads if necessary) the script object from memory and places it in the handle event queue so any call that you make to your script that isn’t handled there is passed through the list of included scripts until something handles it or an error is produced. Local properties of the imported script are not available this way, use a handler to get/set them if you need to do this.

Working With Forms

X2Web provides numerous tools for parsing form elements and this is the main way that everything can talk to each other. The GET and POST variables all end up in the same dictionary from which you can pull out values by name.

set MyValue to getFormVariable “name”

will retrieve name=value from either a get or post form variable. Apache environment variables are also included in the dictionary here so you can also get things like “QUERY_STRING” or “REMOTE_HOST” as well as any that have been passed by the form or xhtml request.

This verb is available to any script or included script or linked script in the chain. So if you call an external script via the XScript tag then it can call getFormVariable and pick up form variables from this particular hit.

Working with Sessions

X2Web sets a temporary session cookie with each unique browser that hits it. This session is maintained for some time and you can store applescript variables in it that can be recalled from a script running in the next hit from that person. These are maintained and removed automatically.

SetSessionVar “IsAuthenticated” to true
if not (GetSessionVar “IsAuthenticated”) is true then...

or something like that. The structure passed does not have to be a string, it can be any applescript value, integers, strings, lists, records even entire scripts or script objects if you’re feeling like an applescript power user.

Working with Folder Variables

A “Folder Variable” is sort of the opposite of a session variable. While session variables are unique to each user and go away when they do, a folder variable is like a tiny database of applescript objects that stay the same for the FOLDER in which you have placed your .x10 script. I use these to store the persistent configuration data of the instantx pages.

SetFolderVar “theName” to {“some applescript Object”, “and another one”} in “../relative/path”

the “in” parameter is optional and will default to the same folder in which the script is running. This again will hold any applescript object at all, not just strings. The ability to store records and lists is particularly useful. GetFolderVar operates similarly:

set MyConfigData to GetFolderVar “theName” from “../../optional/path”

Including Other Pages

You can include bits of other processed .x10 pages. I use this ability to build up the dynamically generated instantx pages from the myriad of available little bits. You can also pass them form data in addition to the copy of the same data that your host page has. The verb can be called in any script and takes a relative path to the page you want to include. It should be an .x10 page.

IncludePage “../relative/path/toPage.x10” WithData {{“name”, “value”}, {“more”, “data”}...}

which will include in the output of the html at that point any output generated from those pages. The WithData is optional and is a list of lists which will be converted into form data passed to the new page as if by a form. So you can use the GetFormVariable verb to work with it there and that page will never know if it was called from an Include or directly from the browser. All other relative paths in the included page will be as if it was called directly, so they wont break if called from an include.

Inserting Data into the Page

There are many ways to get your data onto the page. You can just return it from various scripts that you embed or call remotely. YOu can setup a bunch of script properties with the values in a single XScript call and then use the property access XScript ommand to pull them into wherever they belong or also the replacePageTag verb.

replacePageTag tag “thename” value “the value”

will replace any instance of [thename] or <thename> on the page with “the value” replacing multiple instances if they are there.

You can replace a whole bunch of tags at one time with this verb too it will accept a list of lists the same way we passed to the IncludePage verb above. So if you have gotten a bunch of data to replace it will be faster to do it as a list like:

replacePageTag {{“name”, “james”}, {“condition”, “exhausted”}...}

That means that you can build up a list of values in your script for things dynamically generated like status, background color, selection state and whatnot and keep adding new list elements at the end of the final one and then do all your inserts in a single command.

The replacePageTag verb also supports the “within” parameter which will replace the tags in the passed string and return it to you rather than place it on the page. This is very useful for building lists of repeating parts or for getting data off the page, parsing it and returning it to the page like:

set MyData to ReplacePageTag {{“name”, “value”}, {“more”, “data”}...} within “[name] is very [something]”

In order to not have to embed blocks of your page to parse in the script you can use the:

GetTagContents “tagname”

verb to get the value out of the .x10 page, parse it and return it. If the .x10 page contained something like:

[TagLine]My Name is [name] and I am [status].[/TagLine]

then you could get that for processing from within a script like:

set WorkLine to GetTagContents “TagLine”
set ProcessedData to ReplacePageTag {{“name”, “james”}, {“status”, “tired”}} within WorkLine
return ProcessedData

that also works great in loops to build up long lists of data that you’re going to have to format into tables or whatever. It also means that the WorkLine can be saved in the .x10 file for easy editing rather than inside the script file.

The XLoop system also makes the creating of repeating lists easier. You create the inserted data in an applescript list and then pass it in one command to the xloop to be repeated as many times as you have data. For example if you have a .x10 file that has something like:

<ul>
  <XLoop name=“PeopleList”>
    <li>[1] is [2]</li?
  </XLoop>
</ul>

it’s very simple list with 2 numbered tags embedded in it, to fill that in you’d do something like this in a script:

set MyLoopData to {{“James”, “Tired”}, {“Michael”, “goofy”}, {“bill”, “short”}}
doLoop “PeopleList” listdata MyLoopData

and the line in the XLoop will be repeated for each list element in the list replacing the numbered tags with the indexed list values.

The XLoop data can also contain named parameters instead of numbered ones but you must then also include the order that the list names come in so:

<ul>
   <XLoop name=“NamedPeopleList”>
       <li> [PeopleName] is [PeopleCondition]</li>
   </Xloop>
</ul>

would be worked like:

set MyLoopData to {{“Tired”, “James”}, {“Goofy”, “Michael”}, {“Short”, “Bill”}}
doLoop “NamedPeopleList” listdata MyLoopData listnames {“PeopleCondition”, “PeopleName”}

so PeopleCondition becomes the first value and PeopleName becomes the second in the data. So in this case even though they are backwards in the list, they will fill in the proper values.

Working With XTension

Though you can certainly do all your work with XTension via scripts, a lot of work is done for you by X2Web which keeps a local cache of all the unit status and information so that you can call it up without a context switch to XTension and such. You can also get the uniqueID of the units to make controlling them easier. In any XTension verb that accepts the name of a unit you can replace it with the uniqueID of the unit. The unique ID will always be a simple number so you can include it into a form or otherwise pass it around between the browser and the scripts and it wont get messed up while if a unit name happens to contain reserved characters or quotes or amperstands or something it might completely hose up your system to try to manage it.

Any data about a unit can be accessed and included via the <XTension> tag:

<XTension param=“time delta” unit=“furnace” format=“short” />

would return a short time formatted version of the timedelta for the unit furnace. Timestamp can be: [short|long|none (just returns the number of seconds)|long time|long date|short time|short date|abbreviated date|.

other params that you can ask for are:

 status (returns “on/off” unless you also include alternative labels by adding return=“open:closed”)
 value
 timestamp
 description
 

If you need the information for use in a script use the GetUnitRecord command like:

set ExtractRecord to GetUnitRecord “name of unit” --or uniqueID of unit

These are the same named record properties that are defined in both the X2Web and the XTension dictionary. So you can do things like:

set TheLabel to xtCurrentLabel of ExtractRecord
set TimeDeltaString to xtTimeDeltaString of ExtractRecord

You could combine this with an XLoop and make a unit status display page fairly easily.

Using X2Web with Graphical Layout programs

It can be a pain to use a graphical layout program that doesn’t know anything about the tags that you’re using, but many will allow you to set a tag prefix that it will then recognize as code it needs not to change, like working with active server pages or something. All the tags that X2Web uses are parsed twice upon the first loading of the page, so you can use either carrots or []’s to define anything. Additionally if you include on the page a tag prefix like:

<TagPrefix asp:>
  or
[TagPrefix asp:]

then all tags on the page will require that the tags start like:

<asp:AppleScript>return (current time)</asp:AppleScript>

Example XHTML requests

coming shortly…

x2web/developer.txt · Last modified: 2011/09/28 14:52 (external edit)