My Connect 2016 presentation & demo database

As I promised, I would post my IBM Connect 2016 presentation on my blog. Presentation (PDF): {link}  Demo database (ZIP): {link} You can also find the presentation on SlideShare.net. To the right you see the database design, you want to look in the Agent section for the agents and in the Pages section for the HTML pages. Note: You need to sign the database with an ID that have the proper rights. Otherwise the code will not work. Enjoy!  

6 Comments

IBM Connect 2016 coming up!

In the end of January it is once again time to head to Orlando for the yearly conference that for many years was known as Lotusphere. For the last few years it have been renamed IBM Connect (as well as ConnectED in 2014), and last year most people (including me) thought that 2015 was the end of this conference. But perhaps due to the popularity of the 2015 edition, IBM decided to have the conference again this year, but in a new location as the contract with Swan and Dolphin (where the conference had been held since the first one in 1993) had expired. The new venue is Hilton Orlando. It is closer to the airport and there are also more restaurants around than at Swan and Dolphin. It is close to SeaWorld as well as to the Universal Studios theme parks. Personally I am excited about the new venue. "Swolphin" (as Swan and Dolphin often was referred to) started to get old and worn down, despite a refresh of the rooms back in 2003-2005 some time. Yes, after this many years (18 in a row for me) Swolphin started feeling like a home away from home. You know where everything is, you know the staff and the shortcuts between hotels and sections within the hotel. So a new location makes Connect 2016 more exciting, it will feel like a new conference but hopefully with many of my old friends attending. I have already found several interesting sessions using the session tool. Philippe Riand and Jesse Gallagher will for example talk about the Darwino application development platform, which allows you to integrate your Domino applications with IBM Bluemix an IBM Connections. Another must-attend session is called IBM Domino App.Net and talks about how to utilize Bluemix to build XPages applications in the cloud. In addition we of course have all the sessions we have come to know and love: UserBlast with Mat Newman, Admin Tips Power Hour presented by Chris Miller, Spark Ideas, and of course the Opening General Session (OGS) with a secret guest speaker as the tradition requires. After the fiasco last year with the Tuesday evening special event the organizers went back to holding the event in one of the local theme parks. For the second time it will be held in the Wizarding World of Harry Potter - Hogsmead, which is part of Universal's Islands of Adventure. Last time I had a blast, so much that last year I took a couple of vacation days to visit Hogsmead again as well as the then newly opened Diagon Alley extension over in the Universal Studios park next-door. You need a park-to-park admission pass to visit both parks, but that allows you to take the Hogwarts Express between the two parks. For me personally Connect 2016 is a milestone. It will be my 20th Lotusphere/Connect and for the first time I will present a session! This is not a full one hour session, but a new format called Lightning Talk. Those are shorter 20 minute sessions,…

1 Comment

Calling a Notes web agent from another server using JSONP

