Thursday 24 March 2016

JavaScript: split sentence and add line breaks

I've been using Semantic UIs form validation nigh on constantly over the past few months and apart from the ability to write my own validation rules (which is a brilliant thing by the way) I'm also impressed with the messages that get slung into the UI. The on ly problem I've had though is if the message is particularly long then it can often mess up the layout of the form. After some experimentation I discovered that adding <br/> tags added line breaks within the message. I'm using this an awful lot so I decided to write a simple function which takes a string and splits it on words. It's a wee bit fuzzy so perhaps could do with a wee bit of tidying, but it works for my purposes:

function addBr(sentence, letters, seperator){
    letters = letters || 25;
    seperator = seperator || "<br/>"
    words = sentence.trim().split(" ");
    var returnString = "";
    var line = "";
    while(words.length > 0){
        if(line.length < letters){
            if(~~line.length){
                line += " " + words.shift();
            }else{
                line += words.shift();
            }
        }else{
            returnString += line + seperator;
            line = "";
        }
    }
    if(line !== ""){
        returnString += line;
    }    
    return returnString;
}

Here's a working JSFiddle.

Friday 18 March 2016

Moving data between pages using DataTables and the Query string

I recently got a tweet from someone I previously helped with a DataTable question:

And, seeing as I was playing with the really rather marvelous MDB framework, I thought I'd give it a try.

I knew I'd be able to get the data from the selected rows and also indicate their state as being selected but what was I to do with that data? If I could create a global data JSON object within the script I could use the unique ID of each row as the key to the full data of the representation of the row within the JSON object. The ID was for my benefit and could have been anything unique about the row... I guess I could've used a hash of the rows values as well, but why make things difficult?

So I needed a global data object, something to hide the the ID row within the table and some way of manipulating the data object when the user interacted with the table:

var data = {};
$(function(){
    var example = $("#example").DataTable({
        "columnDefs": [
            { 
                targets: [0], 
                visible: false
            }
        ]
    });
    $('#example tbody').on("click", "tr", function () {
        var temp = example.row(this).data()
        var obj = { 
            "ID": temp[0],
            "Name": temp[1],
            "Position": temp[2],
            "Office": temp[3],
            "Age": temp[4],
            "Start date": temp[5],
            "Salary": temp[6],
        }
        if($(this).hasClass("info")){
            $(this).removeClass("info");
            delete data[temp[0]];
        }else{
            $(this).addClass("info");
            data[temp[0]] = obj;
        }
        console.log(data);
    });
});

In case you're wondering, this is what the data looks like:

{
    "4": {
        "ID": "4",
        "Name": "Cedric Kelly",
        "Position": "Senior Javascript Developer",
        "Office": "Edinburgh",
        "Age": "22",
        "Start date": "2012/03/29",
        "Salary": "$433,060"
    },
    "5": {
        "ID": "5",
        "Name": "Airi Satou",
        "Position": "Accountant",
        "Office": "Tokyo",
        "Age": "33",
        "Start date": "2008/11/28",
        "Salary": "$162,700"
    },
    "6": {
        "ID": "6",
        "Name": "Brielle Williamson",
        "Position": "Integration Specialist",
        "Office": "New York",
        "Age": "61",
        "Start date": "2012/12/02",
        "Salary": "$372,000"
    }
}

So far so good, but how to move the data between the pages?

$("#move").on("click", function(){
    var encodedData = window.btoa(JSON.stringify(data));;
    var href = window.location.href.split("/");
    href.pop();
    href.push("catch.html");
    var newURL = href.join("/");
    document.location.href = newURL + "?data=" + encodedData;
});

When the button with an id of move is clicked I encode the stringed data object, take the uri of the current page, strip off the original page and add a new one (catch.html, in this case) and add the Base64 encoded data to the data query string. I then change the document.location.href to the catching page.

Simple ehh?

Within catch.html I needed to decode the Base64 encoded data and put it back into an object, I also needed to tell the catching DataTable how to read the caught data.

$(function(){
    var example = $("#example").DataTable({
        "columns": [
            { 
                "data": "ID",
                "visible": false
            },
            { 
                "data": "Name",
                "title": "Name"
            },
            { 
                "data": "Position",
                "title": "Position"
            },
            { 
                "data": "Office",
                "title": "Office"
            },
            { 
                "data": "Age",
                "title": "Age"
            },
            { 
                "data": "Start date",
                "title": "Start date"
            },
            { 
                "data": "Salary",
                "title": "Salary"
            }
        ]
    });
    var data = JSON.parse(window.atob(GetURLParameter("data")));
    if(Object.keys(data).length){
        $.each(data, function(k,v){
            example.row.add(v);
        });
        example.draw();
    }
});
function GetURLParameter(sParam){
    var sPageURL = window.location.search.substring(1);
    var sURLVariables = sPageURL.split('&');
    for (var i = 0; i < sURLVariables.length; i++){
        var sParameterName = sURLVariables[i].split('=');
        if (sParameterName[0] == sParam){
            return sParameterName[1];
        }
    }
}

Also simple ehh?

This was a nice little challenge and allowed me to slot wee bits of logic together to get something that just works, it was just what I needed to relax now I've picked all the low-hanging fruit from Empire of Code.

Wednesday 9 March 2016

Ajax Chatter File Attachment

Putting here so I don't forget how to do it:

public string imageData {get;set;}
public string imageName {get;set;}
public string imageDescription {get;set;}
public string recordId {get;set;}
/*
 * imageData:        base64 encoded file starting with something like this - data:image/png;base64,iVBORw0KGgoAAAA...
 * imageName:        name of the file being uploaded
 * imageDescription: description of the file being uploaded
 * recordId:         ID of the record the uplaod is assocaited with
 */
public void submitImage(){
    String base64 = imageData.substring(imageData.indexOf(',')+1);
    Blob actualdata = EncodingUtil.base64Decode(base64);        
    /* Regular attachment */ 
    //Attachment a = new Attachment(
    //    parentId = recordId,
    //    name = imageName,
    //    body = actualdata,
    //    description = imageDescription
    //);
    //insert a;
    /* Chatter attachment */ 
    ContentVersion doc = new ContentVersion();
    doc.Title = imageName;
    doc.Description = imageDescription;
    doc.PathOnClient = imageName;
    doc.VersionData = actualdata;
    insert doc;
    FeedItem post = new FeedItem();
    post.Visibility = 'AllUsers';
    post.ParentId = recordId;
    post.CreatedById = UserInfo.getUserId();
    post.RelatedRecordId = doc.Id;
    post.Type = 'ContentPost';
    post.Title = 'File upload for ' + imageDescription;
    insert post;
    imageData = ''; // so it doesn't blow my page up!
}

Monday 7 March 2016

Sublime Text ASCII Art

Splitting your content into separate files for HTML, CSS and JS is a brilliant idea but sometimes you simply need to smudge it all together - even huge quantities of JS - and that can make navigating through lines and lines of script a pain.

If you use Sublime Text (and if you're not, why not?) then you can install this plugin or you can do what I do and use the excellent Text to ASCII Art Generator (TAAG) to generate lovely comments like this:

/*
 .d8888b.                    888 
d88P  Y88b                   888 
888    888                   888 
888         .d88b.   .d88b.  888 
888        d88""88b d88""88b 888 
888    888 888  888 888  888 888 
Y88b  d88P Y88..88P Y88..88P 888 
 "Y8888P"   "Y88P"   "Y88P"  888 
 */

Quite apart from making things easier, it's also readable in the minimap so you can scroll to just where you need to be!

This is mainly up for my own reference but if it helps all good!