Getting Google Chrome to open notes:// links correctly

If you work at a forward thinking organisation or use Google Chrome yourself you soon come across a slight annoyance where notes:// links do not launch the Notes client to the correct document.

Certainly for me, clicking on a doclink or URL previously would result in nada or chrome would helpfully suggesting searching for it.

My solution is a bit of a hack:

Shut down Chrome and in Windows edit the following file:

C:\Users\<USER>\AppData\Local\Google\Chrome\User Data\Local State

**Thanks to Roy Rumaner for pointing out I had left the filename off

You can see this is actually a JSON formatted file – within it there is a section called:

"protocol_handler": {
      "excluded_schemes": {
         "afp": true,
         "data": true,
         "disk": true,
         "disks": true,
         "file": true,
         "github-windows": false,
         "hcp": true,
         "javascript": true,
         "mailto": false,
         "ms-help": true,
         "news": false,
         "nntp": true,
         "notes": false,
         "shell": true,
         "snews": false,
         "spotify": false,
         "vbscript": true,
         "view-source": true,
         "vnd": {
            "ms": {
               "radio": true
            }
         }
      }
   },

Add the “notes”:false section as indicated and then save and restart Chrome.

That should be it.

Comments (7)

Domino Authentication – returning JSON data on failure

policeman

Though Domino AJAX type authentication has been done to death – I did my first post on this along with Jerry years ago, one thing has always bothered me and that’s the return from Domino if there is an issue. i.e. incorrect password, not authorised etc.

NB This solution assumes you want to authenticate with Domino but not have to use a Domino generated Login form.​

Various Solutions

Various bloggers – ​Jake, Declan and more have suggested various ways in handling the return from Domino and I believe in 8.54 oAuth might be supported but if you have access to the domcfg database on the Domino sever there might be a simpler way.  Somebody might have already blogged this or its so obvious no one has bothered but still…

Suggested Solution

In the Domino Configuration database (domcfg) you can create an entry to point to a custom login form – I assume you are using Session based authentication.  Create this entry to point to a new form within your application.  The easiest way is to just copy the existing $$LoginUserForm from the design of the domcfg.nsf​ (It needs to have Read Public access on it and your ACL needs to allow anonymous users to have Read Public access).

Edit this form and change the form properties content type to application/json​

propertybox

Next copy the computed value and then get rid of the rest of the form except for the hidden fields at the bottom.

​Finally add some JSON text to wrap around the computed value:

 

 

 

{"loggedin":false,"loginError":"<Computed Value>"}

 

The Redirect

The next thing to add is somewhere for the redirect to point to.  This could be anything but I find a simple page with a content type of application/json along with the following JSON data works for me.

{
"loggedin":true,
"user":{
"username":"<Computed Value>",
"accesslevel":"<Computed Value>",
"delete":<Computed Value>,
"roles":[<Computed Value>]
}
}

The Result

​The actual usage is now trivial, from what ever client technology  (assuming it can work with JSON data) you are using perform a normal HTTP Post to your custom database using the URL http://myserver/mydb.nsf?login and pass username, password and redirect values as parameters.  Check the return result, if the loggedin property is present then check to see if its false, if it is then display loginError else in my case I can hold a reference to my user object which is returned on the redirect.

Session timeouts

By default sessions timeout on Domino​ in 30 minutes and though this can be changed you should cover yourself for the event a session has timed out.  NB This is probably more of an issue for desktop technologies like Adobe Air or Chrome extensions.

The best method is to always check any AJAX calls to the Domino server for the existence of a loggedin property and if it exists is it false?  If it is then the user is not logged in so proceed with your login process.​

Leave a Comment

Building a Custom Spark Component for Adobe Flex

Gears

Its taken me a while but I believe I have started to understand the new skinning architecture in Adobe Flex 4 and this blog article describes how to build a reusable custom component taking advantage of the architecture.

This custom component is simply a useful loading animation along with an optional loading message.  I often find myself loading remote data (usually from Domino) into multiple panels within an application and its good UI practice to give feedback to the user that the application is doing something.  Normally I would change the cursor to a busy indicator which is ok but not ideal, especially if your loading multiple panels with different datasets.