In my MWLUG presentation (as well as in a couple of entries on this blog) I talk about how you can access Domino data from a regular webpage using jQuery and a Lotusscript agent returning data as JSON. The issue with this solution is that the web page must be on the same web application path as the Domino agent. You can't do what's known as cross-domain Ajax. For example if the Domino server is domino.texasswede.com but you have the webpage hosted at www.texasswede.com, it will not work. The security in Javascript does not allow calls across servers like that. There is however an easy solution, and it is called JSONP. What you do is to return not JSON but a call-back function with the JSON data as the argument. So instead of returning this: { "firstName":"Karl-Henry", "lastname":"Martinsson","email":"texasswede@gmail.com" } you would have the Lotuscript agent return this: personCallBack({ "firstName":"Karl-Henry", "lastname":"Martinsson","email":"texasswede@gmail.com" }) Let's assume we call the agent GetPersonData.jsonp.  On the calling side (in the jQuery code) you would then use this code: $.ajax({ url : "http://domino.texasswede.com/database.nsf/GetPersonData.jsonp?OpenAgent", dataType:"jsonp" }); Finally you write the Javascript call-back function that will accept the data: function personCallBack(data) { $("#firstName").html(data["firstName"]);     $("#lastName").html(data["lastName"]);     $("#emailAddress").html(data["email"]); } You can of course make this as advanced as you like but this is the basics. I have updated the JSON class I use for stuff like this to include a method to return JSONP. The new function is called SendJSONPToBrowser() and takes a string with the name of the call-back function as argument, for example like this: Call json.SendJSONPToBrowser("personCallBack") Below is the updated class (if you downloaded my sample database from MWLUG you have the older version of it). Enjoy!   %REM Library Class.JSON by Karl-Henry Martinsson Created Oct 9, 2014 - Initial version Updated Nov 6, 2015 - Added JSONP support Description: Class to generate simple JSON from values %END REM Option Public Option Declare Class JSONdata Private p_json List As String Public Sub New() '*** Set default value(s) me.p_json("ajaxstatus") = "" End Sub %REM Property Set success Description: Set success to true or false %END REM Public Property Set success As Boolean If me.success Then Call me.SetValue("ajaxstatus","success") Else Call me.SetValue("ajaxstatus","error") End If End Property %REM Property Get success Description: Not really used... %END REM Public Property Get success As Boolean If me.p_json("ajaxstatus") = |"success"| Then me.success = True Else me.success = False End If End Property %REM Sub SetMsg Description: Set msg item %END REM Public Sub SetMsg(message As String) Call me.SetValue("msg",message) End Sub Public Sub SetErrorMsg(message As String) Call me.SetValue("errormsg",message) me.success = False End Sub Public Sub SetValue(itemname As String, value As String) Dim tmp As String Dim delimiter As String '*** Check for quote (double and single) and fix value if needed tmp = Replace(value,Chr$(13),"<br>") tmp = FullTrim(Replace(tmp,Chr$(10),"")) If InStr(tmp,|"|)>0 Then If InStr(tmp,|'|)>0 Then tmp = Replace(tmp,|"|,|"|) delimiter = |"| Else delimiter = |'| End If Else delimiter = |"| End If '*** Store value with delimiter in list me.p_json(itemname) = delimiter & tmp & delimiter End Sub Public Sub SetData(itemname As String, value As…

0 Comments

Microsoft goes NoSQL with DocumentDB

"Flexible schemas", "automatic indexing"... Sounds interesting, I can see this for some companies as a way to migrate Domino applications to Azure. Put your .NSF based data there and use different technologies to work with it. Also, it has a "pay-as-you-go" pricing, making it even more attractive. More info here.

0 Comments

Microsoft releases Visual Studio 2015

Microsoft today released the latest version of their development environment Visual Studio. There are even free versions, including the complete IDE Visual Studio Community and the code editor Visual Studio Code (available for Widnows, Linux and OSX). Visual Studio now includes even more tools for cross platform mobile development for iOS  and Android. There is even an Android emulator included. The web development part supports tools and frameworks like Angular, Bootstrap, jQuery, Backbone and Django. And naturally the IDE also supports Windows, including Windows 10 (expected to be released at the end of the month). I have been using tools in the Visual Studio family for many years, I started with a beta of Visual Basic 1.0 a long time ago, and used all version up to and including VB 6.0. I also played around some with Visual C++ and even Visual J++. After that I focused mainly on Lotus Notes development, but recently I have started some C#/.NET projects at work using Visual Studio Community 2013.

0 Comments

MWLUG in Atlanta – I will be presenting!

It is less than 7 weeks left until MWLUG, the Midwest Lotus User Group conference. This year the conference takes place in Atlanta, between August 19 and 21. During the three days there will be over 40 technical session and workshops on collaboration, receptions and networking opportunities, as well as access to experts of IBM solutions, both from IBM and other companies. The topics includes application development, system administration, best practices, customer buisness cases and innovation/future plans by IBM. Breakfast and lunch is included for two days as well. And all this for the cost of only $50 per person! The event takes place at Ritz-Carlton in downtown Atlanta. There is a block of rooms reserved at a special conference rate of $149.00 per night. One of the sessions will also mark my personal debute as a speaker at a conference. I will present "Break out of the box - Integrate existing Domino data with modern websites" where I will talk about how to integrate websites built either within Domino or on other platforms with backend data that resides in a Domino database. I will talk about how you can build a modern looking website using tools like jQuery and Bootstrap and seamlessly integrate them with existing data on your trusty Domino server using JSON and Ajax. I will also provide plenty of example code ready for you to bring home and start playing with. A number of IBM Champions will be presenting, as well as IBMers and other industry experts. So no matter your interest, I am sure you will find plenty of good sessions. I am sure I will have a hard time picking which sessions to attend! So what are you waiting for? Go to http://www.mwlug.com and register! See you there!  

