Classic Domino and multi country dates with Bootstrap

I was doing some fixes on a classic domino web app that uses bootstrap datepicker when an issue was raised. turns out its a bugger to get the jquery datapicker and domino date format to agree with each other for different countires ie mm/dd/yyyy or dd/mm/yyyy or dd.mm.yyyy

you would think that a little bit of JavaScript would solve the problem but there was multiple instances with a variety of browsers where it ended up that what ever domino was doing to calculate the date format was not matching the result of the JavaScript.

So we cheated, we replaced the “format:” parameter in the date picker below:

$('#MYDATE').datepicker({
    format: "mm/dd/yyyy",
    clearBtn: true,
    orientation: "top auto",
    todayHighlight: true,
    autoclose: true,
    weekStart: 1
 });

with some computed text with the following formula:

dat := @Text(@ToTime("01/28/1900");"D0S0") ;
sep := @Middle(dat ;2;1) ;
@If( @Left(dat; 2) = "28" ; "dd" + sep + "mm" + sep + "yyyy" ; "mm" + sep + "dd" + sep + "yyyy")

I find the best way is to put this in the default setting meaning you only have to do it once

$.datepicker.setDefaults({
     dateFormat: '<Computed Value>'
});

Simple, worked fine with a wide variety of date formats and kept everything in sync with what ever format Domino ended up picking.

C3 charts on Saleforce Winter16

As @devinthecloud points out in his Blog post Salesforce Winter 16 wrecked C3 charts on the pages he and I had developed. he found the removal of <apex:form> fixed the issue on his pages, but on my page the charts were still broken, so instead of this:

 

 

You get this

 

 

I stripped the page down to a bare minimum that you can use to recreate the issue, see below,

<apex:page docType="html-5.0" 
           applyBodyTag="false"
           showHeader="true"
           readOnly="true"
           sidebar="false">
<html lang="en">
  <head>
      <!-- Static Resources for CSS -->
        <link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.css" rel="stylesheet"/>
    </head>
    <body>
      <div id="chart"></div>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.js" />
      <script>
        var chart = c3.generate({
          data: {
            columns: [
  //            ["setosa", 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.2, 0.1, 0.1, 0.2, 0.4, 0.4, 0.3, 0.3, 0.3, 0.2, 0.4, 0.2, 0.5, 0.2, 0.2, 0.4, 0.2, 0.2, 0.2, 0.2, 0.4, 0.1, 0.2, 0.2, 0.2, 0.2, 0.1, 0.2, 0.2, 0.3, 0.3, 0.2, 0.6, 0.4, 0.3, 0.2, 0.2, 0.2, 0.2],
              ["versicolor", 1.4, 1.5, 1.5, 1.3, 1.5, 1.3, 1.6, 1.0, 1.3, 1.4, 1.0, 1.5, 1.0, 1.4, 1.3, 1.4, 1.5, 1.0, 1.5, 1.1, 1.8, 1.3, 1.5, 1.2, 1.3, 1.4, 1.4, 1.7, 1.5, 1.0, 1.1, 1.0, 1.2, 1.6, 1.5, 1.6, 1.5, 1.3, 1.3, 1.3, 1.2, 1.4, 1.2, 1.0, 1.3, 1.2, 1.3, 1.3, 1.1, 1.3],
              ["virginica", 2.5, 1.9, 2.1, 1.8, 2.2, 2.1, 1.7, 1.8, 1.8, 2.5, 2.0, 1.9, 2.1, 2.0, 2.4, 2.3, 1.8, 2.2, 2.3, 1.5, 2.3, 2.0, 2.0, 1.8, 2.1, 1.8, 1.8, 1.8, 2.1, 1.6, 1.9, 2.0, 2.2, 1.5, 1.4, 2.3, 2.4, 1.8, 1.8, 2.1, 2.4, 2.3, 1.9, 2.3, 2.5, 2.3, 1.9, 2.0, 2.3, 1.8],
              ["setosa", 30],
  //            ["versicolor", 40],
  //            ["virginica", 50],
            ],
            type : 'pie',
            onmouseover: function (d, i) { console.log("onmouseover", d, i, this); },
            onmouseout: function (d, i) { console.log("onmouseout", d, i, this); },
            onclick: function (d, i) { console.log("onclick", d, i, this); },
          },
          axis: {
            x: {
              label: 'Sepal.Width'
            },
            y: {
              label: 'Petal.Width'
            }
          }
        });
        setTimeout(function () {
          chart.load({
            columns: [
              ["setosa", 130],
            ]
          });
        }, 1000);
        setTimeout(function () {
          chart.unload({
            ids: 'virginica'
          });
        }, 2000);
      </script>
    </body>
</html>
</apex:page>

 

This let me narrow it down to the Salesforce header.
when you set **showHeader=”true”** it breaks
if you set **showHeader=”false”** it starts working
As this is obviously and provably down to a change in winter 16 I can raise it with Salesforce and get a fix.
…….. Wrong!
I quote

