Question: I have lists where the items are created from nintex workflows. I need to prevent the users from adding list items manually, as the workflows ensure dependencies. 

Revoking the add item permission is not an option, as the workflows need this permission to create the item. (Running with elevated privileges is also no option)

I am aware of three places which need to be handled: 
1. The "add new list item" link at the bottom of the list view
2. The custom action "add new [listtype] item"
3. The datasheet view

Current thinking:
1. + 2. : Inject Javascript in to the NewItem.aspx and do a pesimistic permission check using the ClientOM (works). I would prefer to not have the links visible at all, for usability reasons. 
3. Only way I see is having a workflow handle this.

Any suggestions / improvements?

Answer: 
It is indeed sad that sharepoint does not allow customisation of certain pages and controls out of the box.

Anyways, I'd think your best option is as you suggest to create Javascript which hides the new buttons. I've created a small Script for you which you can inject by using a Content Editor web part on the Allitems.aspx and other ASPX Pages related to this list:

```
<script language="javascript">   
 _spBodyOnLoadFunctionNames.push("HideNewControls");   

 function HideNewControls() {
    $('#Ribbon.ListItem.New.NewListItem - Large').hide();
    $('#Ribbon.ListItem.New.NewFolder - Large').hide();
    $('#idHomePageNewLink').hide();
    $('#Ribbon.List.ViewFormat.Datasheet - Large').hide()
}
</script>  

```

Hope this helps.
I used the following to hide the last empty row in datasheet view (where new items are added):

```
    //Add jquery reference
    <script type='text/javascript' src='../../SiteAssets/javascript/jquery-1.10.2.min.js'>
    </script>
    <script type='text/javascript'>
    //Use _spBodyOnLoadFunctionNames.push to prevent any collisions 
    //with $(document).ready()
    _spBodyOnLoadFunctionNames.push('setDisplay');
    function setDisplay(){
        //. . . 
        //Put any other code needed on page load here 
        //. . .
        hideLastRow();  
    }

    function hideLastRow(){
        //If there is more than one datasheet view on the page, 
        //find the id of the table using F12.  Then use that as 
        //the first part of the selector below.  Since each table 
        //row in datasheet view has the "role='row'" attribute we 
        //can use it in the selector.
        var rows = jQuery('table[id*="spgridcontainer"] tr[role=\"row\"]');
        if (rows.length > 0){
            var lastRowIdx = (rows.length)-1;   
            if (lastRowIdx == 1){
                jQuery('.ms-listviewtable').hide();
            }
            else{
                jQuery(rows[lastRowIdx]).hide();
            }
        }
    }

    //Bind the hideLastRow function to DOMNodeRemoved so it will 
    //fire again if a row is deleted so it will not reappear if 
    //the table is redrawn.
    jQuery(document).bind('DOMNodeRemoved',function(e){
        var el = e.target;
        //Check if the element removed is one of the datasheetview rows
        if (jQuery(el).is('table[id*="spgridcontainer"] tr[role=\"row\"]')){
            //An assert function was throwing an error so I set it to null 
            //to prevent a pop-up.  After testing there is no need for this 
            //function and it seems to be a bug when thrown in this instance.
            Sys.Debug.assert = function(){};
            hideLastRow();  
        }   
    });</script>

```

Note that I used 'jQuery' instead of '$' to prevent problems.