1 Comment

Microsoft and jQuery Ajax calls – not using standards

I recently started using C# and .NET for the first time to build a web application. It is just a proof of concept application where I am trying to implement CRUD (Create, Read, Update and Delete) though jQuery and Ajax calls from a simple webpage. The application should let me retrieve a list of all companies in the database, get information about a specific company (based on a company id), update an existing company (and create a new company in the database if it does not exist) and finally allow a company to be deleted. I been doing these things for years using IBM Domino as the backend, simple reading the query string and parsing the name-value pairs before performing actions based on the values. So when I started using Visual Studio I naturally thought things would work the same there. But I found out that ASP.NET is using a different method to address web resources. It uses the concept of routes, so instead of adding information passed to the server using the query string, the data is passed in the actual URL: To get a list of all companies you would call /api/Company, and to get information about a specific company you add the company id (/api/Company/Q1234). If I want to pass two arguments to the server, for example to get all companies in a specific city and state, you would call /api/Company/TX/Dallas. In my opinion, this gives you much less flexibility than if  you pass arguments in the query string. You must put the arguments in the correct order, and it is much harder to use optional arguments. One example of where I used optional argumenst is for sort order. In some cases I want the companies to be returned in descending order, instead of the default ascending. Or I want to sort on a specific column/values. In those cases I pass along a special argument, but normally I don't. Less data to transfer that way, and cleaner code. But it still works. It is when you want to perform a POST of form data to the server that it get really complicated and annoying. This is the sample code using the ASP.NET Web API generated by Visual Studio 2013: // POST: api/Company public void Post([FromBody]string value) {     ... do stuff here } As you perhaps can tell, this function only take one argument, which is pretty useless in a real application. And you can't just add additional arguments in the declaration. One way to do it (as described here) is to use a data transfer object containing all the arguments, which then is used in the function: public class CompanyDTO {     public string CompanyID { get; set; }     public string LegalName { get; set; }     public string Address { get; set; }     public string City { get; set; }     public string State { get; set; }     public string ZIP { get; set; } } // POST: api/Company public string Post(CompanyDTO Company) {…

3 Comments

7 Rules for Creating Gorgeous UI

I found this two-part article about web design very interesting and want to share it. I am very similar to the author, I have also learned what looks good by looking at sites. In the end, I learned the aesthetics of apps the same way I’ve learned any creative endeavor: cold, hard analysis. And shameless copying of what works. I’ve worked 10 hours on a UI project and billed for 1. The other 9 were the wild flailing of learning. Desperately searching Google and Pinterest and Dribbble for something to copy from. These “rules” are the lessons from those hours. So word to the nerds: if I’m any good at designing UI now, it’s because I’ve analyzed stuff — not because I came out the chute with an intuitive understanding of beauty and balance. Part 1: https://medium.com/@erikdkennedy/7-rules-for-creating-gorgeous-ui-part-1-559d4e805cda Part 2: https://medium.com/@erikdkennedy/7-rules-for-creating-gorgeous-ui-part-2-430de537ba96

0 Comments

Bug in Bootstrap grids

While working on a web form using Bootstrap, I ran into a very strange issue with the grid system. I am not sure if I should qualify it as a bug, but it is definitely very annoying, and not the expected behavior. I created a page containing code like this: <div class="container"> <div class="col-sm-4 form-group"> <label for="ContactName">Name</label> <input type="text" class="form-control" id="ContactName" placeholder="FirstName LastName"> </div> <div class="col-sm-4 form-group"> <label for="ContactEmail">Contact Email</label> <input type="email" class="form-control" id="ContactEmail" placeholder="username@example.com"> </div> <div class="col-sm-4 form-group"> <label for="ContactPhone">Contact Phone</label> <input type="phone" class="form-control" id="ContactPhone" placeholder="(xxx) xxx-xxxx"> </div> </div> What happened was that when the browser window was smaller than the breakpoint for col-sm (less than 992 pixel wide), the input fields became semi-disabled. I could not click on them to select them and enter values, and the cursor did not change into an insert-point like it should. For all purposes it looked like the field had been disabled. But using the tab key, it was possible to go to the field and enter values. When I made the browser wider, it suddenly worked again. The issue occured in IE and Firefox, both the latest versions. The solution was to put the columns into a div with the row class. Suddenly it all worked: <div class="container"> <div class="row"> <div class="col-sm-4 form-group"> <label for="ContactName">Name</label> <input type="text" class="form-control" id="ContactName" placeholder="FirstName LastName"> </div> <div class="col-sm-4 form-group"> <label for="ContactEmail">Contact Email</label> <input type="email" class="form-control" id="ContactEmail" placeholder="username@example.com"> </div> <div class="col-sm-4 form-group"> <label for="ContactPhone">Contact Phone</label> <input type="phone" class="form-control" id="ContactPhone" placeholder="(xxx) xxx-xxxx"> </div> </div> </div> Hope this will help someone!