The aim is to have a custom component which will indicate something is loading for that specific pane so if you have multiple panes loading different data they will each have there own indicator.  The component will work with any standard Flex Spark container (Panel, Group etc).

Heres a quick demo so you can see in advance what the end result is (view source enabled).

The demo simulates the loading of data by using 2 buttons to kick off a load event and data loaded event.  Obviously these 2 events are normally controlled by your application and I would recommend looking at AS3 signals & Robotlegs as good frameworks for controlling this process.

Building the Component – first the state logic.

Our component needs to have 3 states – the default state, the loading data state and the data loaded state.

This state information needs to be passed to the skin so it can change its appearance basedon these states.

The component will consist of a simple custom component built in actionscript which will be responsible for passing the state information to the skin as well as having an optional loading title.  The other element will be the Skin file which is responsible for how the component looks in the 3 different states.

The actionscript component extends the SkinnableContainer which means we can wrap the component around any standard Flex container e.g.

<container:LoadingPane skinClass=”shinydesign.skin.LoadingPaneSkin” id=”loadingPanel” height=”300” width=”400” loadingTitle=”Loading Demo Data>

<s:BorderContainer left=”5” right=”5” top=”5” bottom=”5” cornerRadius=”5” backgroundColor=”0xcccccc></s:BorderContainer>

</container:LoadingPane>

We need some extra custom states in our component and the skin needs to know about them, to do this you add some meta data to the top of the class, in this case I have added 2 new states – loading and dataLoaded.

[SkinState("loading")]

[SkinState("dataLoaded")]

public class LoadingPane extends SkinnableContainer

If you were building your component in MXML you would do the following

<fx:Metadata>
        [SkinState("loading")]
        [SkinState("dataLoaded")]
</fx:Metadata>

Next we have some properties which are used to set the current state.  NB you don’t use the normal method of setting a state component.currentState=  instead you use the setter on the desired property, in this case component.loading=true.

public function set loading(value:Boolean):void

{

if(_loading !=value){

_loading=value;

_dataLoaded=false;

invalidateSkinState();

}

}

This method first checks to see if the value is different then sets it if it is, it then changes the dataLoaded property to false (because we are now loading in new data) and finally it calls the standard invalidateSkinState method.  This methods forces the skin to reevaluate its skin state.

When the skin does its evaluation it will call the standard getCurrentSkinState method on the host component, therefore we override it so we can return the state value we want.

override protected function getCurrentSkinState():String {

if(dataLoaded)

return ‘dataLoaded’;

if(loading)

return ‘loading’;

return super.getCurrentSkinState();

}

In this case if dataLoaded = true then we return the string ‘dataLoaded’, if loading = true we return ‘loading’.

Optional Loading Title

To allow a developer to use there own custom loading messages we need to have a custom skin part in the component – in this case we have made the skin part optional.

[SkinPart(required="false")]
 public var LoadingLabel:Label;

We have a string property -loadingTitle on the compoent which is used to set the text value on our LoadlingLabel – this property can be set either through MXML or through actionscript.

<container:LoadingPane id=”dataLoadingPane” loadingTitle=”Loading Demo Data>

 

dataLoadingPane.loadingTitle=“Loading Demo Data”

We then override the event partAdded to check to see when the LoadingLabel is added to the Skin – at this point we can set the text property of the label.  NB This is one way of doing this there are other ways.

//Add the loading text if the label is being added to the skin

override protected function partAdded(partName:String, instance:Object):void {

super.partAdded(partName, instance);

if (instance == LoadingLabel) {

LoadingLabel.text=loadingTitle;

}

}

The Skin

The Skin is a separate file which holds the UI for our component.  The idea being this separation of logic and UI means I could easily apply a different skin if I wanted to.

The Skin itself needs to be based on our custom component and we need to add our additional custom states (NB normal and disabled are the default inherited states).

<fx:Metadata>[HostComponent("shinydesign.container.LoadingPane")]</fx:Metadata>


<s:states>

<s:State name=”normal/>

<s:State name=”disabled/>

<s:State name=”loading/>

<s:State name=”dataLoaded/>

</s:states>

