(via Instapaper)

Andulka

Product Placement
No title available
TMBGareOK. The Official They Might Be Giants tumblr
Keni

No title available
EXPECTATIONS
Lint Roller? I Barely Know Her
2025 on Tumblr: Trends That Defined the Year
Mike Driver
PUT YOUR BEARD IN MY MOUTH
hello vonnie
I'd rather be in outer space 🛸

roma★
𓃗
untitled

gracie abrams
Fai_Ryy
$LAYYYTER
Cosmic Funnies

seen from France
seen from Colombia
seen from Türkiye
seen from Georgia
seen from Canada
seen from Argentina
seen from Canada
seen from Morocco

seen from Brazil

seen from United States

seen from France
seen from United States

seen from Belgium
seen from United States
seen from United States

seen from United States
seen from Chile
seen from Türkiye
seen from Azerbaijan

seen from United States
@notesonmobile-blog-blog
(via Instapaper)
Stuff like this is a great start, but until these OS modification can be installed on any phone without rooting or pissing off your service provider I don't see it getting much traction. It's probably different in Europe where service providers are in a much different position, but here in the states Verizon won't ever support that kind of thing across the board. Possibly on a few handsets they can get it backed in from the OEM, but not as something a user is installing on their own. This means that BYOD isn't possible here and the enterprise will have to provide the phone. This puts us back to where we were a few years ago with Blackberry.
(via Instapaper)
Using source control in Lotus Notes
Niklas Heidloff recently blogged about how to use the new SVN support in Notes 8.5.3. However, something really stood out right at the begining:
There are three "repositories" that need to be kept in synch: 1) The server side managed SVN project 2) The client side on disk project under SVN control 3) The NSF project (using a virtual file system)Â
I have to remember to keep 3 different copies of my NSF in sync?!?! (I'm not going to even mention the DXL aspects of this whole thing either) Don't get me wrong, It's great that IBM is finally getting around to doing this after 20 years, but it seems really complicated to me. Of course, there is a much easier way. A way that has been around for 10+ years. A way that doesn't require any thing else complicated to manage like a subversion repository. Teamstudio CIAO!
Using Teamstudio CIAO! for XPages development
So how easy is it to add a database to source control using CIAO!? Once CIAO is installed, it takes only 3 steps.
Step 1. Open your database in Domino designer and click the CIAO icon in the toolbar.
Click yes
Step 2. Enter in the project information. Only the path to the CIAO! Log is required.
Step 3. Enter in a comment for the initial version of this database.
Relax a bit....
Done. That's it! You can now check out and check in from the CIAO! dialog or if you are using Domino Designer 8.5.1 or higher you can check things out right from the application navigator in Designer!
Also, just like with the Subversion support in 8.5.3, you you can see what elements are checked out by other people on your team.
Finally here is a video that walks through the entire process. Don't worry though, it only takes 1 minute and 13 seconds from start to finish.... Don't try that with Subversion!
(via Instapaper)
 #2 really hit home today. 'GET THY DATA DIALED!'. Getting your data right is more important than you think in a web app.
Getting the URL parameters in a Domino Java web agent
In my dataProxy agent I needed an easy way to get all the URL parameters. I figured I would post that in a separate entry so it wouldn't get lost.
private HashMap getURLParameters() throws NotesException { String url = agentContext.getDocumentContext().getItemValueString("QUERY_STRING"); String[] vals = url.split("&"); HashMap m = new HashMap(); for( int i = 0; i < vals.length; i++){ String[] p = vals[i].split("="); if( p.length == 2 ){ try { m.put(p[0], URLDecoder.decode(p[1],"UTF-8") ); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } return m; }
I can then save them in a member of my agent as a HashMap like param.get("db") or param.containsKey("db") and can get at them where ever I am.
HTML5, CSS3, etc.... It doesn't matter what the standard says, until the browsers all support it the same, you don't get cross platform without pain or for free.
This is a great little tutorial on using media queries to control the layout of the content in your web app. This can be very handy when you are trying to display content to a variety of mobile devices - phones, tablets, laptops - and don't want to develop different sites for each - but remember - don't make your mobile users download more than they need!
A whole bunch of great talks from the Business Of Software Conference held in Boston.
That title is a mouthful for sure, but this link really drove home why the concept of progressive enhancement is the future of the mobile web. Design first for mobile, let the 'desktop' version ask for the big images and large JS libraries. Don't make a mobile device download lots of stuff it isn't going to use anyway.
Another great, though much longer article, on why responsive design is not as important anymore is here. This goes into much more depth on the background for why you should be designing for mobile first and is another great read.
Back on track
Hairshirt or not.... the experiment rolls forward!
Now that I got the JSON bug solved worked around I can get back to fleshing out the non-XPages version of the Customers On the GO! app.
The next page is the contact details. The XPages version of this page wasn't too complicated and I wouldn't normally dedicate an entire post about it, but this will give me a chance to walk through my Notes document as JSON function I talked about yesterday.
After clicking the 'Contacts' link at the bottom of the app, you are sent to the 'contactsList.html' page. The page itself is almost identical to the app's home screen. The content for the page is collected using the JSON formatted output of a view in the CRM applciation using the following JS:
function loadContactsPageData(){ var cat = getURLParameter("c"); var parentId = ('00000000'+getURLParameter("documentId")).slice(-8); // Get the list data. $.getJSON('http://10.1.1.39/unplugged/tdtool.nsf/dataProxy?OpenAgent&db=unplugged/rm.nsf&v=JSONContacts&RestrictToCategory='+cat, function(data) { var contactArray = convertViewEntryToJSONObject(data); $('#contactDetailsTemplate') // Select the template. .tmpl(contactArray) // Bind it to the data. .appendTo('#contactsContainer'); // Render the output. $('#contactsContainer').listview('refresh'); } ); }
The contact template is very basic as well and looks like this:
<script id="contactDetailsTemplate" type="text/x-jquery-tmpl"> <li> <a href="contact.html?openfileresource&documentId=${noteid}"> {{if fpjrFunction_WB=="Developer"}} <img style="jobImage" src='designer.png'> {{else}} <img style="jobImage" src='admin.png'> {{/if}} <span style='contactName'>${fpnhName_WB}</span> <br/><span style='contactDetails'>${fpjrPosition_WB}</span> <br/><span style='contactDetails'>${fppbPhone_WB}</span> {{if fppbXtn_WB}} <span style='contactDetails'> Ext: ${fppbXtn_WB}</span> {{/if}} </a> </li> </script>
Not that complicated, and very similar to the first page, so it was really easy to throw together.Â
Each item in the above list has a link that brings you to the 'contact.html' page where the individual contacts information is displayed. In the XPages version, there was nothing much to this page, and really didn't offer any more information than the list did. Just the customers name, job role, phone number, and a big button called 'Call'. So here is where the dataProxy agent comes into play. To get a document all I need is the following URL:  unplugged/tdtool.nsf/dataProxy?OpenAgent&db=unplugged/crm.nsf/&outputformat=JSON&documentId=00000000
(Of course I would use the real note id, but this is an example). This URL I can use in my JQuery.getJSON call in the same way I was using it with the views.
NotesDocument.js
To make it easier to deal with the document object I create a few helper functions/objects. First was a little JS function to wrap the getJSON call for documents:
function getNotesDocument( db, docid, callback ){ var url = 'http://10.1.1.39/unplugged/tdtool.nsf/dataProxy?OpenAgent'; url += "&db=" + db; url += "&documentId=" + docid; url += "&outputformat=JSON"; $.getJSON(url,function(data){ var doc = new NotesDocument(data); callback(doc); }); }
This function takes 3 parameters, the db and docid as strings and the callback that the getJSON function should call. The passed in callback will be called with a NotesDocument object though instead of the direct results from the getJSON call itself.Â
The NotesDocument object is simple and only has two functions, a constructor and a method called getItem. This is what it looks like:
var NotesDocument = function(val){ this.JSON = val.document; this.items = {}; // convert the array of items to named properties in this object // this will make accessing them a bit faster than looping through // the entire list looking for the item by name for( var i = 0; i< this.JSON.item.length; i++ ){ for( val in this.JSON.item[i] ){ if( val !== "name"){ // values get put into a field named the same as their data type this.items[this.JSON.item[i].name] = this.JSON.item[i][val]; } } } delete this.JSON.item; // no need to store the items twice }; NotesDocument.prototype.getItem = function(item){ if( this.items.hasOwnProperty(item) ){ return this.items[item]; } return ""; }
This little bit of code lets me access the item names in much the same way as if I was working directly with the built in NotesDocument object in Domino.
Finally the function that gets the document can be reduced down to this bit of JS:
function loadContactPage(){ var cat = ('00000000'+getURLParameter("documentId")).slice(-8); // Get the list data. getNotesDocument( "unplugged/crm.nsf", getURLParameter("documentId"), function(doc) { $('#contactTemplate') // Select the template. .tmpl(doc) // Bind it to the data. .appendTo('#contactDetails'); // Render the output. // need to re-apply styles so the 'call' button will // be shown normally. For some reason the only way to // get this to work with the link button is to // 'refresh' the entire page. $('#contactDetail').trigger('create'); } ); }
One of my biggest frustrations with JQuery Mobile is that it doesn't deal with dynamic content very well. You probably noticed that there is a call to the 'trigger()' function above. After much trial and error, and google searching, it was the only way I could get the 'Call' button to render as a JQM Button widget and not a link. The reason all this is needed is that JQM loads a page and does all it's markup tweaking before the getJSON() call returns. As a result, by the time the template code has been processed, JQM thinks it's done with the page. To get around it you either need to add all the JQM classes and styles to the template code manually, or you need to force JQM to reprocess the page - which is what calling trigger('create') does when you specify the DIV for the page.
And just like the rest of the pages, I add a event handler to call this function when the contactDetails page is loaded:
$(document).bind("mobileinit", function(){ [...snip...] $('#contactDetail').live('pagebeforeshow',function(event, ui){ loadContactPage(); }); [...snip...] }
With the Javascript ready to go all that is left is the page template that will display the data from the document. For that I'm going to use the getItem function in the NotesDocument object directly in my page template:
<script id="contactTemplate" type="text/x-jquery-tmpl"> <span class='contactName'>${$data.getItem("fpnhName_WB")}</span><br/> <span class='contactDetails'>${$data.getItem("fpjrPosition_WB")}</span><br/> <span class='contactDetails'>${$data.getItem("fppbPhone_WB")}</span> {{if $data.getItem("fppbXtn_WB")}} <span class='contactDetails'> Ext: ${$data.getItem("fppbXtn_WB")}</span> {{/if}} <a id='callButton' href="tel:${$data.getItem("fppbPhone_WB")}" data-icon="grid" data-role="button">Call</a> </script>
When the JQuery template code evaluates the template, you can access some of the objects it passes in directly. The object here we are using is the $data object, which corresponds to the data that you passed to the jQuery.tmpl() function. With that ability we can call the getItem() function and get the value out of the field.
I'm feeling pretty happy with what I have up to this point. The dataProxy agent and the JSON document output is working well, and I've been able to keep the look and feel of the app intact.
Next up is the license page.
(via Instapaper)
(via Instapaper)
Thanks for nothing...
Well that was a total waste of a morning. Long story short was that I wanted to be able to create documents in a Domino database, but not require a form to do it. Naturally I created an agent that my HTML form could post to. All was going well, but I decided that I also wanted to be able to attach an image as well as some simple form fields. So, after a little more work, my agent reading the 'multipart/form-data' with the help of the Apache commons fileupload library. That itself was a bit of a trick since all the examples assume you are using it in a servlet context. There is a way however, to use the agent's DocumentContext document instead of the HTTPRequest object. All this was working fantastic... only when I started looking at the attachments I created did I discover a huge(!!!) problem. My images were corrupt. At first I though maybe I didn't have something set right with the Apache code, but alas, after wasting an entire morning, it turns out Domino was to blame. On top of that, it apparently has been a problem for a long time and is still, broken on 8.5.2.
What is happening is that when Domino writes the binary data coming from the HTTP request to the DocumenContext document, it converts the contents to LMBCS and thus totally messes up my binary POST data. There is nothing I can do to get access to the original data, short of writing a actual servlet - which probably won't work anyway.
ARRGGG!!!!!
Fine. Lesson learned. Domino is not a good HTTP server. Ya I know there are easier ways to do this with forms and file upload controls and what not but that's not the point though. This stuff should work.
Notes documents as JSON
There are a couple of ways to do this online, but having a Java agent to do view JSON gave me a good opportunity to do it my own way. I have a couple things going for me at the moment - I don't need rich text (yet), and I don't need to be able to create or update documents (yet).
The 'Document' class in Java has a function called generateXML which has been around for a long time (5.0.3 according to the doc) so it should be relatively stable, but as with all things Domino... we shall see if it is in practice. That got me the DXL version of a Notes document. To get the JSON I went to github and got the org.json classes and imported them into a Java script library in Domino:
This has a lot of really handy classes in it, but what I really wanted was the XML class that has a toJSONObject method. With all these pieces, it was really easy to put the following method together:
private void writeDocument(Database db, String documentId, boolean asJSON) throws NotesException, IOException, JSONException { Document doc = db.getDocumentByID(documentId); if( null== doc){ doc = db.getDocumentByUNID(documentId); } if( null== doc){ System.out.println("document not found"); return; } // write the document out java.io.Writer sw = new java.io.StringWriter(); doc.generateXML(sw); sw.flush(); PrintWriter ao = getAgentOutput(); if( asJSON ){ ao.println("Content-type: application/json"); ao.print(XML.toJSONObject(sw.toString()).toString()); } else{ ao.println("Content-type: text/xml"); ao.print(sw.toString()); } ao.flush(); }
I threw that into the dataProxy agent and added 2 URL parameters:
documentId= Lets me specify the document I want to access
outputformat=JSON Omitting this parameter keeps the output in DXL.
That's it! With the next post I'll show you how to integrate this into the mobile app.