2 Comments

File Upload in Classic Domino Web using jQuery and Bootstrap

This week I was asked to create a simple web form where customers could fill out a few fields, attach two files and submit it for review. The document with the information and attachments are saved into a Domino database, so it can be processed thought the Notes client by the internal staff. These days I mainly use Bootstrap (and jQuery) to design the webpages, since Bootstrap makes it very quick and easy to get a nice clean look of the page. Using jQuery allows me to do some nice manipulations of the DOM, hiding and showing sections as needed for example, or disable the submit button until all required fields have been filled out. It has been a long time since I worked with the file upload control in Domino, and it was as ugly as I remembered it. But I knew I had seen some nice jQuery/Bootstrap file upload controls, so I located one that I liked in the Jasny plugin library. If you haven't already, take a look at those components! So how do I tie this control to the Domino file upload control? As so many times before, Jake Howlett and his excellent site CodeStore comes to the rescue. He wrote an article back in 2005 about how to fake a file upload control, and that code can be used as-is, and combined with the Jasny plugin. Here is what my code looks like after doing that: <div class="col-md-6"> <label>Producer Agreement</label> <!-- File Upload --> <div class="fileinput fileinput-new input-group" data-provides="fileinput" title="Attach file here"> <div class="form-control" data-trigger="fileinput"> <i class="glyphicon glyphicon-file fileinput-exists"></i>&nbsp; <span class="fileinput-filename"></span> </div> <span class="input-group-addon btn btn-default btn-file"> <span class="fileinput-new">Select file</span> <span class="fileinput-exists">Change</span> <input type="file" name="%%File.1" class="required"> </span> <a href="#" class="input-group-addon btn btn-default fileinput-exists" data-dismiss="fileinput">Remove</a> </div> </div> On the second file upload control I just change the name to "%%File.2". The form tag must have the encoding set to multipart/form-data, so this is what it looks like for me: <form name="SubmissionForm" id="SubmissionForm" action="AgencySubmission?CreateDocument" method="post" enctype="multipart/form-data"> It all worked perfectly. I was able to attach the files and submit the form, and the files showed up in the Notes client. What I did not like was the dreaded "Form processed" message. I tried a few different things, using the $$Return field, etc. But nothing worked. To make a long story short(er), and without diving too deep into details, I had the form setup to render as HTML, not as a Notes form, thus using ?ReadForm to display it. But when I changed it to Notes on the form properties, the Domino server added it's own Javascript code to submit the form (in addition to extra HTML). I found out a way to trick Domino to "hide" that Javascript code, so only my jQuery/Javascript code was sent to the browser. Then I wrote my own code to do a HTTP POST submission of the form as multipart/form-data: $('form#SubmissionForm').submit(function(event){ // Disable the default form submission event.preventDefault(); // Gat all form data var formData = new FormData($(this)[0]); $('input').each( function() { formData.append($(this).attr('id'),$(this).val()); });…

6 Comments

Free Code – Class to read URL name-value pairs

Here is another little code snippet I want to share. I use it all the time in my Lotusscript-based Domino web agents, and I figured that other could benefit from it as well. It is just an easy way to check for and read the name-value pairs (arguments) passed from the browser to the web server by HTTP GET or POST calls. Put the code below in a script library, I call it Class.URL: %REM Library Class.URL Created Oct 9, 2014 by Karl-Henry Martinsson Description: Lotusscript class to handle incoming URL (GET/POST). %END REM Option Public Option Declare %REM Class URLData Description: Class to handle URL data passed to web agent %END REM Class URLData p_urldata List As String %REM Sub New() Description: Create new instance of URL object from NotesDocument %END REM Public Sub New() Dim session As New NotesSession Dim webform As NotesDocument Dim tmp As String Dim tmparr As Variant Dim tmparg As Variant Dim i As Integer '*** Get document context (in-memory NotesDocument) Set webform = session.DocumentContext '*** Get HTTP GET argument(s) after ?OpenAgent tmp = FullTrim(StrRight(webform.GetItemValue("Query_String")(0),"&")) If tmp = "" Then '*** Get HTTP POST argument(s) after ?OpenAgent tmp = FullTrim(StrRight(webform.GetItemValue("Request_Content")(0),"&")) End If '*** Separate name-value pairs from each other into array tmparr = Split(tmp,"&") '*** Loop through array, split each name-value/argument For i = LBound(tmparr) To UBound(tmparr) tmparg = Split(tmparr(i),"=") p_urldata(LCase(tmparg(0))) = Decode(tmparg(1)) Next End Sub %REM Function GetValue Description: Get value for specified argument. Returns a string containing the value. %END REM Public Function GetValue(argname As String) As String If IsElement(p_urldata(LCase(argname))) Then GetValue = p_urldata(LCase(argname)) Else GetValue = "" End If End Function %REM Function IsValue Description: Check if specified argument was passed in URL or not. Returns boolean value (True or False). %END REM Public Function IsValue(argname As String) As Boolean If IsElement(p_urldata(LCase(argname))) Then IsValue = True Else IsValue = False End If End Function '*** Private function for this class '*** There is no good/complete URL decode function in Lotusscript Private Function Decode(txt As String) As String Dim tmp As Variant Dim tmptxt As String tmptxt = Replace(txt,"+"," ") tmp = Evaluate(|@URLDecode("Domino";"| & tmptxt & |")|) Decode = tmp(0) End Function End Class It is now very easy to use the class to check what values are passed to the agent. Below is a sample agent: Option Public Option Declare Use "Class.URL" Sub Initialize Dim url As URLData '*** Create new URLData object Set url = New URLData() '*** MIME Header to tell browser what kind of data we will return Print "content-type: text/html" '*** Check reqired values for this agent If url.IsValue("name")=False Then Print "Missing argument 'name'." Exit Sub End If '*** Process name argument If url.GetValue("name")="" Then Print "'Name' is empty." Else Print "Hello, " + url.GetValue("name") + "!" End If End Sub It is that easy. If my proposal for a session at ConnectED is accepted, you will about how to use jQuery and Bootstrap to retrieve data in .NSF databases through Lotusscript agents, and I will be using…

4 Comments

Free Software – Password Reset for Notes/Domino

Earlier this year I was asked to research some alternatives for a web-based password reset function at my work. One of the larger support burdens are users who forget the passwords, especially in the first few days after changing it. We have a 90 day password lifespan, then a new password need to be picked. Some users wait until the last minute, which usually is Friday afternoon right before they go home, making it very likely that they will forget the new password over the weekend. Another big group is auditors, who may come in every 6 months or so, and by then their passwords have of course already expired. I first looked at some COTS solutions from HADSL (FirM) and BCC (AdminSuite). They were both very competent, and in addition have several other functions that I really would like to have in my environment (like synchronization between Domino Directory and Active Directory). However, as my company is in a cost saving phase, I was asked if I could build something myself, so I played around a little, and came up with a small and simple application. The application contains two web pages. The first page (Setup) is where the user will setup the security questions used for password recovery as well as entering an external email address that they have access to even if locked out from the Domino account at work. This page is protected by regular Notes security, so the users need to set this up before they lose access to their account. The second page (Request)is where the user can request the password to be reset. After entering their Notes name, the user is presented with one of the security questions. If the question as answered correctly, the user can now enter a new password. If the question is wrong, another of the questions is presented to the user. I am also using regexp to make sure that the password match the requirement our organisation have for password strength. Both pages are built using Bootstrap (v3.2.0),  jQuery (v1.11.0), and for the icons I use Font Awesome (v4.2.0), all loaded from BootstrapCDN. I also use a few local CSS and Javascript files to handle older versions of Internet Explorer. The process steps were created using code by jamro and you can find the code here. By the way, Bootsnipp is a great resource to avoid having to invent the wheel again. There are hundreds of free snippets of code there to build neat Bootstrap functionality. When the user fill out and submit the setup page, a document is created in a Notes database. When the user need to reset the password, the security questions and answers are retrieved from that document. To prevent unauthorised access to the Notes documents, they use Readers fields to prevent them from being visible to anyone but the signer of the agents running on the server. This application can of course be updated with more functionality. Instead of allowing the user to pick a password, one could be generated by the server and sent through email to the address entered during setup. There…

7 Comments

jQuery – A flexible way to show/hide sections

Yesterday Stephen Gainer blogged about a small Javascript problem he had. Brilliant!  I gave my customer exactly what he wanted!  No muss no fuss!  I’m sure you see where I’m going with this.  As soon as this was done, my customer came back to me and said he needed four more of these. My solution, which is terrible, was to duplicate the above four more times (me2Show, me2Hide, me3Show, me3Hide and on and on and …..)  Now I realize how stupid this is, but remember how I said above that there are certain simple things that I never really learned because I never had to?  Well this is one, and this is where I would like YOUR help! I know there has to be some way to loop through all of my element ID’s with a simple piece of JavaScript, but I can’t for the life of me figure out how to do that.  Can anyone help me out here? I commented on Stephen's post and suggested that he use jQuery to easily loop though all elements with a specific class and add a listener function to them to detect a click. Since it is hard to get all information into a comment, I decided to post a simple code sample here instead. My code is easy to expand on, e.g by adding more sections. There are of course many different ways to do this. You can of course use .toggle(), but I prefer to have better control of when to hide and show the sections. You can break out the lines $(".mySection").hide(); into a separate function and call it from the two locations. This is of course not saving anything in this particular code sample, but in more complex code it would make sense to break down the code into separate functions if they are called from multiple lines. Hopefully this code will help someone, or inspire someone to start playing with jQuery. I like jQuery, as it easily integrates with classic Domino web applications, and even can be used with Xpages. <html> <head> <title>jQuery hide/show</title> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> <script> $(document).ready(function () { // Hide all sections when the page is first loaded $(".mySection").hide(); // Setup all elements with class "myButton" to react on click $(".myButton").click( function() { // Check if the section is already displayed if ($(this).html()=="Hide") { // Hide the current section var sectionID = $(this).attr("data-showsection"); $("#"+sectionID).hide(); // Set the button label to "Show" $(this).html("Show"); } else { // Hide all sections, using the class mySection $(".mySection").hide(); // Set all button labels to "Show" $(".myButton").html("Show"); // Show the section we want to display var sectionID = $(this).attr("data-showsection"); $("#"+sectionID).show(); // Set the button label to "hide" $(this).html("Show"); } }); }); </script> </head> <body> <button id="btnOne" class="myButton" data-showsection="sectionOne">Show</button> <div id="sectionOne" class="mySection" data-btnID="btnOne">This is the 1st section.</div> <br> <button id="btnTwo" class="myButton" data-showsection="sectionTwo">Show</button> <div id="sectionTwo" class="mySection" data-btnID="btnTwo">You are now seeing the 2nd section.</div> <br> <button id="btnThree" class="myButton" data-showsection="sectionThree">Show</button> <div id="sectionThree" class="mySection" data-btnID="btnThree">This is the 3rd section.</div> <br> <button id="btnFour" class="myButton" data-showsection="sectionFour">Show</button> <div id="sectionFour" class="mySection"…

0 Comments

Code snippet – jQuery

This morning I was working on a web application, and I came up with a pretty neat and simple little solution. So I just wanted to share it, in case anyone else need something similar. I have a webpage with an HTML form. Each input tag has an attribute called notesfield, matching the name of the field in Notes where the value is stored: <div class="col-md-3"> <label>First Name</label> <input class="form-control" type="text" notesfield="FirstName" value="" /> </div> <div class="col-md-2"> <label>Initial</label> <input class="form-control" type="text" notesfield="MiddleInitial" value="" /> </div> <div class="col-md-3"> <label>Last Name</label> <input class="form-control" type="text" notesfield="LastName" value="" /> </div> Then I created a simple function that will call an agent on the Domino server, which will return all the fields on the specified document as JSON. This function is called after the HTML page is fully loaded. function loadNotesFields(docunid) { var notesfieldname = ""; $.ajax({ url: "/database.nsf/ajax_GetNotesFieldFields?OpenAgent", data: {"NotesUNID":docunid}, cache: false }).done(function(data) { $('input[notesfield]').each(function() { notesfieldname = $(this).attr("notesfield"); $(this).val(data[notesfieldname]); }); }); } The function is actually extremely simple, and here you can see the power of jQuery. What I do is to perform an Ajax call to a Domino URL, passing a UNID to the agent to use in the lookup. I set cache to false, to avoid the browser from reusing previously retrieved data (this is a good thing to do if the data retrieved can be suspected to change frequently). The jQuery .ajax() functions returns the JSON in the data object, and when the call is done, the callback function loops through each input element with an attribute of notesfield, reads the value of said attribute and then sets the value of the input element to the corresponding Notes value. The only thing left is to write the agent that will return the JSON. It could look something like this: Dim urldata List As String Sub Initialize Dim session As New NotesSession Dim webform As NotesDocument Dim db As NotesDatabase Dim doc As NotesDocument Dim urlstring As String Dim urlarr As Variant Dim urlvaluename As Variant Dim i As Integer Dim json As String Set webform = session.DocumentContext '*** Remove leading "OpenAgent" from Query_String urlstring = StrRight(webform.Query_String_Decoded(0),"&") '*** Create list of arguments passed to agent urlarr = Split(urlstring,"&") For i = LBound(urlarr) To UBound(urlarr) urlvaluename = Split(urlarr(i),"=") urldata(urlvaluename(0)) = urlvaluename(1) Next Set thisdb = session.CurrentDatabase '*** Create content header for return data Print "content-type: application/json" '*** Get Notes document baed on NotesUIND argument Set doc = db.GetDocumentByUNID(urldata("NotesUNID")) '*** Build JSON for all fields in document except $fields json = "{" + Chr$(13) ForAll item In doc.Items If Left$(item.Name,1)"$" Then json = json + |"| + item.Name + |":"| + item.Text + |",|+ Chr$(13) End If End ForAll '*** Remove trailing comma and line break json = Left$(json,Len(json)-2) json = json + "}" '*** Return JSON Print json End Sub Happy coding!

6 Comments

API for ZIP Code Distance, Radius, and more

  The other day I stumbled on a really cool website, where they offer a free API to calculate distance between two US ZIP codes, all ZIP codes in a specific radius from a given ZIP code, as well as a few other ZIP code related functions. The results can be returned in different formats, like JSON, XML and (in some cases) CSV. Highly recommended! The URL is http://zipcodedistanceapi.redline13.com/ I am considering creating a Lotusscript class for some of these functions, so stay tuned!  

2 Comments

Excellent Bootstrap select plugin with great support

For a Domino-based web application I am currently working on, I needed a nicer looking select box (drop down) than what Bootstrap offers out of the box. I did some searches and found a handful of free ones, most of them pretty good but not exactly what I wanted. Some did not handle different themes, other had additional functionality I did not want/need, etc. I probably been looking for a good alternative for 3 weeks by now. Then the other day I found an inexpensive plugin at CodeCanyon. Custom Select for Twitter Bootstrap 3 is just $5 if you use it for a public site, or $25 if you use it on a site where you charge the users for access. It's well worth it. The control is nice and clean, and very easy to use. What really impressed me was how the author of the plugin, Lisa Stoz, fixed an issue I ran into. It was not a bug in the plugin, but I had a need to use custom tag attributes, and the plugin did not support that originally. The next day Lisa had a new version available with that functionality added. She also helped me with some additional questions that I had. I am very impressed with the quick response and the professional support. I am new to CodeCanyon, but that site seems very nice. It contains a large number of jQuery and javascript plugins, Bootstrap themes and plugins, and much more. There is also a section with WordPress plugins, as well as a separate site for Wordpress themes called ThemeForrest. That site also have other themes and templates. If you build websites, but like me is not a graphics genius, ThemeForrest is a great place to find themes or just inspiration for your site. The themes (as are the plugins) are very modestly priced, between $5 and $10 in most cases. I have just started to scratch the surface of what's available there, but I already think this is a great resource. The next time I need a plugin for Bootstrap, jQuery or Wordpress, I will probably start at CodeCanyon. Disclaimer: The links above uses an affiliate code, giving me a small credit at the site if you purchase anything.

1 Comment

Bootstrap – An Overview

As I mentioned in a previous article, my boss asked me to write some short summaries of a couple of common web technologies and frameworks. I already wrote about jQuery, and now the turn has come to Twitter Bootstrap, commonly called just Bootstrap. Twitter Bootstrap is one of the durrent darlings of web developers. It is a CSS framework, and it also includes some Javascript and the icon set GlyphIcons. Personally I use Font Awesome, a larger set (currently 361 icons) of icons compatible with GlyphIcons. Just like jQuery, you can use Bootstrap from a CDN (Content Delivery Network). There are also several themes available (both free and premium), so you can quickly get a different look than with the default Bootstrap colors. The free themes are also available through a CDN. With Bootstrap it is very easy to quickly create nice looking websites/applications. There are several ready-made templates on the Bootstrap site, and there are many more available all over the internet. So what you typically do is to download a template that fit your project, and then start customizing it. A couple of weeks ago I needed to quickly put up a one-page marketing website. I simply downloaded one of the templates, changed the headline, added my content and removed the sign-up button. In 30 minutes I had the site up, and that included writing the inital text. Then I spent another hour or so tweaking and editing the text, but the actual design part took just minutes. I am also currently working on a larger web application (which I hope to be able to blog about later this fall), and I choose to use Bootstrap there as well. One of the issues I always had in the past was to find a nice menu system to use on my sites, and this actually caused me to abandon the redesign of my personal website for over a year. When I discovered Bootstrap it just took me a few hours to totally revamp my website (including adding some functionality), and I now have a nice and functional menu system. The site also include icons for the menu entries, using Font Awesome. Bootstrap contains a large number of elements: buttons, dropdowns, tables, labels, input controls, alert messages, a grid system (totally redesigned in Bootstrap version 3), etc. There is plenty of documentation available online, both at the official Bootstrap website and on other sites and forums. So if you haven't looked at Bootstrap yet, see if it might help you in your next web project!

1 Comment

Bootstrap 3 released

Back in June I wrote about the availability of Release Candidate 1 of Bootstrap 3. Today the finalized version have been released.   If you are migrating from version 2 to version 3, here is a list of what changed. Among the many changes is a modified grid system, using percent instead of pixel-based width, responsiveness built in to the code files, a new flatter/cleaner look, and a number of new elements. You can read more in Kathy Brown's article at SocialBizUG.org. You can read more at http://getbootstrap.com/, where you also can download it. If you prefer to use a CDN (Content Delivery Network), you can use BootstrapCDN at http://www.bootstrapcdn.com/ Also, if you are developing using XPages, don't miss Philippe Riand's latest amazing project, Bootstrap for XPages. It uses Bootstrap 2.3, as version 3.0 probably will not work correctly in XPiNC (XPage in Notes Client), due to the fact that support for IE 7 and Firefox 3.5 have been dropped in the latest version.

0 Comments

Bootstrap 3 Release Candidate 1 available

As of this last weekend, Release Candidate 1 (RC1) of the next major version of Bootstrap became available. You can also use the hosted version at BootstrapCDN. There are many changes in this version, and among them I want to point out a few that I consider important: No more support for old browsers like Internet Explorer 7 and earlier or Firefox 3.6 and earlier. This avoids many hacks, and makes the code faster. Mobile first- Responsive CSS is no longer in a separate file, but included in the core CSS file. Overhauled and simplified grid system, including more friendly to mobile devices where they scale up and down better. Grid system is using percentage instead of pixel, which helps in mobile websites. Buttons - "fewer but better", per the documentation. Buttons look simpler/flattened. Moving Glyphicons to a separate repository, instead of integrating with Bootstrap. This should make it easier to use Font Awesome as replacement. "Hero unit" renamed "jumbotron". Added new components: Panel, List group Submenus have been dropped. And many more changes... There is no official release date yet, but I think we can expect the final version in a month or two.

2 Comments

End of content

No more pages to load