“At times, Client Side JS conflict with SFDC header JS will collide with already defined functions with the same name.”

“the behaviour of JavaScript is inconsistent with Salesforce components.”

and

“as we don’t support JavaScript”

Ah it’s nice to see that young Internet companies have the same grasp of customer service as the traditional IT companies and thus it falls back on consultants to fix, in this case with an Iframe, I’m not a fan of Iframes normally but as Salesforce use them themselves there is precedent
And so we now split our single page into 2 pages, an inner content and an outer Iframe wrapper
First we take out the existing page (it was called **”chart_test”**), rename it to **”chart_test_inner”** and set **showHeader=”false”**
Then we put in a Iframe wrapper with the old name and a bit of CSS to make it size properly then point it to the inner content

<apex:page docType="html-5.0" 
           applyBodyTag="false"
           showHeader="true"
           readOnly="true"
           sidebar="false">
<html lang="en">
  <head>
  <style>
  .fluidMedia {
    position: relative;
    padding-bottom: 56.25%; /* proportion value to aspect ratio 16:9 (9 / 16 = 0.5625 or 56.25%) */
    padding-top: 30px;
    height: 0;
    overflow: hidden;
  }
    .fluidMedia iframe {
        position: absolute;
        top: 0; 
        left: 0;
        width: 100%;
        height: 100%;
    }
      </style>
  </head>
    <body>
    <div class="fluidMedia">
        <iframe src="../apex/chart_test_inner" frameborder="0" > </iframe>
    </div>
    </body>
</html>
</apex:page>

 

And now instead of a broken

We have a working

Hooray!!!

Updating Statamic on AWS

For this blog I use Statamic, a very nice website CMS bassed on Markdown and using flat files which makes it perfect for the way I work in that I can link a Drop box account to the cheap AWS server I use for hosting and then edit blogs via mobile on a wide variety of machines with just a test editor.

Anyway the site has been rock solid for ages (5500+ hours) when I suddenly realised I wanted to upgraded the Statamic version to take advantage of some new features, that’s an easy job, you just replace a couple of directories in the httpd WWW directory, but I got a couple of errors and realised that I had an old version of PHP53 on the server and I had not patched it for a while (wince). also it had been so long since I had even logged on to the box that I could not remember what to do, so this is just an aide-memoire for those in the same situation

as I’m on Linux you need to make sure your AWS pem is secure sooo

sudo chmod 644 serverkey.pem

Then connect to the box with SSH

ssh -i serverkey.pem ec2-user@XXX.XXX.XXX.XXX

Now first things first, lets do a full update

sudo yum update

Once that is done, we have to remove http and php to update them all (yes you will get an outage)

sudo yum remove php httpd php-cli php-xml php-common httpd-tools

This will uninstall the server its self (but not your website), lets install the new version

sudo yum install php55 php55-pdo php55-gd 

If you notice I added “php55-gd” to the install as you will need this for some of the new Statamic features such as the file and gallery features. Quick start the server before anyone notices

sudo service httpd start
 

You will find that the site seems to work fine, but as soon as you attempt to go to a individual blog you will find it gives you a 404, this is because the htaccess files in Statamic are being ignored so you will have to go back and tell httpd to not ignore them. so you need to edit the httpd.conf file
So first lets go to the httpd config directory

[ec2-user@ip-XX-XXX-XX-XXX /]$ cd etc/httpd/conf
 

