Showing posts with label Lotusscript. Show all posts
Showing posts with label Lotusscript. Show all posts

Friday 12 June 2009

Notes Client Tip - Dragging and Dropping documents into a calendar

I was asked today the following question,
Why can't we drag a customer from a customer list onto our Customer Visit Calendar and make an appointment with them that way?
Good question. We already have that functionality on the web interface. Popup a customer list, select the customer or customers from the list and drag them to the day you want to schedule the visit and it auto creates the document for that customer on the day you dragged the document(s) onto.

I sucked my pencil for a bit, scratched various bits of my anatomy that would not be misconstrued by my colleagues as offensive and hummed and ahhed. I pinged Julian Robichaux and bounced the idea off him. Can I drag docs which are not calendar docs from an embedded view on a page (or form) onto calendar view embedded on the same form and create a document or documents based on the QueryDragDrop event of the calendar based on the documents that I had dropped.

Julian confirmed my initial thoughts that this was a non-runner because when a view is embedded you can't seem to access the drag drop events - BUMMER! So I then mentioned a word not mentioned in polite society much these days and to give Julian credit it didn't finch or berate me in any way. "What about Framesets?" I said

After a bit of futtering about we discovered that yes you could accecss the Drag and Drop events from FrameA to FrameB and Joy of Joys the CurrentView in the UIWorkspace FrameB's QueryDragDrop event was the view from FrameA! _ YIPEE!

I took my leave of Julian with much thanking and promises of beer and proceeded to have a bit of a debug to see what I could do.

I created a wee test NSF with two forms CUSTOMER and CALENT
Followed by a View of just the CUSTOMER forms and a Calendar view of the CALENT forms
A Frameset was created and in the LHS frame I popped CUSTOMER view and in the RHS frame CALENT calendar view.

On the CALENT view's QueryDragDrop I entered some code and had a ferret about in
what was an what was not passed, this is what I found out.

If you grab one doc from the CUSTOMER view and drop it over the calendar, then there are no documents in the UIView.Documents collection, there is a CaretNoteID that links to the dragging document in the UIView.

If you select more than one document from the CUSTOMER view and drag it over the Calendar then the UIView.documents collection contains the documents you selected.
If you actually select (the wee tick in the gutter) one document the UIView.documents will contain that one document, but you cannot count on users doing that.

Sub Querydragdrop(Source As Notesuiview, Continue As Variant)

Dim ThisSession As New NotesSession
Dim ThisDB As notesdatabase
Dim ThisUI As New NotesUIWorkspace
Dim ThisUIV As NotesUIView
Dim ThisDC As notesdocumentcollection
Dim OldDoc As NotesDocument
Dim NewDoc As NotesDocument

Set ThisDB = ThisSession.CurrentDatabase
Set ThisUIV = ThisUI.CurrentView
' *** Test to see if the view I am dragging from is the calendar or the customer list
If ThisUIV.ViewName <> "Calendar" Then
Set ThisDC = ThisUIV.Documents
'*** Well you must have dragged SOMETHING to fire the event so get it from
'*** from the CaretNoteId
If ThisDC.Count = 0 Then
Set OldDoc = ThisDB.getDocumentById(ThisUIV.CaretNoteID)
Set NewDoc = New NotesDocument(ThisDB)
NewDoc.Form = "CalEnt"
NewDoc.Customer = OldDoc.Customer(0)
NewDoc.City = OldDoc.City(0)
NewDoc.Date = Source.CalendarDateTime
NewDoc.Time =Format(Now,"hh:mm")
NewDoc.Status = "Planned"
Call NewDoc.Save(True,False)
Else
Set OldDoc = ThisDC.GetFirstDocument
Do While Not (OldDoc Is Nothing)
Set NewDoc = New NotesDocument(ThisDB)
NewDoc.Form = "CalEnt"
NewDoc.Customer = OldDoc.Customer(0)
NewDoc.City = OldDoc.City(0)
NewDoc.Date = Source.CalendarDateTime
NewDoc.Time =Format(Now,"hh:mm")
NewDoc.Status = "Planned"
Call NewDoc.Save(True,False)
Set OldDoc = ThisDC.GetNextDocument(OldDoc)
Loop
End If
Else
'*** This is the calendar and I am moving docs around inside it
Set ThisDC = ThisUIV.Documents
If ThisDC.Count = 0 Then Exit Sub
Set OldDoc = ThisDC.GetFirstDocument()
Do While Not (OldDoc Is Nothing)
OldDoc.Date = Source.CalendarDateTime
Call OldDoc.Save(True,False)
Set OldDoc = ThisDC.GetNextDocument(OldDoc)
Loop
End If
Call ThisUI.ReloadWindow()