I then added a Label for the loading title – this ties uo with the optional SkinPart in the Custom Component – LoadingLabel – NB The ID of the label must match the ID in the custom component.

The actual loading graphic is a small Flash Movie – We are using the Flash Player already so why not?  You use a SWFLoader to load a Flash Movie within a Flex Application.  NB the movie has already been embedded within the Flex Application and is not loaded from an external source.

[Embed(source="shinydesign/assets/GearsSmallMovie.swf")]

public static const Gears:Class;

<s:SWFLoader source=”{Gears}” width=”100” height=”100” id=”loadingGraphic“  alpha.dataLoaded=”0” alpha.loading=”1/>

The contentGroup Group is the standard area that is used by Flex to display any content which is within the container.

i.e. in this case the BorderContainer component will be within the contentGroup Group.

<container:LoadingPane skinClass=”shinydesign.skin.LoadingPaneSkin” id=”loadingPanel” height=”300” width=”400” loadingTitle=”Loading Demo Data>

<s:BorderContainer left=”5” right=”5” top=”5” bottom=”5” cornerRadius=”5” backgroundColor=”0xcccccc></s:BorderContainer>

</container:LoadingPane>

The Skin Effects

Like any good Flex application there is a subtle use of effects to cause a Fade between the loading graphic and the actual content.

This is done by the use of State Transistions.

<s:transitions>

<s:Transition fromState=”loading” toState=”dataLoaded>

<s:Sequence>

<s:Fade target=”{contentGroup}” startDelay=”300/>

<s:Fade target=”{loadingThrobber}/>

</s:Sequence>

</s:Transition>

<s:Transition fromState=”*” toState=”loading>

<s:Sequence>

<s:Fade target=”{contentGroup}” startDelay=”300/>

<s:Fade target=”{loadingThrobber}/>

</s:Sequence>

</s:Transition>

</s:transitions>

In my case I have targeted when the state is changed from loading to dataLoaded and from normal to loading.

The recommend method is to put the actual property values that will be changed within the component and just use the transitions to trigger the change.  You can see an example here.

<s:Group id=”contentGroup” alpha.loading=”0” alpha.dataLoaded=”1” left=”0” right=”0” top=”0” bottom=”0” minWidth=”0” minHeight=”0” includeIn=”dataLoaded>

<s:layout>

 

In this case I have set the alpha property for the loading state to be 0 on the contentGroup (in other words hidden) but for dataLoaded its set to 1.  Because its a fade transistion it will animate between the 2 alpha values.

The syntax for this is PROPERTY.STATENAME

An important extra is the startDelay property of the transistion.  I used this to force a consistent minimum delay before the loading graphic is faded away.

If you don’t do this then when the data loads very quickly you can end up with jarring / blinking effect.  It seems slightly strange to slow down the display of the data but in the end the experience is much smoother.

Grab the Source

The SWC & source code is available here on GitHub.

 

 

 

Leave a Comment

Quick video of a Flex App reading X Page generated barcodes

Further to the previous blog entry I have done a quick video to demonstrate the Flex App reading the barcodes which have been generated by an X Page.

Saves having to print off the barcodes or you might not have access to a webcam.

Leave a Comment

Creating Barcodes with an XPage / Reading them with Flex

barcode2

Barcodes you have to love them, those little digital pictures can make life a lot easier when trying to tag a multitude of things but still be machine readable.

Already smart phones along with cheap / integrated webcams are putting potential barcode scanners at everyone’s fingertips, what we need is an easy way to create the barcode and then read it.

2D Barcodes

2D Barcodes like the Datamatrix and QR Code can encode a reasonably large amount of information, certainly enough to hold a unique key.

Creating a barcode with an XPage

Due to the ability for an XPage to easily leverage Java code it is quite straightforward to integrate an existing Java library, so when the XPage is called a rendered barcode is returned.

For this demo I have decided to use a commercial library – the code will operate in a demo mode and is reasonably priced if you decide to buy it.  For this demo I am only interested in the Datamatrix barcode so I downloaded that specific Jar file from here.

Setting Up

There are plenty of other great blogs which explain how to use existing Java libraries with X Pages – so I won’t go into any great detail here.  Heres a very good example from Stephen Wissel in fact I used his example as the basis for generating the barcode.