And edit the httpd.conf file ( a good cheat sheet to vi is [Here](http://www.lagmonster.org/docs/vi.html) )

sudo vi httpd.conf

change the instances of “AllowOverride None” to “AllowOverride All”
once that is saved you just restart httpd

sudo service httpd restart

And you should be all done.

Screwing With The IBM Connections Activity Stream

Customising the IBM Connections experience is a growing field, and the activity stream seems to be one of the most popular area for those customisations to take place…

It all started with this [blog entry: I love it! embed.ly in IBM Connections](http://www.lbenitez.com/2011/06/i-love-it-embedly-in-ibm-connections.html ) by Luis Benitez and a clients need to not use a third party library with associated API calls to generate their updates, and ended with a bit of swearing and chunk of JavaScript.

So what we want to do is loop thought all the status updates on any given connection page, and if we find a suitable bit of text i.e. a url we are going to pop that URL in an Iframe, but basically we could do anything we wanted

First lets steal most of the install instructions from Luis’s posting (these work for both V4 and V5 of connections)

  • If it is not already there, copy footer.jsp to the customization directory. e.g., copy <WAS_PROFILE_ROOT>/installedApps/Activities.ear/oawebui.war/nav/templates/footer.jsp to <IC_INSTALL_ROOT>/data/shared/customization/common/nav/templates †
  • Repeat for header.jsp e.g, copy <WAS_PROFILE_ROOT>/installedApps/Activities.ear/oawebui.war/nav/templates/header.jsp to <IC_INSTALL_ROOT>/data/shared/customization/common/nav/templates
  • Switch to the <IC_INSTALL_ROOT>/data/shared/customization/common/nav/templates directory ‡
  • Edit header.jsp
  • At the beginning of the file, look for the last <div class=”lotusRightCorner”> Just before that, add the following code:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>

– Save and close the file
– Edit footer.jsp
– Scroll to the bottom of the file and now its time to add our own code

<script type="text/javascript">    
var customEmbed = {
    invoke: function(){
        //First Lets look for all the activity post contents and loop though them
        $(".lotusPostContent").each(function() {
        // we are looking for a youtube url in this example with regular expressions
        var pattern1 = /(http://)?(www.youtube.com|youtu.?be)/; 
        var testhtml = $(this).html();
            //As we are continusly looping thought the page content we dont want to embed the extra content twice
            //So im checking to see if there is already an iframe in the post content, also im looking to see if the html
            //at the start of the .lotusPostContent contains a vcard class, as that means that is not a real post but 
            //rather a "this posts was made by User X" kind of thing and can be ignore else you get mad nested updates
            if (pattern1.test(testhtml) && testhtml.indexOf("iframe") == -1 && testhtml.indexOf("<span class="vcard">") != 1) {
                $(this).append(customEmbed.addhtml($(this).html()));
            }       
        });        
    },
    addhtml: function(html){
        var pattern2 = /(http://)?(www.youtube.com|youtu.?be)/; 
        var srcrul = html.match(pattern1);
        //here we have used match to get the url we want so that we can stuff it into the iframe
        return '<div><iframe width="500" height="600" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen scrolling="no"src="' + srcrul[0] + '" ></iframe></div>'7;
    }
}
setInterval(function(){
    customEmbed.invoke();
},4000);
// I find that a 4 second loop is about right for this kind of thing
</script>

#####Notes:
– I’m using a setInterval vs a setTimeout, because some page navigation in connections only requests an update to the central pane not the footer and also we want items to update on the basis of user actions.
– I using $(this).append rather than directly updating the html as Connections uses a load of dojo attach for its social functions such as “like” buttons and messing with the HTML directly brakes these.
– The best place to test your Regular expresions is at [https://regex101.com](https://regex101.com/#javascript)
There you go, the template to do anything you want with status updates

† <WAS_PROFILE_ROOT> is where the profile for your app server is located, normally in windows somthing like X:IBMWebSphereAppServerprofilesAppSrv01
‡ <IC_INSTALL_ROOT> is where you installed connection on windows normally somthing like X:IBMConnections

Conditional Checking in AngularJs using Restangular

This problem seems specific but its the age old “get details of parent document when you only have the child documents” problem now in the fun world of a client side application.

Problem: A page in an angularJs application contains a list of notes made by an attendee on a number of presentations.

If that presentation has been marked as complete then they you should be able to click on any given note and be taken directly to the slide they made the note on.

If however the presentation has not been made public then it should just be static text, the api call that returns the list of notes does not contain the public/notpublic details, so we have to make another API call to the presentations to find out if their are public.

However we want to keep the number of calls to a minimum and use existing code if suitable.

This project is using Restangular, described as an “AngularJS service to handle Rest API Restful Resources properly and easily”, which as far as I am concerned is both wonderful and bloody woeful. The framework tends to make hard things easy, and easy things hard. In this case I just want the JSON that a GET call returns. To do that, and not get all the extra objects that Restangular adds, you have to alter the root app.js of your app so that you can get an “original” response.

Bung the following code in the function that contains “function (RestangularProvider)” <– I am assuming that you already have Restangular up and working

        // add originalElement to the response so we can
        // have un-restangularized objects as well
        RestangularProvider.setResponseExtractor(function(response) {
          //console.log(response);
          var newResponse = response;
          newResponse.original = angular.copy(response);
          //console.log("response", newResponse.original);
          return newResponse;
        });

Now in the controller of the page you are displaying the notes on you want to add the following to the init ( ensuring that your “.service” contains “ApiRestangular” )

  init: function () {
        ApiRestangular.all('api/events/presentations').getList().then(
           function(successResponse) {
             angular.extend($scope, {
              presentationlist: successResponse.original
             });
           },
           function(errorResponse) {           
           }
        );

This makes a Restangular call to the ‘api/events/presentations’ api and when it gets the result, it fetches the original JSON result and stuff its in the “presentationlist” variable in the $scope
You now have an in memory array you can search to get more info straight from the page e.g

 isPresentationPublic: function (note) {
          if (typeof this.$scope.presentationlist === 'undefined') {
            return false;
          } else {
            for (var i = 0; i <= this.$scope.presentationlist.length; i++) { 
              if (note.idOfPresentation == this.$scope.presentationlist[i].id) {
                return this.$scope.presentationlist[i].ispublic
              }
            }  
          }
      },

(It should be noted that this is pure user interface stuff, and not meant to be secure).