End Sub


This code allows the user to drag a customer (with or without tick selction) or customers from the customer list in the left hand frame onto the calendar and create a calendar entry for that customer on the dropped on date. The user can also safely drag and drop calendar entries around inside the calendar.

Useful and cool. :-)

I have popped the NSF up here so if you are interested in seeing it in action you can have a go.

Enjoy ...

Wednesday 4 February 2009

You can have a play with Twimino V0.0.1 if you want

He ho Peeps.

If you will that way inclined you can have a play with Twimino V0.0.1 ... it is no where near done yet, I have perhaps worked on it for 3-4 hours so do NOT expect loveliness!!! It not all there yet and it is likely full of of bugs.. but it works after a fashion. Thomas's version is slightly different I use the Domino SAX parser and he doesnt (it has to be said his is a good deal more professional than mine, but what the hey ...)

The Twitter API is doing something strange with the DM api and it might take a few refreshes of the agent to see you DMs appear...(they are GREEN in the Friends Time line BTW)

You can download it here. (116k ish)

Once I apply some polish and some more features , friends, searchs, automatic SNURL/SNIP and the like, I will bung it up on OpenNtf for now have a play if you feel that way inclined the code is all LS and is not that difficult to follow.

Once you have done the first Harvest the agent will kick in and run every 5 mins, you may have to press F9 to refresh the view, the friend list builds as you get Tweets in.

Click on a tweet to get the option menu, or right click and use the options you find there.

You can also click on your Friend list to get a menu there.

Non-automatic manual refreshes via the big button on you friends time line

No piccies as yet I am afraid

Tuesday 3 February 2009

Twimino Nearly Ready

I got a bit bogged down in another issue so I am not quite there yet. I still need to do a couple of views and enable a click-up menu of options on the friend list for "Tweet At Twit", "DM Twit" etc

However the underlying guts is all there now.. sort of.













