Friday, 27 June 2014

Date conversion within JsRender using Moment.js

Moment.js rocks!

I dare say I've said it before and I know I'll say it again but it really, really rocks! You know what else rocks? JsRender also rocks!

Why do they rock? They rock because they allow me to write Converters which are a line long and allow me to convert US formated dates to UK formated dates with this:

$.views.converters({
    ukDate: function (value) {
        return moment(value).format("DD/MM/YYYY");
    }
});

This means that I use this line in my JsRender template:

<dt>Date Recieved</dt>
<dd>{{ukDate:Date_Received__c}}</dd>

And the US formated date gets converted without me having to worry!

That's why Moment.js and JsRender rock!

Wednesday, 25 June 2014

Update SalesForce rich text area in VisualForce page

I've just come across this post by Matt Lacey, a day too late as I discovered this yesterday!

Basically the issue is that Salesforce has rich text fields which are not in the least bit easy to re-render. A colleague had a requirement to change the text within the rich text area depending upon the user changing a select value, the base starting points for the rich text area were contained within hidden fields on the form but he needed to update the rich text area upon the select being changed without Salesforce complaining too much.

I inspected the elephant and clocked that the ids he had given to various apex components were coming through properly but that they were mixed up in some sort of colon-and-alphabet soup. That's where I got to thinking about jQuerys selectors and had a wee brain wave... the missing piece then was looking at the CKEDITOR object and its setData method and we were in business.

Given this structure on the visualforce page:

<apex:pageBlockSection rendered="{!NOT(draftMode)}">
  <apex:selectList 
    label="Request Description source:"
    value="{!descriptionSelected}" 
    multiselect="false" 
    size="1"
    id="descOption">
    <apex:selectOptions 
      value="{!descriptionList}" />
  </apex:selectList>
</apex:pageBlockSection>

 ... 

<apex:pageBlockSection>
  <apex:inputField 
    label="Request" 
    value="{!pagePubRec.Published_Request__c}"
    id="requestText" />
</apex:pageBlockSection>

 ... 

<apex:inputHidden 
  id="customerDescription" 
  value="{!customerDescription}"
  />
<apex:inputHidden 
  id="caseDescription" 
  value="{!caseDescription}" />

We can use this javascript:

<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
  $(function(){
    // Select the select that ends with the id of 'descOption'
    // and listen to it changing...
    $("[id$='descOption']").on("change", function(){
      // Probably not needed but better safe than sorry.
      var $this = $(this);
      // Get the full id if the textarea which contains 'requestText',
      // including all the salesforcie stuff, as that'll be the reference
      // we'll use to grab the correct CKEDITOR instance.
      var cke_editor_instance = $("textarea[id*='requestText']").attr("id");
      if ($this.val() === "Customer Request description"){
        // If the value of the select is "Customer Request description"
        // update the textarea which underlays the rich text editor with 
        // the data from our hidden field...
        $("textarea[id*='requestText']")
          .val($("[id$='customerDescription']").val());
        // ...and set the data for the CKEDITOR instance with the same value.
        CKEDITOR.instances[cke_editor_instance]
          .setData($("[id$='customerDescription']").val());
      }else{
        // We've only got 2 so no need to use a switch or 
        // something else more fun.
        $("textarea[id*='requestText']")
          .val($("[id$='caseDescription']").val());
        CKEDITOR.instances[cke_editor_instance]
          .setData($("[id$='caseDescription']").val());
      }
    });
  });
</script>

Yon Matt Lacey is right though, this is a hack... it's not a terrible hack... but it is a hack! There's no guarantee taht this approach will continue to work, but I'll keep my fingers crossed!

Tuesday, 17 June 2014

Words for today... and the day before...

I'm doing masses of things to do with dates and created some lovely objects using PHPs strtotime for yesterday, and the day before yesterday and I wanted to name them. Apparently in lots of languages there is a specific word for the day before yesterday but we're a bit stuck in modern English... so a wee Google search found this lovely answer. As such I've going to be using these words as much as possible!

ereyesterday
The day before yesterday; On the day before yesterday
overmorrow
The day after tomorrow; On the day after tomorrow

Sunday, 8 June 2014

A picture is worth a thousand lines of code... or is it?