Image Format

PNG, GIF or JPEG?  If you decide to go for PNG or GIF as your file format you need to download some additional JARs which also need to be added – for PNG here, for GIF here.  Just make sure you have added to the them to the database the same way as the barcode Jar file.

I decided to use the PNG file format.

The XPage

Similar to Stephens example you need to make sure you add your SSJS to the beforeRenderResponse event of the XPage – this way we can return what we want back to the user.  This SSJS will call a java class which actually generates the barcode.

Note this code has been tested on a 8.52 server.

The SSJS code looks like this:

// Get the output stream
var exCon = facesContext.getExternalContext();
var response = exCon.getResponse();
var out = response.getOutputStream();
 
if (out==null) {
  print(&quot;No Stream&quot;);
} else {
  print(&quot;All good with the stream&quot;);
}
//Get key from URL
var key = (param.key || &quot;&quot;);
print(&quot;Encoding: &quot; + key);
 
// Set the MIME Type to image/PNG
response.setContentType(&quot;image/png&quot;);
response.setHeader(&quot;Cache-Control&quot;, &quot;no-cache&quot;);
 
//Instantiate the BarcodeGenerator class
var bar:shinydesign.BarcodeGenerator=new shinydesign.BarcodeGenerator();
//Example setting a width property
bar.setImageWidth(400);
//Call the generate method passing the key and the output stream
bar.generateBarcode(key,out);
 
// Stop the page from further processing;
facesContext.responseComplete();
out.close();

The Java Code

The Java code is not production ready (no error handling etc) so use at your own risk.

The class has some properties which allows you to set the height and width.

The main method – generateBarcode is passed the output stream and the code which needs to be converted to a barcode.  Remember in this case I am only interested in the datamatrix barcode and the image format is PNG.

In my case I wanted to not only stream the PNG back to the browser but I wanted to save a copy of the image on the file system (under the servers HTML directory).

This way in a real app I could generate a barcode for a document, return it live to the user and then when the document is saved attach the image to the document.  This means on subsequent viewing there is no need to generate the image again.

Add the following class within the shinydesign package:

package shinydesign;
import java.io.FileInputStream;
import java.io.File;
import java.io.OutputStream;
import java.io.IOException;
import com.java4less.rbarcode.*;
 
public class BarcodeGenerator {
 
	public String filename;
	private int imageWidth=200; //Default width for image
	private int imageLength=200; //Default height for image
	private boolean imageSaved; //Whether the class was successfull in saving the image to the filesystem
 
	public boolean isImageSaved() {
		return imageSaved;
	}
 
	public int getImageWidth() {
		return imageWidth;
	}
 
	public void setImageWidth(int imageWidth) {
		this.imageWidth = imageWidth;
	}
 
	public int getImageLength() {
		return imageLength;
	}
 
	public void setImageLength(int imageLength) {
		this.imageLength = imageLength;
	}
 
	//This method generates a Barcode image and stores it on the server filesystem it then returns the image filename
	public void generateBarcode(String code,OutputStream out) throws IOException{
 
		// create barcode
		com.java4less.rdatamatrix.RDataMatrix bc=new com.java4less.rdatamatrix.RDataMatrix();
		bc.barType=com.java4less.rdatamatrix.RDataMatrix.DATAMATRIX;
		bc.code=code;
		bc.checkCharacter=true;
 
		// work with pixels
		bc.X=1;
		bc.resolution=1;
		bc.topMarginCM=5;
		bc.leftMarginCM=5;
		bc.setSize(imageWidth,imageLength);
 
		//Save image to file system
		//In this case a subdirectory under the servers HTML drectory - using PNG in this case
		BarCodeEncoder  bce=new BarCodeEncoder(bc,&quot;PNG&quot;,&quot;data/domino/html/app1/file&quot;+code+&quot;.png&quot;);
		//Set a property with the result of the PNG encoding
		this.imageSaved=bce.result;
 
		try{
			   File file1 = new File(&quot;data/domino/html/app1/file&quot;+code+&quot;.png&quot;);
			   FileInputStream fs = new FileInputStream(file1);
			   byte[] byteArray = new byte[(int) file1.length()];
			   fs.read(byteArray);
			   fs.close();
			   out.write(byteArray);
			  }catch(Exception e){
			   return;
			  }
	}
 
}