This is what it looks like now in Default view
with the OPTIONS bar closed. Your Friend Time line is displayed in the main body part of the screen with unread marks and message threading where possible (some clients don't do replies and as such the thread gets broken)







This is the Option Bar open where you set your profile, sign the DB turn the harvesting agent on and off it can be slid away when not needed.














When you click on a tweet in your friend's timeline instead of the tweet opening you get this menu which allows you to Send a new TWEET
Reply to the TWEET you clicked on
Retweet the TWEET you clicked on
Or Open the first URL in the TWEET text in your browser














This is your send a tweet dialog, it can copy with new Tweets, Replies and Retweets. (Tomorrow it will get DMs)


All these options are also on the RIGHT CLICK menu for the VIEW

The agent runs every 5 mins to harvest the tweets but you can do manual refreshes using the view's "Manual Harvest of Tweets" button

At the minute the Friend List Auto Populates from the Tweets you harvest

I have a background agent that your can run that harvests "All your followers" "All Someone Elses Followers" and will allow you to add and block chums...but that will be for Version 0.0.2

Anyhows Off to bed for me...

Wednesday 28 January 2009

Twitter in an NSF

Greetings and felicitations peeps and peepettes,

In a fit of pique at not being at LS09 and wishing that I could get a decent Twitter client that had a decent search, sorts and message threading also I was asked a question by a virtual colleague about "how to read an XML data stream in LS?"

So I threw together some LS at an NSF and "DYMTweetlet" was born. I now have a local NSF that sits and merrily polls my twitter stream every 3 mins if my notes client is up. Stores the tweets in a notes doc and then has all the notes-ee goodness of message threading, views, sort, search and the like. It also finds tweets from your chums that are "reply to" people you aren't following and sends them "Can I follow you" request.

It looks like shite at the minute, but it works, all I need is a way of getting the avatar piccies down to add to the PEEP document. Wild Bill & Matt White have pointed me at Java for this which I was investigating this evening, tomorrow I will give it a go and see what happens

Thursday 21 August 2008

Reading a CSV attachment in a server agent on Domino running on an iSeries

Oh Gentle readers here is the solution to a bit of a quandary that hit me the other day.

We have and agent that runs on a windows machine that reads a CSV sent out as an email by another system (non-domino) to a Domino mail-in database. A Server "On arrival of New Mail" agent runs , detaches the file, opens it , reads it and acts on the data inside the file on a record by record basis.

Now this all works a treat on a Windows server, but when we tried to move it to a iSeries the agent just grunted rolled over and went back to sleep, no errors but no data sourced actions performed either.

Now an iSeries is a funny if very reliable beast and what was happening was this. The email arrived in the mail box, the agent triggered and the file was saved to the what is known in the iSeries world as the IFS to the same folder as in Winders world. However the file was saved with the Coded Character Set Id (CCSID) that the AMGR jobs were running with when the save took place. For our iSeries this was 37. I could read the file from the IFS from a 5250 emulation screen. I could even drag and drop it from the iSeries to my PC and it read perfectly but the data that was being returned from the file was garbage. Initally I though it might be pure EBCDIC but not putting it through and EBCDIC convertor returned more of the same sort of garbage.

My chum Julian Robichaux wrote a nifty class that reads CSV files line by line and returns a nice easy to use arrays which needless to say I had used to read in the now detached CSV file. After some twittering and being lead down an interesting tangent by Kerr Raniney about reading the CSV directly from the MIME entity. (an idea I may investigate at a later date .. Thanks Kerr) I noticed in the help a section on what not to do in OS400 and was lead from there to the startling discovery that it was the OPEN statement that was at fault, When it changed it from
Open csvFileName For Input As csvFile
to
Open csvFileName For Input As csvFile CHARSET='UTF-8"

then everything started to work again!

What was happening according to the help file was that in the absence of an UTF8 or UTF16 BOM
on the file itself OR the CHARSET setting on the OPEN command the iSeries opens the file with the
CCSID tha tis on the file, in this case 37 so the iSeries was basically taking ASCII thinking it was
EBCDIC and forcing it into CCSID=37. The result was basically crap data. However setting the
CHARSET= parameter did the trick!

For all you iSeries Gnomes like me out there this is a fact worth remembering if you want to do
anything "smart" with attachments in agents.

Tuesday 19 August 2008

An Interesting use of the postopen event of the application












I was faced with an interesting programming issue today which was solved with the seldom used PostOpen event that you can find on the database (sorry application). You can find this in the Other section of the application, then the Database Resources and then Database Script .

The event is found inside this section and gets triggered immediately the Application has reached a restful state in the UIworkspace.

This is an event that in our Org is seldom used, so seldom I thought I would blog the fact we used it. Basically we needed a check when the application opened that if it was a local replica that it had been replicated within a certain "window" of opportunity. If the file had not been replicated in say the last 14 days the application would close until the user replicated. If the file had not been replicated in the last 90 days then the file was "locked" and could never be used and the user was prompted to recreate the replica.

As I say this and the other events in the DB script section are often overlooked and when you really need them they can be really useful!

** Update ** Quite a few people have come up with MUCH more interesting uses, I advice you to have a read at the comments.

Monday 12 May 2008

Getting back to the URL you where at when you opened a document.

I was explaining this to a junior dev today and thought i would pass it on.

If you have a Web App with one form but 3 views and the document can be opened from any one of the 3 views. How do you get back to the view you where at when you opened the document in the first place?

There are several ways of doing this, this is mine and it uses a session cookie in the browser to do it.

First you need some cookie handling JS in your form or external JS file, Something like this.


function createCookie(name,value,days) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = name+"="+value+expires+"; path=/";
}