I got really quite excited when I read about Codeivate last week and spent ages installing it on everything that'd work with it... and then - after it collecting some statistics - really quite sad that thus far my longest streak of coding is 20mins.

There's me claiming to work bloody hard and only managing a stint of 20 mins!

Then I got to thinking about my work flow and I clocked that a lot of what I do is code like a crazy thing and then test that what I've done is working... often dipping into the console and writing code in there that then gets cut and pasted into the IDE when it's working as I want it to... so actually recording the code that gets put into the IDE isn't a correct representation of the amount of work I do - just a representation of the amount of work I'm willing to commit to a file rather than some nebulous space within the browsers memory.

Phew!

(At least that's what I'm telling myself! ;-))

Thursday, 29 May 2014

API joiner

APIs are getting on for becoming the lifeblood of the internet but they can be a pain. If I need to get into the nitty-gritty of the API calls so that I can tweak the data they return to me I end up using Boxer to split the URI on question-marks and ampersands and then having to remember to join them before testing in the browser. Take this for example: http://maps.googleapis.com/maps/api/staticmap?center=Brooklyn+Bridge,New+York,NY&zoom=13&size=600x300&maptype=roadmap &markers=color:blue%7Clabel:S%7C40.702147,-74.015794&markers=color:green%7Clabel:G%7C40.711614,-74.012318 &markers=color:red%7Clabel:C%7C40.718217,-73.998284&sensor=false. Should I want to change that I'd pull it into Boxer and end up with something like this:

http://maps.googleapis.com/maps/api/staticmap
center=Brooklyn+Bridge,New+York,NY
zoom=13
size=600x300
maptype=roadmap
markers=color:blue|label:S|40.702147,-74.015794
markers=color:green|label:G|40.711614,-74.012318
markers=color:red|label:C|40.718217,-73.998284
sensor=false

It's a lot easier figuring out how to tweak it like that but squidging it all back together is a pain!

So, with a wee bit of free time last night, I wrote the tool above which takes the separate parts and does all the hard work for me! It just runs in your browser so feel free to copy the source if you'd like or use it where it is, its guts are easy as anything:

$(function(){
    $("#target").submit(function( event ) {
        event.preventDefault();
        var baseURI = $("#baseURI").val();
        var URILines = $("#URILines").val().split(/\n/);
        var lines = [];
        // http://stackoverflow.com/a/8479118
        for (var i=0; i < URILines.length; i++) {
            if (/\S/.test(URILines[i])) {
                lines.push($.trim(URILines[i]));
            }
        }
        $("#joinedLink").empty().append($("<a></a>", {
            "text": "New Link",
            "target": "_blank",
            "href": baseURI + "?" + lines.join("&")
        }));
    });
});

It's hosted on my Google Drive here: Make an url!, or just click the image above.

Friday, 9 May 2014

Some thoughts on DateTimePicker (xdsoft.net)

We've decided to use this DateTimePicker as it seems to play nicely with older browsers but we've also had to do a fair bit of exploration in order to get it to do what we want. On the whole the documentation is brilliant but there's the odd issue where I got confused so in order to save someone else some time I'll document them here:

  • Format

    It uses PHPs date/time format - which is cool as I love PHP almost as much as I love JavaScript but you should still be aware!

  • minDate & maxDate

    These need to be in the "YYYY/MM/D" format (Moment.js format)! Generally speaking, once the format has been set in the picker initialization it's smart enough to clock that if you give it a value then it should parse it in the format it's already been given... except when it comes to minDate & maxDate where you need to use its default formatting - this took me a couple of hours to clock so I hope it helps someone.

  • Adding to the options

    It's possible to add to the methods of an already initialized picker by simple calling .datetimepicker() with the new option/s.

On the whole it's a lovely UI widget, I just hope these pointers help someone else when they use it.

School's out... FOREVER!

It's #2 son's last day at school!

He's had an interesting academic career thus far but it's come on leaps and bounds over the past year or so thinks to the sterling work of my friends, he himself and InterHigh!

His exams start next week for 10 whole days and then that's it! He'll be off to France to pick cherries or Standon to work over the Summer

A very proud Dad sends his love!

Good luck ASH!!!!!

This picture is of him with his first chainsaw! ;-)