Getting the Image

To display the barcode simply use the a normal HTML Image Tag like this:

<img src="http://192.168.1.30/barcodedemo.nsf/test.xsp?openxpage&key=Shiny Design"/>

Where test.xsp is your XPage which calls the Java Code and the key is the string that you wish to encode into a barcode.

The Gotcha

Currently there is an issue if you try and put multiple image tags on the same page – as an XPages beginner I am not sure quite what the problem is but the code will not render all of the images.  This is not a problem if you use the attach image method described above as you could just reference the stored files.

Using the Barcode

The following Adobe Flex application will read a generated Datamatrix barcode and display the result.

jungledragon

First print off some test datamatrix barcodes which I have encoded using the above technique.  Each one should bring back some information based on the amazing avatar images that Ferdy Christant has created for JungleDragon.  Many thanks to Ferdy for giving me permission to reuse the images here and if you haven’t looked at JungleDragon yet then its about time you did.

snowleopardbarcodecobrabarcodegorillabarcodelionbarcodebearbarcodeowlbarcode

 

For this demo the information is stored within the application using a simple ArrayCollection but it could easily retrieve information from a Domino application / alternative system.  Don’t forget as its Adobe Flex it can easily be converted to an AIR application which can then run on mobiles.  For a mobile version we could then use the phones camera to pickup the barcode.

Mark Myers and I have some plans for some great little applications which will leverage this technology – stay tuned! In the meantime if you have any need for a barcode implementation within your software solutions then just drop me a line.

Link to Demo (Due to WordPress eating my HTML)

Comments (8)

Adobe Flex & Robotlegs–a simple process flow diagram

Carrying on with previous blog posts about RobotLegs I thought it might be useful to someone to have a simple process flow diagram along with an explanation on how it hangs together.

Initially Robotlegs (or any framework that I can see) can appear a little over the top and there seems to be a lot of bits of code hanging together but this granularity is important as it allows reuse and testability and tries to eliminate close coupling between bits of code this in turn makes it easier to manage change.

The described process is for the initial part of an Adobe Flex application which needs to load some external configuration data.  This data needs to be loaded first and then it needs to be made available to the rest of the application in a controlled manner.  In Lotus Notes terms these would typically be your keyword documents.

This is a common requirement so I want this to be a reusable technique / codebase.

I have decided to follow convention and use the suggested design pattern of MVC(S).  In the process below I haven’t actually reached the point where I need a view yet so we are only going to cover Commands, Events, Models and Services (No View or Mediator).

NB This is not an explanation of Robotlegs but more about how the various bits hang together.  Even with that in mind its worth quickly explaining what each of the bits are again.

Commands

Commands are small short lived bits of logic, they are typically mapped to an event such that when that event is fired the command reacts to it.  The event is normally injected into the Command so if it has any payload it can be accessed.

Events

Events are used to communicate between your application tiers, there are Framework events – as in Robotleg ones, System events – as in Flash Player  / Flex ones and there are custom events which you create yourself.  These custom events can be used just for passing a Flag e.g. Something has loaded and / or they can carry payloads e.g. Data Objects which are then worked on by whatever is listening for the event.

Models

Models are used to control access to your data – this is the place you would hold your arraycollections and any business logic to do with that data.  You would also typically have Value Objects (VO) defined here.  Value Objects are used to convert data you have received from a service into a strongly typed object which means you gain type ahead and compilation checking which helps to reduce bugs.

Services

Services are used to communicate with outside services i.e. to get the data.

It is good practice to define your Service methods in an interface and then create a concrete class from that interface.  Where ever you need to use that service you refer to the Interface as the object type and then at runtime Robotlegs will inject the concrete version (you map this relationship in the Context which is described below).

By using an interface you can then change 1 line in the Context to map the interface to a different concrete class and nothing else will need to be changed .

Process Flow

MultiDBSearch

The process diagram has numbered steps and these are the details for each step:

1. The context of which there has to be at least 1, though you can have more, is used to bootstrap the application.  Its here you map your commands to events, setup your various injections and finally dispatch a Robotlegs Event – ContentEvent.Startup(2).

2. The Robotlegs Event – ContentEvent.Startup is being listened for by the StartupCommand (3).

3. The StartupCommand in this case only does 1 thing and that is to dispatch a custom event ApplicationEvent.LOAD_CONFIG (4).

4. The custom event has several flags – in this case It has been dispatched with the LOAD_CONFIG flag.  The LoadConfig (5) Command is listening for this event with this flag.

5. The LoadConfig Command has been Injected with the ConfigService(6) Interface.

Now the Command has access to the ConfigService it can call a method directly on it – in this case loadConfig().

6. The ConfigService will load the configuration data from an external location and then convert the returned data into a value object.  Therefore the service in this case will loop through the data and create an ApplicationConfig Value Object, it will then dispatch a custom event (7) but this time it will carry the ApplicationConfig Value Object with it.

7. The custom event ApplicationEvent.CONFIG_LOADED is the same custom event as 4 but this time with a different flag and a ApplicationConfig Value Object payload.  The UpdateConfigCommand(8) is listening for this event.

8. The UpdateConfigCommand has been injected with the ApplicationConfigModel(9) and this command will take the ApplicationConfig Value Object from the event it was listening for and update the ApplicationConfigModel.

9.  When the command (8) updates the ApplicationConfigModel it dispatches a custom event(10) to let any listeners know the the config model has been updated.

10.  The custom event ApplicationEvent again is the same event as 4 & 7 but with a different flag and there is no payload this time.  This means any part of the application that needs to know the config has been updated can react.

Summary

  1. Setup Context, map commands to events and inject dependencies.
  2. Dispatch a startup event to indicate Context is setup and we are good to go.
  3. Have a command listen for when the Context is setup so the initial application logic can start.
  4. Dispatch a custom event to indicate Startup Command has finished.
  5. Have the LoadConfig command listen for the custom event, it then runs the loadConfig() method on the injected Service.
  6. The loadConfig() method in the Service will got out over HTTP and load some XML data, the result handler in the Service will then parse this data into a Value Object and dispatch a config data loaded custom event and include this Value Object with it.
  7. The UpdateConfigCommand is listening for the data config loaded event, it has the model injected into it so it can take the config data object and update the model with it.
  8. The model then dispatches an event to let all listeners know that it has been updated.
  9. At this point I can then proceed with the Application flow as I have my config data.

Conclusion

I know it looks like a lot – but imagine the following scenarios:

You need to reload the config at another time within the application, all I need to do is dispatch the custom event – ApplicationEvent.LOAD_CONFIG  and then listen for when the model dispatches its event to say its been updated.

You need to change your service so that rather than use XML it now needs to be a SOAP based webservice.  Create a new concrete service class than implements the Service Interface and change one line in your context.

If anyone wants the Flex source just let me know.

Leave a Comment

Camera Trap

51u0EBI4ChL._SL500_For Christmas this year I brought my wife a camera trap to help find out what animals visit the garden at night.  The camera trap is a nifty bit of kit which consists of a digital camera, a PIR and lots of IR LEDs – similar to the one pictured here.

The camera can take stills or videos and so far seems to be working well except for the IR illumination being a bit strong – just means you have to position it a bit further back than you think.

So far I have put out a little bit of meat as we are hoping to capture badgers (don’t tell the local farmer) but these are the results so far – 2 cats, 1 mouse and 1 bird Winking smile .

Ah well maybe I will catch the infamous wild cat of the North Cambridgeshire fens.

PICT0605PICT0130PICT0018PICT0042

The other animals we have caught have been on the front facing security camera:

Small deer

 

And something which doesn’t go well with my Chickens.

Fox

Comments (1)

Implementing TagDragon in a Domino Application

logo

TagDragon is Ferdy Christant’s excellent JQuery plugin to provide type ahead functionality.  The plugin is not free but requires a small donation but is worth it for a stable robust plugin.