function readCookie(name)
{
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++)
{
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}

function eraseCookie(name)
{
createCookie(name,"",-1);
}

Then on the page/form/view that has a link to a document on it place this is in the onLoad event:

createCookie("goback",location.href,0)

This will create a session cookie (it deletes itself when the current browser window closes) with the current location stored in the cookie.

Then on your form, place a hidden field called BackURL, or something similar, then on the onLoad event of the form have the following

document.forms[0].BackURL.value = readCookie("goback");


This pulls back the last place you were from the browser and stores it on the form.
Finally on your WQS agent you can use this to get back to your original place by

print |[script language='javascript']location.href='|+ThisDoc.BackURL(0)+|';[/script]|

Alternately you could populate a $$Return field with the contents of the cookie and use that
to redirect the form to the place that you were.

Thursday 3 April 2008

Working out what folder any given document is in if FolderReferences is not switched on

Here is a bit of code from the Lotus Notes Support site which like all
simple things is only simple when you see it done :-). The gurus amongst you
probably know this already but for me it was "oooooooo right" moment.

Here is the code for a selected docs agent


Dim session As New notessession
Dim db As notesdatabase
Dim doc As notesdocument
Dim doc2 As notesdocument
Dim view As notesview
Dim noteid1 As String
Dim noteid2 As String
Dim item As notesitem
Dim collection As notesdocumentcollection
Set db=session.CurrentDatabase
Set collection=db.UnprocessedDocuments
Set doc=collection.getfirstdocument
noteid1=doc.NoteID
Forall v In db.Views

If v.isfolder Then
Set doc2=v.GetFirstDocument
While Not doc2 Is Nothing
noteid2=doc2.NoteID
If noteid1=noteid2 Then
Messagebox v.name
End If
Set doc2=v.getnextdocument(doc2)
Wend
End If

End Forall

Monday 24 March 2008

Converting Web Posted Data into a Notes List collection in an agent

When you use a POST (or for that matter GET) transaction directly to an agent from an AJAX connection call you generally have to do something with the data. I find that converting the arguement name value pairs into a Notes List makes life so much easier. This is how I do it,

' *****************************************
Dim ThisSession as new NotesSession
Dim ThisDoc as NotesDocument
Dim TheParms List as String
' *****************************************
Set ThisDoc = ThisSession.DocumentContext
EvalString = |@URLDecode("Domino";"|+ThisDoc.Request_Content(0)+|")|
RawParms = Evaluate(EvalString)
AmpArray = Split(RawParms(0),"&")
Forall pairs In AmpArray
EquArray = Split(pairs,"=")
TheParms(EquArray(0)) = EquArray(1)
End Forall
' *****************************************

When this code is run you have a Notes List that comprises of all the argument pairs Posted
to to the agent.

Say for example the posted data was :

type=GD&vn=wibble&qi=wobble&dt=01010111

the resultant list would be :

TheParms("type") contains GD
TheParms("vn") contains wibble
TheParms("qi") contains wobble
TheParms("dt") contains 01010111

You can then access any of the arguments passed by name.

If you want to use this with a get you can get rid of the lines

EvalString = |@URLDecode("Domino";"|+ThisDoc.Request_Content(0)+|")|
RawParms = Evaluate(EvalString)
AmpArray = Split(RawParms(0),"&")

and use the Query_String_Decoded cgi variable

AmpArray = Split(ThisDoc.Query_String_Decoded(0),"&")

However remember that unlike the POST the GET string will start with a "&" so your ForAll
will need to test for AmpArray being equal to "" to avoid the first element of the AmpArray.

Steve

Disqus for Domi-No-Yes-Maybe