My requirements were to autocomplete on the entries in a view column for performance reasons.

  • The bits you need are:
  • Plugin from Ferdy
  • JQuery Library
  • A Holding form in Notes – not used for anything but redirecting
  • A $$ViewTemplate for ‘holding’ the JSON formatted view.
  • A JSON formatted view.

The main thing I had to do to get the plugin to work with Domino is deal with the HTTP Post requirement.  Ferdy’s plugin expects to perform a HTTP Post when a letter has been entered so you can’t just call a Domino view URL directly, you could call an agent and deal with the response there but for performance reasons you might want to get the JSON formatted data back from a view.

Redirection form

The redirection form has a tag and max field on it – these fields are passed via the HTTP Post from the plugin and a SaveOptions = "0" to prevent the document actually being saved.

In addition I used a $$Return field to compute a URL to open a view which has been formatted with JSON formatted data e.g.

"[/"+@WebDbName+"/(JSONData)?openview&StartKey="+tag+"&count="+max+"]"

Depending on your requirements you could add a $PublicAccess field and enable the write public access form property if you wanted this functionality for Anonymous users.

View Template

formprop The $$ViewTemplate needs to be form with a content type of application/json.

 

 

 

 

 

The actual contents of the form looks like the following:
viewbody

We need the additional JSON on the end of the view because we will be appending a comma to the end of each document in the view and if you leave a comma at the end of JSON data it will throw an error.  Don’t worry about the additional item as the view count is already defined by the component and then passed through via the $$Return to the openview URL command and therefore the additional element will be ignored.

The JSON formatted view is simply a 2 column view – the first column is sorted by what ever your main field is and is marked as hidden, this just keeps the view sorted correctly.  The second column contains your JSON Data and looks like this:

"{\"tag\":\""+@URLEncode("Domino";FieldToSearchOn)+"\",\"id\":\""+@Tex(@DocumentUniqueID)+"\"}"+","

Notice we add an id which is the UNID as well as append a comma.  I decided to URLEncode the field as well which can bloat the data a bit but is probably the safest option if your not sure what data the field is going to contain.

Thats it for the Notes side.

To implement the web side I used the folowing HTML (the same as Ferdy’s demo code):

<div id="tagbox" class="tagbox">
<input type="text" value="" id="tags" />
</div>

This was the JavaScript I used in conjunction with the plugin;

$(document).ready(function() {
    $('#tagbox').tagdragon({'field':'tags','url':'typeahead?createdocument',
    'onSelectedItem':function(val){openDocument(val)},
    'onRenderItem': function(val,index,total,filter) { return unescape(val.tag)}
    });
});
function openDocument(val){
window.location = '/webwork/tourtariff.nsf/0/'+val.id;
}

The URL posts to my redirection form by using the ?CreateDocument Domino URL – NB I was hosting this control within a domino form within the same database so you might need to tweak the URL.

  • In addition I use 2 of Ferdys callbacks:
    onSelectedItem = calls my openDocument function which is passed the currently selected item and as we added an id which holds the UNID in the JSON data it makes it easy to get a handle on the underlying document.
  • onRenderItem = I use this callback to unescape the tag which was URL encoded in the view.

Comments (1)

Blog Tag – Stickfight has thrown down the gauntlet (well fingerless glove)

Boxing gloves As part of our preparation for polishing our Adobe Flex skills Mark Myers has suggested a Blog Tag – where we set each other an Adobe Flex technical challenge in which we have 2 weeks to write a blog explaining how to solve it.

Here is my first challenge to Mark.

Your challenge is to create a custom component which has no external dependencies i.e. a black box which utilises the inbuilt internationalisation features of Adobe Flex to display popup help in the users currently selected language.  The popup help should have a close button and a more info button both of which should dispatch appropriate events – you do not need to handle the additional info action in the component.

The popup help should be suitable styled and positioned either at the calling event (mouse click) or in a fixed position (maybe configurable – top, middle, left etc)

Ideally though the component will utilise the inbuilt internationalisation features of flex it should be possible to swap out this approach to use an alternative source / method for the content without having to change the core code.

Good luck Mr Myers!

If anyone else wants to get involved just drop us a note – its a good way to learn new stuff and build content in your blogs.

Leave a Comment

Adobe Flex Frameworks & why they matter (particularly if your coming from Lotus Notes)

rl-header-logo-310-253 Frameworks – particularly micro AS3 frameworks for Flex seem to be in vogue, but why?  What do they offer?  Other than adding what looks like making your apps more complex.

If your a Lotus Notes / Domino developer I am sure you have come across the classic tactical application which has grown over time to be a business critical application, you know the one which has had multiple developers over time (who have now left) and of course there is no documentation.

One of the advantages of Lotus Notes is its quick to develop and there are multiple ways to do the same thing – particularly Domino apps.

One of the disadvantages of Lotus Notes is there are multiple ways to do the same thing (you see what I did there ;-)

This leads to an unholy mess of an application – you have code everywhere, you have business logic in hide when’s, you have computed text creating fields on the fly, multiple script libraries with 40 functional routines etc.  This ultimately leads to several things happening: 

  • Bugs and errors go up -  but hey doesn’t matter its quick to fix right – maybe before IT compliance rears its head?
  • Support and lights on budgets get consumed by these Notes apps, but they were quick and cheap to develop right?
  • Adding new functionality suddenly takes a lot longer than you would expect – mainly because you have no idea what the impact will be and you have to find out how it all fits in – assuming you didn’t build the complete app.  Ever added a new lookup view to an application because it was easier to do rather than workout the impact of modifying an existing lookup view.

Of course the IDE doesn’t help – the Domino Designer is really staring to show its age when compared to other IDEs.  To be fair it has to manage a lot of different design elements as well as 2 clients.

Adobe Flex apps could suffer from similar problems if you followed the same route but this is where a framework comes into its own + some other bits like Unit Testing and Continuous Integration. 

Frameworks provide a structure to your applications – i.e. they help to define a best practice application architecture, which ultimately means as a developer you know where your various bits of code should be placed and if you were joining a team or working on existing application you would already know how its structured.  Not only do frameworks help with structure they also are designed to make it easier to unit test by isolating key functionality, which also makes it much easier to add new functionality as well as much better reuse.

There are several frameworks available (list taken from http://corlan.org/flex-frameworks/):

  • Cairngorm (Adobe Open Source) – MVC framework
  • PureMVC (Open Source) – MVC framework
  • Mate (Open Source) – Mate is a tag-based, event-driven Flex framework
  • Swiz (Open Source) – Metadata-based Dependency Injection framework
  • Spring ActionScript (Open Source) – Dependency Injection framework part of SpringSource
  • Parsley (Open Source) – IOC Container (Configuration and Dependency Injection), MVC, and localization
  • Robotlegs – automated metadata based dependency injection micro-architecture (framework) with a light footprint and limited scope

After looking at several I have decided for now to settle on Robotlegs

Robotlegs is an IoC/DI container that is modeled on the PureMVC application structure. It is designed to be MVCS, model-view-controller-service, providing metadata dependency injection across these layers.

Ok so what does that mean in English ;-)   Basically it means that the framework breaks your code elements in Flex down into:

Context – This is where the mapping between the various framework elements happen, its also acts as an event bus.  There needs to be at least one context but there can be more.

Mediators – mapped to your views.  Mediators are the middle men (or women) between your views and the framework.  They pass along view events to the framework and access view methods and properties on behalf of the framework.

Views – your visual components, datagrids, lists etc.  The idea here is the visual components have no dependencies on your application.  Instead they use mediators to pass information via events out to the framework.

Commands – This is where the business logic lives.  These are short lived objects.

Models  – These objects do the work on the data.  They raise events once the work has been done.  NB Value Objects (VO) are associated with the model and provide strong data typing.

Services – This part of the framework communicates to external services (XML, SOAP, RemoteObject etc) and raises events when work has been done.

Communication is done between the framework and the application by using standard flash events.

Heres a great diagram which shows how the bits talk to each other (links to Robotlegs site)

robotlegsflow

 

Resources

An Introduction to Robotlegs AS3 Part 1: Context and Mediators

An Introduction to Robotlegs AS3 Part 2: Models

An Introduction to Robotlegs AS3 Part 3: Services

Best Practices

Comments (3)